diff --git a/My project/Assets/CSV.meta b/My project/Assets/CSV.meta
new file mode 100644
index 000000000..4a50fe015
--- /dev/null
+++ b/My project/Assets/CSV.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 11bd481dedab309449d6ac6e71fd9ea9
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/CSV/Multilingual.csv b/My project/Assets/CSV/Multilingual.csv
new file mode 100644
index 000000000..1d64010ca
--- /dev/null
+++ b/My project/Assets/CSV/Multilingual.csv
@@ -0,0 +1,362 @@
+1,"消息列表"
+2,"建设"
+3,"[我要看到血流成河!]
+"
+4,"阵营的普通单位如完成击杀后,将
+在下回合获得攻击强化。
+"
+5,"排名列表(#3)"
+6,"名次"
+7,"玩家名"
+8,"城市数"
+9,"信仰"
+10,"比那名居天子"
+11,"带领<普鲁士帝国>"
+12,"设置"
+13,"排名"
+14,"科技"
+15,"消息"
+16,"下回合"
+17,"城市已升级!"
+18,"请从下方选择一项奖励"
+19,"工作坊"
+20,"有bug别点"
+21,"公园"
+22,"伟人"
+23,"城墙"
+24,"财富"
+25,"人口扩张"
+26,"领土扩张"
+27,"请等待其他玩家操作..."
+28,"步兵"
+29,"轻骑兵"
+30,"弓兵"
+31,"盾兵"
+32,"剑士"
+33,"重骑兵"
+34,"炮兵"
+35,"芙兰朵露"
+36,"蕾米莉亚"
+37,"十六夜咲夜"
+38,"红美铃"
+39,"帕秋莉诺蕾姬"
+40,"占领城市"
+41,"升级"
+42,"恢复
+"
+43,"解雇"
+44,"挖掘"
+45,"采集"
+46,"帆船"
+47,"冲锋艇"
+48,"战舰"
+49,"清除树林"
+50,"渔猎"
+51,"狩捕"
+52,"林场"
+53,"采矿场"
+54,"农田"
+55,"港口"
+56,"道路"
+57,"桥梁"
+58,"谷仓"
+59,"加工厂"
+60,"市场"
+61,"冶炼厂"
+62,"神庙"
+63,"森林神庙"
+64,"山神庙"
+65,"海洋神庙"
+66,"焚林垦田"
+67,"植树造林"
+68,"拆除"
+69,"和平祭坛"
+70,"智慧之塔"
+71,"繁荣之殿"
+72,"财富之巅"
+73,"权力之门"
+74,"皇家公园"
+75,"世界之眼"
+76,"平原"
+77,"这是一片空旷的土地。"
+78,"这里是提示文字
+提示玩家应该怎么操作"
+79,"登山"
+80,"KING
+职阶召唤
+"
+81,"BISHOP
+职阶召唤
+"
+82,"QUEEN
+职阶召唤
+"
+83,"KNIGHTS
+职阶召唤
+"
+84,"CHARIOT
+职阶召唤
+"
+85,"科技名称"
+86,"该科技将会解锁以下内容:"
+87,"取消"
+88,"研发"
+89,"[巴别之瞻妄]"
+90,"帝国控制的城市越多,研发科技的费用越高。"
+91,"当帝国规模愈发庞大,众声喧哗的世界便难以共鸣于同一道理。知识在各城邦间折损、误解、甚至扭曲,如同昔日攀天之塔的回音,终将自毁其基。"
+92,"金币 (+2)"
+93,"回合"
+94,"十六夜姣夜"
+95,"这里是宵夜的对话内容。
+第二行。
+第三行"
+96,"这里是蕾米的对话内容。
+第二行。
+第三行。"
+97,"测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文"
+98,"测试标题"
+99,"确认"
+100,"胜利"
+101,"恭喜您获得最终胜利!"
+102,"拥有城市"
+103,"拥有雕塑"
+104,"最终得分"
+105,"返回主菜单"
+106,"失败"
+107,"很遗憾,您已出局"
+108,"新游戏"
+109,"继续游戏"
+110,"故事模式"
+111,"图鉴"
+112,"战绩"
+113,"关于"
+114,"地图尺寸"
+115,"玩家数量"
+116,"游戏难度"
+117,"选择阵营
+"
+118,"红魔馆"
+119,"难度"
+120,"高傲的红魔馆大小姐抽到了埃及帝国卡。
+不知为什么,她赌上了整个红魔馆押自己赢。"
+121,"“无聊,我要看到血流成河!”"
+122,"埃及帝国"
+123,"优雅而怠惰的月之公主抽到了法兰西帝国卡。
+尚无败绩,不过好像都是她的宠物月兔代打。"
+124,"“输了的话,今晚就没饭吃了哦,铃仙酱~”"
+125,"永远亭"
+126,"法兰西帝国"
+127,"沉静而可怖的地灵殿主人抽到了印度帝国卡。
+她只是来寻找妹妹和宠物,稀里糊涂加入了对局。"
+128,"“投降吧,阁下毫无胜算。我只想带她们早些回家。”"
+129,"地灵殿"
+130,"印度帝国"
+131,"“投降吧,阁下毫无胜算。我只想带她们回家。”"
+132,"开始霸业!"
+133,"经典模式"
+134,"征服模式"
+135,"来自红魔馆的吸血鬼大小姐——蕾米莉亚·斯卡雷特,此刻伫立于金字塔之巅,宣告自己即是埃及正统的王权化身。她将率领红魔馆的将领们南征北讨,驱策妖精女仆在尼罗河的滋养下开垦荒芜之地,筑起属于斯卡雷特王朝的辉煌帝国。"
+136,"斯卡雷特王朝"
+137,"伟人阵营"
+138,"芙兰朵露·斯卡雷特"
+139,"继承赛特意志的恶魔之妹。"
+140,"继承克里欧帕特拉意志的魔女。"
+141,"蕾米莉亚·斯卡雷特"
+142,"继承奥里西斯意志的吸血鬼。"
+143,"继承阿努比斯意志的女仆长。"
+144,"继承荷鲁斯意志的武术家。"
+145,"伟人职阶:马(Knights)
+继承赛特意志的红魔馆二小姐。拥有特色破局技能四重存在。"
+146,"帕秋莉·诺蕾姬"
+147,"伟人职阶:后(Queen)
+继承克里欧帕特拉意志的魔女。拥有特色范围伤害技能皇家烈焰。"
+148,"伟人职阶:王(King)
+继承奥西里斯意志的吸血鬼。拥有特色反击回复技能红色不夜城。"
+149,"伟人职阶:相(Bishop)
+继承阿努比斯意志的女仆长。拥有特色突袭技能银之跳跃。"
+150,"伟人职阶:车(Rook)
+继承荷鲁斯意志的武术家。拥有特色反伤技能虹色太极拳。"
+151,"士兵特性"
+152,"妖精女仆"
+153,"领土内未改造的森林可训练基础单位。
+妖精是森林的呼吸,是自然的化身。"
+154,"文明特性"
+155,"尼罗河的女儿"
+156,"在游戏开始时拥有耕种科技。
+埃及是尼罗河的馈赠。"
+157,"来自永远亭的月之公主——蓬莱山辉夜,此刻端坐于凯旋门下,优雅地宣布她将继承法兰西帝国的荣光。月光洒落枫丹白露,竹影漫过香榭丽舍。她将率领兔子军团,漫步于革命与浪漫交织的疆土上,从容地重塑法兰西的雄图霸业。"
+158,"蓬莱山王朝"
+159,"铃仙·优昙华院·因幡"
+160,"继承拉纳意志的月兔。"
+161,"八意永琳"
+162,"继承贝尔蒂埃意志的月人。"
+163,"蓬莱山辉夜"
+164,"继承拿破仑意志的月之公主。"
+165,"因幡帝"
+166,"继承红衣主教意志的妖怪兔。"
+167,"藤原妹红"
+168,"继承贝尔纳多特意志的蓬莱人。"
+169,"妖怪兔"
+170,"永远亭阵营的单位在领土内的恢复量由4点提升至5点。
+兔子轻跳而过,好运悄然而至。"
+171,"田园绅士学"
+172,"在游戏开始时拥有采集科技。
+文明的第一课,就在在葡萄藤与玫瑰花间。"
+173,"埃及"
+174,"法兰西"
+175,"普鲁士"
+176,"普鲁士帝国
+守矢王朝"
+177,"八坂神奈子将扮演普鲁士帝国——守矢铁血联盟的最高领袖。她将以神权与军威并重的姿态,率守矢神社在钢铁洪流中强势登顶东方理想国大赛!"
+178,"射命丸文"
+179,"犬走花"
+180,"泄矢诹访子"
+181,"东风谷早苗"
+182,"八坂神奈子"
+183,"领袖特性"
+184,"[神不需要奇迹]
+"
+185,"挖掘<遗迹>必定获得强力作战单位。"
+186,"[妖怪山的天狗们]
+"
+187,"1范围内如有友方死亡,自身获得1回合的强化效果。"
+188,"[鲁尔山谷]
+"
+189,"初始拥有<狩猎>科技。没有矿石的山脉也能为冶炼厂提供1点城市经验。"
+190,"印度帝国
+古明地王朝"
+191,"古明地觉将扮演印度帝国——地灵圣朝的女王。她将以深不可测的心灵操控,带领地灵殿,在恒河文明中冉冉升起,问鼎东方理想国大赛的最终冠军。"
+192,"星熊勇仪"
+193,"灵乌路空"
+194,"古明地恋"
+195,"火焰猫燐"
+196,"古明地觉"
+197,"[你还有一次说谎的机会]
+"
+198,"游戏开始时获得所有敌人位置和所有遗迹位置的提示"
+199,"[旧地狱的怨灵]
+"
+200,"被杀死后,会对凶手附加<中毒>的负面效果。"
+201,"[恒河女神]
+"
+202,"初始拥有<种植>科技。种树享受40%的折扣。"
+203,"战绩历史"
+204,"所有战绩"
+205,"回合数"
+206,"得分"
+207,"阵营"
+208,"得分系数"
+209,"日期"
+210,"阵营图鉴"
+211,"伟人图鉴"
+212,"奇观图鉴"
+213,"成就图鉴"
+214,"阵营图鉴
+"
+215,"高傲而任性的红魔馆大小姐抽到了埃及帝国卡。
+不知为什么,她赌上了整个红魔馆押自己赢。"
+216,"沉静而可怖的地灵殿主人抽到了印度帝国卡。
+她只是来寻找妹妹和宠物,稀里糊涂加入了对局。"
+217,"“投降吧,阁下毫无胜算。我只想带她们仨快点回去。”"
+218,"可靠又专横的风雨之神抽到了普鲁士帝国卡。
+她已经为这款游戏新成立了并购部和宣传部。"
+219,"“我要这游戏的冠名权,把你们负责人叫来。”"
+220,"守矢神社"
+221,"普鲁士帝国"
+222,"“投降吧,你没有胜算。我只想快点带家妹回去。”"
+223,"帝王星收集 3 / 5
+在游戏中召唤对应的伟人,点亮帝王星吧!"
+224,"伟人图鉴
+"
+225,"角色介绍"
+226," 继承了阿努比斯意志的少女,原本是在红魔馆服侍蕾米莉亚·斯卡蕾特的女仆长,拥有操纵时间/停止时间程度的能力。
+ "
+227," 她是红魔馆中唯一的人类,冷静从容、头脑敏锐、优雅潇洒,偶尔也有些毒舌。对大小姐唯命是从,也正因此陪着任性的主人一同加入到了这款风靡幻想乡的游戏之中。"
+228,"居然是……冥界守护神吗?不过大小姐那种程度,是不会死的吧。这样一来,我就变得多余了呢。"
+229,"大小姐也来到冥界了吗?该说幸运还是不幸呢……反正不管在哪里,我都会侍奉好大小姐。"
+230," 在意识到大小姐所扮演的奥里西斯亦有冥王的身份后,她似乎有些开心,这便是操纵命运的能力吧,她这么想。"
+231,"冥界的守护神?说得倒轻松,我是不是该去向某位偷懒的死神讨教一下‘划水秘诀’了呢。"
+232," 虽然招牌的道具变成了安卡和瓦斯权杖,但她仍在黑曜石神像的阴影之中擦亮了手中的银刃。一定要帮助大小姐赢下比赛,她已下决心。"
+233," 获得阿努比斯扮演卡的人类少女。她本是在红魔馆服侍蕾米莉亚·斯卡蕾特的女仆长,陪着任性的大小姐一同加入游戏。
+ "
+234,"居然是……亡者引路人吗?不过大小姐是不会死的吧。我变得多余了呢。"
+235,"角色特性"
+236,"三星挑战"
+237,"[又见面了,大小姐]"
+238,"累计召唤10次"
+239,"[完美潇洒的从者]"
+240,"在一回合内连续闪现到4个不同的伟人身边"
+241,"[于冥河守候]"
+242,"闪现到蕾米莉亚身边后蕾米莉亚在该回合内死亡"
+243,"在一回合内,连续闪现到4个不同的己方伟人身边"
+244,"[为您指引归途]"
+245,"闪现到蕾米莉亚身边后,蕾米莉亚在该回合内死亡"
+246,"十六夜 夜"
+247,"口"
+248,"关"
+249,"奇观介绍"
+250," 古代世界最大、最著名的图书馆,建于托勒密王朝时期的埃及,旨在收藏天下所有知识。后因战火与政治动荡多次焚毁。
+ 在游戏中,作为知识类奇观,解锁全部科后即可获得,提供3点城市经验。"
+251,"众人评价"
+252,"蕾米莉亚和帕秋莉正在讨论。"
+253,"七十万卷!你可别让小恶魔累死哦。传出去坏了我红魔馆的名声。"
+254,"小恶魔很结实,何况她是自愿的。倒是某只老鼠可能会累死吧。"
+255,"听说进了亚历山大港的船只,必须把书留下来,就像打劫一样呢。"
+256,"若真如此,我还真希望黑白老鼠多来几趟。"
+257,"[雅典娜的居所]"
+258,"累计建造10次"
+259,"[船过港,书且留]"
+260,"在亚历山大港建造该奇观,必须靠近谷仓、港口和市中心"
+261,"[七十万卷遗梦]"
+262,"伟人帕秋莉·诺蕾姬在该奇观上连续停留10回合"
+263,"亚历山大图书馆"
+264,"成就收集星({count}/100)"
+265,"战斗成就"
+266,"战斗成就(5/25)"
+267,"[系统设置]"
+268,"音乐音量"
+269,"音效音量"
+270,"显示提示"
+271,"语言"
+272,"简体中文"
+273,"关闭"
+274,"退出"
+275,"关于我们"
+276,"出品 蕾米莉亚指挥部"
+277,"原作 上海爱丽丝幻乐团"
+278,"本作品为 东方project 的二次同人创作"
+279,"关注我们"
+280,"@蕾米莉亚指挥部"
+281,"官方网站"
+282,"开发团队"
+283,"版本信息"
+284,"隐私政策"
+285,"服务条款"
+286,"少女加冕中..."
+287,"卢克索神庙"
+288,"孟菲斯老城"
+289,"吉萨大金字塔"
+290,"阿布辛贝大神庙"
+291,"狮身人面像"
+292,"奥里西斯神庙"
+293,"枫丹白露宫"
+294,"索邦大学"
+295,"交易所广场"
+296,"卢浮宫"
+297,"凯旋门"
+298,"巴黎圣母院"
+299,"巴黎天文台"
+300,"勃兰登堡门"
+301,"海登堡大学"
+302,"汉堡港口仓库城"
+303,"新天鹅堡"
+304,"柏林胜利纪念柱"
+305,"拜罗伊特节日剧院"
+306,"齐柏林飞艇基地"
+307,"阿育王柱"
+308,"那烂陀寺"
+309,"亨比"
+310,"泰姬陵"
+311,"红堡"
+312,"米纳克希神庙"
+313,"简塔曼塔天文台"
diff --git a/My project/Assets/CSV/Multilingual.csv.meta b/My project/Assets/CSV/Multilingual.csv.meta
new file mode 100644
index 000000000..db73f9246
--- /dev/null
+++ b/My project/Assets/CSV/Multilingual.csv.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 64c1bbe0986b866488c0ff7df56a175e
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export.meta b/My project/Assets/Resources/Export.meta
new file mode 100644
index 000000000..362858ebd
--- /dev/null
+++ b/My project/Assets/Resources/Export.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 79aa236e1c9c5fd4abc4d4c174fe54d4
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/AIConfig.asset b/My project/Assets/Resources/Export/AIConfig.asset
new file mode 100644
index 000000000..3d7ed3940
--- /dev/null
+++ b/My project/Assets/Resources/Export/AIConfig.asset
@@ -0,0 +1,89 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b40ff2b127284ad4b576403fbf9b0d95, type: 3}
+ m_Name: AIConfig
+ m_EditorClassIdentifier:
+ MoneyScore: 0.1
+ UnitScore: 1
+ CityScore: 5
+ CityDefendScore: 0.2
+ OneCanMoveGridMaxScore: 1
+ OneSightGridMaxScore: 1
+ UnitAttackScore: 1
+ UnitDefendScore: 1
+ UnitExploreScore: 5
+ UnitExploreCityCenterScore: 20
+ UnitExploreTreasureScore: 10
+ UnitExploreStarfishScore: 5
+ FutureScoreTransformValue: 0.5
+ MilitaryConstructionRatioValue: 0
+ TechInfoList:
+ - TechType: 1
+ Ratio: 1
+ - TechType: 2
+ Ratio: 1
+ - TechType: 3
+ Ratio: 1
+ - TechType: 4
+ Ratio: 1
+ - TechType: 5
+ Ratio: 1
+ - TechType: 6
+ Ratio: 1
+ - TechType: 7
+ Ratio: 1
+ - TechType: 8
+ Ratio: 1
+ - TechType: 9
+ Ratio: 1
+ - TechType: 10
+ Ratio: 1
+ - TechType: 11
+ Ratio: 1
+ - TechType: 12
+ Ratio: 1
+ - TechType: 13
+ Ratio: 1
+ - TechType: 14
+ Ratio: 1
+ - TechType: 15
+ Ratio: 1
+ - TechType: 16
+ Ratio: 1
+ - TechType: 17
+ Ratio: 1
+ - TechType: 18
+ Ratio: 1
+ - TechType: 19
+ Ratio: 1
+ - TechType: 20
+ Ratio: 1
+ - TechType: 21
+ Ratio: 1
+ - TechType: 22
+ Ratio: 1
+ - TechType: 23
+ Ratio: 1
+ - TechType: 24
+ Ratio: 1
+ - TechType: 25
+ Ratio: 1
+ - TechType: 26
+ Ratio: 1
+ - TechType: 27
+ Ratio: 1
+ - TechType: 28
+ Ratio: 1
+ - TechType: 29
+ Ratio: 1
+ - TechType: 30
+ Ratio: 1
diff --git a/My project/Assets/Resources/Export/AIConfig.asset.meta b/My project/Assets/Resources/Export/AIConfig.asset.meta
new file mode 100644
index 000000000..75b43bc5a
--- /dev/null
+++ b/My project/Assets/Resources/Export/AIConfig.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8582602f11b29574bbc97685fd858ad0
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/Achievement.asset b/My project/Assets/Resources/Export/Achievement.asset
new file mode 100644
index 000000000..516da032e
--- /dev/null
+++ b/My project/Assets/Resources/Export/Achievement.asset
@@ -0,0 +1,15 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b664cf36cbd74c59a853c45c232706b0, type: 3}
+ m_Name: Achievement
+ m_EditorClassIdentifier:
+ AchievementList: []
diff --git a/My project/Assets/Resources/Export/Achievement.asset.meta b/My project/Assets/Resources/Export/Achievement.asset.meta
new file mode 100644
index 000000000..0517b43ba
--- /dev/null
+++ b/My project/Assets/Resources/Export/Achievement.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 27f4bb438a10ceb4ab02dac1f478600c
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/ActionDataAssets.asset b/My project/Assets/Resources/Export/ActionDataAssets.asset
new file mode 100644
index 000000000..3f02a0cd6
--- /dev/null
+++ b/My project/Assets/Resources/Export/ActionDataAssets.asset
@@ -0,0 +1,2479 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 03c8c08563eb96c43b296f9aaa8786a7, type: 3}
+ m_Name: ActionDataAssets
+ m_EditorClassIdentifier:
+ ActionList:
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 1
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u8BAD\u7EC3\u6B65\u5175"
+ Desc: "\u57FA\u7840\u5355\u4F4D\u3002\u62E5\u6709<\u51B2\u523A>\u548C<\u57CE\u9632>\u6280\u80FD\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 0aa305c6fa2a1e347b1a1654e9916749, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 95717e953addf6240b8ecaf898fca81e, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 07b9340a256d3f14e98a07b26776a349, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 257160dea0566b341b19e32538e6fa47, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 2
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 2
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u8BAD\u7EC3\u8F7B\u9A91\u5175"
+ Desc: "\u9AD8\u673A\u52A8\u6027\u5355\u4F4D\u3002\\n\u62E5\u67092\u79FB\u52A8\u529B\u548C<\u51B2\u523A><\u57CE\u9632><\u9041\u8D70>\u6280\u80FD\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: cd6bf02b5a50ab6478dfbaae0c78eda6, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 1ec120fb74395554fa5a801de623b4c0, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: d1218fb75bc29a4408e5906e4c4ca29b, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 5351895aa45f40b45a5561176119406a, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 3
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 3
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u8BAD\u7EC3\u5C04\u624B"
+ Desc: "\u8FDC\u7A0B\u5355\u4F4D\uFF0C\\n\u62E5\u67092\u5C04\u7A0B\u548C<\u51B2\u523A><\u57CE\u9632>\u6280\u80FD\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: c309c0d82c57f074b8ce6c64daf8c235, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 58413c2a66dfde142b6a1ccbe9f27e68, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 776e928d9af60ec4ea93b81b182d9b42, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 1e8a896b0bff269469dc3932a8706cc9, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 3
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 4
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u8BAD\u7EC3\u76FE\u5175"
+ Desc: "\u9632\u5FA1\u5355\u4F4D\u3002\\n\u62E5\u67093\u9632\u5FA1\u529B\u548C<\u57CE\u9632>\u6280\u80FD\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: e2d90fea274788343beeb783be7239e1, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 6b69822039c6f164eae13f3047ceddda, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 3a5b08e2d8ef56244b76ddf8e86eb827, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: d4a256b9eaa2b73488b9583b3cf3a0f0, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 3
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 5
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u8BAD\u7EC3\u91CD\u9A91\u5175"
+ Desc: "\u5F3A\u529B\u673A\u52A8\u5355\u4F4D\u3002\\n\u62E5\u67093\u79FB\u52A8\u529B3.5\u653B\u51FB\u529B\u548C<\u51B2\u523A><\u8FDE\u7EED\u6740\u654C>\u6280\u80FD\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 0478030a95f1e8f4f89dba9caf11f942, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: bc07a0e352dc0ec4d953da0ae702714e, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 6c1be9a2822f2dd499a2675c58880f9f, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 10d088e6f0a8082469f19b5de3341c6c, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 0
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 6
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u8BAD\u7EC3\u70AE\u5175"
+ Desc: "\u5F3A\u529B\u8FDC\u7A0B\u5355\u4F4D\u3002\\n\u62E5\u67093\u5C04\u7A0B4\u653B\u51FB\u529B\u548C<\u57CE\u9632>\u6280\u80FD\u3002\u65E0\u6CD5\u53CD\u51FB\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: f506a24f1810cc94db88966c30141449, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: de978a3bf7b28104db2d1bd96b32d1cd, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: a68d85698d73d744bbaa558ec0f55baf, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: dcab41c93277f734c83b8bc8582fbb81, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 8
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 7
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u8BAD\u7EC3\u5251\u58EB"
+ Desc: "\u5F3A\u529B\u7EFC\u5408\u5355\u4F4D\u3002\\n\u62E5\u67093\u9632\u5FA1\u529B3\u653B\u51FB\u529B\u548C<\u51B2\u523A>\u6280\u80FD\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 24f4ae4dfde76d049a508a0a16aa107f, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 07b05b46de560ed46b5b8d4162e2cf93, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: ecc257b0a99511942a1fda317f2eab92, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: e1142a63bb18f3346a85900db3261624, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 5
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 8
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 0aa305c6fa2a1e347b1a1654e9916749, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 95717e953addf6240b8ecaf898fca81e, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 07b9340a256d3f14e98a07b26776a349, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 257160dea0566b341b19e32538e6fa47, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 0
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 9
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 0aa305c6fa2a1e347b1a1654e9916749, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 95717e953addf6240b8ecaf898fca81e, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 07b9340a256d3f14e98a07b26776a349, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 257160dea0566b341b19e32538e6fa47, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 0
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 15
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5DE8\u4EBA"
+ Desc: "\u8D85\u5F3A\u529B\u7EFC\u5408\u5355\u4F4D\u3002\\n\u62E5\u670940\u8840\u91CF\u548C4\u653B\u51FB\u529B\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 15b8ae2a5f592ec41a4f61736b107770, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: ccc50745a363dbe49903b67a049d1738, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 49c7859254c88494cbf8a1a436591a78, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 4aa7581f148af6848a76951c675e055e, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 0
+ - ActionId:
+ ActionType: 0
+ WonderType: 0
+ ResourceType: 1
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u6355\u9C7C"
+ Desc: "\u5B66\u4E60<\u6355\u9C7C>\u79D1\u6280\u540E\u53EF\u6267\u884C\u3002\\n\u6536\u83B7\u6B64\u5904\u7684\u6E14\u4E1A\u8D44\u6E90\uFF0C\u5E76\u83B7\u5F971\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002"
+ Icon: {fileID: 21300000, guid: d7b0a16ac6f53ad4b8820d8c295c6bc1, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 2
+ - ActionId:
+ ActionType: 0
+ WonderType: 0
+ ResourceType: 5
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u91C7\u96C6"
+ Desc: "\u5B66\u4E60<\u91C7\u96C6>\u79D1\u6280\u540E\u53EF\u6267\u884C\u3002\\n\u6536\u83B7\u6B64\u5904\u7684\u6C34\u679C\u8D44\u6E90\uFF0C\u5E76\u83B7\u5F971\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 6b326932a8dd82740a3ad90e95e54e9d, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 1
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 47db57bf308d56a4c95ede49bec10ea5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 2
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 6391f095bb7b38143ba94ff1b85fc39d, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 3
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: c8a4c958d9782c14eba3dd4d9c455ad3, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 2
+ - ActionId:
+ ActionType: 0
+ WonderType: 0
+ ResourceType: 4
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u72E9\u730E"
+ Desc: "\u5B66\u4E60<\u72E9\u730E>\u79D1\u6280\u540E\u53EF\u6267\u884C\u3002 \\n\u6536\u83B7\u6B64\u5904\u7684\u52A8\u7269\u8D44\u6E90\uFF0C\u5E76\u83B7\u5F971\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: d5dba383bd7c4c5458298967194e6a41, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 1
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 95d5e0690585b454b8bbaed933fa0ab4, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 2
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: b0583954460992148af5db1162253144, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 3
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 4d01dae65ab3c774e9838e3dd5f131f9, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 2
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 9
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u8BBE\u519C\u7530"
+ Desc: "\u5C06\u5E84\u7A3C\u6539\u9020\u4E3A\u519C\u7530\uFF0C\u53EF\u63D0\u4F9B2\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002\\n\u9700\u8981<\u8015\u79CD>\u79D1\u6280\u3002"
+ Icon: {fileID: 21300000, guid: 7983e5706aca9634188e20ecea690403, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 10
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u91C7\u77FF\u573A"
+ Desc: "\u53EF\u5728\u91D1\u77FF\u4E0A\u5EFA\u9020\u91C7\u77FF\u573A\uFF0C\u63D0\u4F9B2\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002\\n\u9700\u8981<\u91C7\u77FF>\u79D1\u6280\u3002"
+ Icon: {fileID: 21300000, guid: 4814901362cb1924ca96564a88e97e74, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 11
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u4F10\u6728\u573A"
+ Desc: "\u53EF\u5728\u68EE\u6797\u4E0A\u5EFA\u9020\u4F10\u6728\u573A\u3002\\n\u4F1A\u6E05\u9664\u68EE\u6797\u4E2D\u7684\u52A8\u7269\u3002\u63D0\u4F9B1\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002\\n\u9700<\u4F10\u6728>\u79D1\u6280\u3002"
+ Icon: {fileID: 21300000, guid: a3bcc84a63fcc9d4f98afa1a74445f56, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 3
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 12
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u6E2F\u53E3"
+ Desc: "\u5728\u6D45\u6D77\u533A\u57DF\u5EFA\u9020\u6E2F\u53E3\uFF0C\u53EF\u63D0\u4F9B1\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002\\n\u80FD\u591F\u5C06\u666E\u901A\u5355\u4F4D\u8F6C\u5316\u4E3A\u6D77\u4E0A\u5355\u4F4D\uFF0C\u540C\u65F6\u80FD\u591F\u5EFA\u7ACB\u6D77\u6D0B\u901A\u8DEF\u3002"
+ Icon: {fileID: 21300000, guid: a3c4b263edc024d4791bc9a1c6319e8c, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 7
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 17
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u6865\u6881"
+ Desc: "\u5728\u6D45\u6D77\u533A\u57DF\u5EFA\u9020\u6865\u6881\u3002\u4E0D\u63D0\u4F9B\u57CE\u5E02\u7ECF\u9A8C\uFF0C\\n\u4F46\u662F\u53EF\u4EE5\u5EFA\u7ACB\u901A\u8DEF\uFF0C\u63D0\u4F9B\u79FB\u52A8\u52A0\u6210\u3002"
+ Icon: {fileID: 21300000, guid: 6a0350b4b8d6cd841907bd69c550a76b, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 15
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u8C37\u4ED3"
+ Desc: "\u5468\u56F4\u7684\u6BCF\u7247\u519C\u7530\u53EF\u4EE5\u63D0\u4F9B1\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002\\n\u6BCF\u5EA7\u57CE\u5E02\u4EC5\u80FD\u62E5\u6709\u4E00\u4E2A\u8C37\u4ED3\u3002\u9700\u8981<\u5EFA\u9020>\u79D1\u6280\u3002"
+ Icon: {fileID: 21300000, guid: 128e1895b83c19147a9e7abae5013836, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 13
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u52A0\u5DE5\u5382"
+ Desc: "\u5468\u56F4\u7684\u6BCF\u5EA7\u4F10\u6728\u573A\u53EF\u4EE5\u63D0\u4F9B1\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002\\n\u6BCF\u5EA7\u57CE\u5E02\u4EC5\u80FD\u62E5\u6709\u4E00\u4E2A\u52A0\u5DE5\u5382\u3002\u9700\u8981<\u6570\u5B66>\u79D1\u6280\u3002"
+ Icon: {fileID: 21300000, guid: 3736fd4d232ac644999388df827da0bd, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 14
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u51B6\u70BC\u5382"
+ Desc: "\u5468\u56F4\u7684\u6BCF\u5EA7\u4F10\u6728\u573A\u53EF\u4EE5\u63D0\u4F9B2\u70B9\u57CE\u5E02\u7ECF\u9A8C\u3002\\n\u6BCF\u5EA7\u57CE\u5E02\u4EC5\u80FD\u62E5\u6709\u4E00\u4E2A\u51B6\u70BC\u5382\u3002\\n\u9700\u8981<\u51B6\u70BC>\u79D1\u6280"
+ Icon: {fileID: 21300000, guid: c7090b827e3b73846848e3d4ca62c43f, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 18
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u5E02\u573A"
+ Desc: "\u6BCF\u56DE\u5408\u63D0\u4F9B\u5468\u56F4\u52A0\u5DE5\u5382\u3001\u91C7\u77FF\u573A\u3001\u51B6\u70BC\u5382\u7B49\u7EA7\u603B\u548C\u7684\u989D\u5916\u91D1\u5E01\u3002\\n\u6BCF\u5EA7\u57CE\u5E02\u4EC5\u80FD\u62E5\u6709\u4E00\u5EA7\u5E02\u573A\u3002\\n\u9700\u8981<\u8D38\u6613>\u79D1\u6280\u3002"
+ Icon: {fileID: 21300000, guid: 12d635ed2fbe2484f8165f6dc689d699, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 2
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u9053\u8DEF"
+ Desc: "\u4E0D\u63D0\u4F9B\u57CE\u5E02\u7ECF\u9A8C\uFF0C\u4F46\u662F\u53EF\u4EE5\u5EFA\u9020\u901A\u8DEF\uFF0C\u63D0\u4F9B\u79FB\u52A8\u529B\u52A0\u6210\u3002\\n\u53EF\u4EE5\u5EFA\u5728\u4E2D\u7ACB\u9886\u571F\u4E0A\u3002"
+ Icon: {fileID: 21300000, guid: 5a396d90a9458c14994d15d50181d129, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 3
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 19
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u795E\u5E99"
+ Desc: "\u53EA\u80FD\u5EFA\u5728\u6CA1\u6709\u68EE\u6797\u7684\u5E73\u539F\u4E0A\uFF0C\u6BCF\u56DE\u5408\u63D0\u4F9B\u4FE1\u4EF0\u5206\u3002"
+ Icon: {fileID: 21300000, guid: 27a5e613b3702524c8a590043d46ab2d, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 20
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 20
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u68EE\u6797\u795E\u5E99"
+ Desc: "\u53EA\u80FD\u5EFA\u5728\u6CA1\u6709\u4F10\u6728\u573A\u7684\u68EE\u6797\u4E0A\uFF0C\u6BCF\u56DE\u5408\u63D0\u4F9B\u4FE1\u4EF0\u5206\u3002"
+ Icon: {fileID: 21300000, guid: f1d52943ec8fb714b802a53f64d3f653, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 20
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 21
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u5C71\u795E\u5E99"
+ Desc: "\u53EA\u80FD\u5EFA\u5728\u6CA1\u6709\u91C7\u77FF\u573A\u7684\u5C71\u8109\u4E0A\uFF0C\u6BCF\u56DE\u5408\u63D0\u4F9B\u4FE1\u4EF0\u5206\u3002"
+ Icon: {fileID: 21300000, guid: 3439a16df11af0143bf980e4bdb162f6, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 20
+ - ActionId:
+ ActionType: 1
+ WonderType: 0
+ ResourceType: 22
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u6D77\u6D0B\u795E\u5E99"
+ Desc: "\u53EA\u80FD\u5EFA\u5728\u6CA1\u6709\u5EFA\u7B51\u7684\u6C34\u57DF\u4E2D\uFF0C\u6BCF\u56DE\u5408\u63D0\u4F9B\u4FE1\u4EF0\u5206\u3002"
+ Icon: {fileID: 21300000, guid: 50fa0b7a0cca4b84da0103b9aae16035, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 20
+ - ActionId:
+ ActionType: 2
+ WonderType: 1
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1"
+ Desc: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1,\u5B8C\u6210\u4EFB\u52A1\u540E\u53EF\u4EE5\u5EFA\u9020\u5947\u89C2"
+ Icon: {fileID: 21300000, guid: 9ae4068de3182e54c9c44e10b66089e6, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 2
+ WonderType: 2
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1"
+ Desc: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1,\u5B8C\u6210\u4EFB\u52A1\u540E\u53EF\u4EE5\u5EFA\u9020\u5947\u89C2"
+ Icon: {fileID: 21300000, guid: 5d2cbba21798bbf47af040f07f81ce58, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 2
+ WonderType: 3
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1"
+ Desc: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1,\u5B8C\u6210\u4EFB\u52A1\u540E\u53EF\u4EE5\u5EFA\u9020\u5947\u89C2"
+ Icon: {fileID: 21300000, guid: 99f299139fee8074babe65db7c3ba2fc, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 2
+ WonderType: 4
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1"
+ Desc: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1,\u5B8C\u6210\u4EFB\u52A1\u540E\u53EF\u4EE5\u5EFA\u9020\u5947\u89C2"
+ Icon: {fileID: 21300000, guid: 28481e4b4d1464f40b2463f41f7e0eb4, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 2
+ WonderType: 5
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1"
+ Desc: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1,\u5B8C\u6210\u4EFB\u52A1\u540E\u53EF\u4EE5\u5EFA\u9020\u5947\u89C2"
+ Icon: {fileID: 21300000, guid: 9654e91d69aca024c9a5f6e122007a1c, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 2
+ WonderType: 6
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1"
+ Desc: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1,\u5B8C\u6210\u4EFB\u52A1\u540E\u53EF\u4EE5\u5EFA\u9020\u5947\u89C2"
+ Icon: {fileID: 21300000, guid: c9a566b58f2082b4a9848735e022f3e7, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 2
+ WonderType: 7
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1"
+ Desc: "\u89E3\u9501\u5947\u89C2\u4EFB\u52A1,\u5B8C\u6210\u4EFB\u52A1\u540E\u53EF\u4EE5\u5EFA\u9020\u5947\u89C2"
+ Icon: {fileID: 21300000, guid: 6b82d407e72f5a04dad2051557c4a48c, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 1
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5355\u4F4D\u5347\u7EA7"
+ Desc: "\u6740\u6B7B3\u4E2A\u654C\u4EBA\u540E\uFF0C\u5355\u4F4D\u53EF\u4EE5\u5347\u7EA7\uFF0C\u751F\u547D\u503C\u4E0A\u9650+5\u5E76\u7ACB\u523B\u6062\u590D\u6240\u6709\u751F\u547D\u503C\u3002"
+ Icon: {fileID: 21300000, guid: f2126554d286b6d448668305e244637a, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 2
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u6062\u590D"
+ Desc: "\u6062\u590D2\u70B9\u751F\u547D\u503C\u3002\u5728\u5DF1\u65B9\u9886\u571F\u4E0A\u5219\u989D\u5916\u6062\u590D2\u70B9\u751F\u547D\u503C\u3002"
+ Icon: {fileID: 21300000, guid: c323ac3243bda414eaa9278eb9e48b64, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 3
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName:
+ Desc:
+ Icon: {fileID: -1049461823314036041, guid: e22523e4598b34743b9e70e61bd1215a, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 4
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u6316\u6398"
+ Desc: "\u6316\u6398\u9057\u8FF9\uFF0C\u5C06\u83B7\u5F97\u91D1\u5E01\u3001\u79D1\u6280\u3001\u5355\u4F4D\u7B49\u968F\u673A\u5956\u52B1\u3002"
+ Icon: {fileID: 2409451532123415758, guid: 26b53ff2426a2bb4cb59b989971dd55f, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 5
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u91C7\u96C6"
+ Desc: "\u91C7\u96C6\u6D77\u661F\uFF0C\u83B7\u5F9710\u91D1\u5E01\u7684\u5956\u52B1\u3002\u9700\u8981<\u8FDC\u6D0B\u5BFC\u822A>\u79D1\u6280\u3002"
+ Icon: {fileID: 21300000, guid: d2ae8861cb8d06a49a0b0d1a6fb05317, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 6
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5360\u9886\u57CE\u5E02"
+ Desc: "\u5360\u9886\u4E00\u4E2A\u6751\u5E84\u6216\u8005\u57CE\u5E02\uFF0C\u8BE5\u57CE\u5E02\u5956\u7EB3\u5165\u60A8\u7684\u9886\u571F\uFF01"
+ Icon: {fileID: 21300000, guid: 8d071a9c7a653e44ca0ce093bf9a991f, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 7
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u89E3\u96C7"
+ Desc: "\u89E3\u96C7\u8BE5\u5355\u4F4D\uFF0C\u5C06\u8FD4\u8FD8\u751F\u4EA7\u5355\u4F4D\u4E00\u534A\u7684\u8D39\u7528"
+ Icon: {fileID: 21300000, guid: ae88a6e6387f26640aafefa0f8f13cc6, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 11
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u6539\u9020\u5E06\u8239"
+ Desc: "\u5C06\u5C0F\u8239\u6539\u9020\u4E3A\u5E06\u8239\u3002\u6D77\u4E0A\u8FDC\u7A0B\u5355\u4F4D\u3002\u62E5\u67093\u79FB\u52A8\u529B2\u5C04\u7A0B\u548C<\u5DE1\u6D0B><\u51B2\u523A>\u6280\u80FD\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 72cdea71c8955e84b8c971c2a98ed784, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 5e45161bf08e1c24b925debded53cf25, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 5d6619e6a796e7b4daf82b8c2c20c6b8, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 129c2dbbb67cb024399dfacb703aa61d, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 5
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 12
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u6539\u9020\u51B2\u950B\u8247"
+ Desc: "\u5C06\u5C0F\u8239\u6539\u9020\u4E3A\u51B2\u950B\u8247\u3002\u6D77\u4E0A\u5F3A\u529B\u8FD1\u6218\u3002\u62E5\u67093\u79FB\u52A8\u529B3\u653B\u51FB\u529B3\u9632\u5FA1\u529B\u548C<\u51B2\u523A>\u6280\u80FD\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: b52ff165cd4970749901916c78b227d5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: fdddcfc4023434c44a0396de45ce2e3e, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 02a87bdfef4eb8d4eb1b1bd6702121f5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 77cd314448045a64b8c139052cb1b721, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 5
+ - ActionId:
+ ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 13
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u6539\u9020\u6218\u8230"
+ Desc: "\u5C06\u5C0F\u8239\u6539\u9020\u4E3A\u6218\u8230\u3002\u6D77\u4E0A\u8D85\u5F3A\u8FDC\u7A0B\u3002\u62E5\u67092\u79FB\u52A8\u529B3.5\u653B\u51FB\u529B3\u5C04\u7A0B\u548C<\u6E85\u5C04>\u6280\u80FD\u3002\u65E0\u6CD5\u53CD\u51FB\u3002"
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: aab7c2c92a9b95244b970ca9e2427377, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: f4afefbd54b21c04cbaaf206729628c6, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: ca222ed49ae2bae488e23508059c6619, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: d692b5d8b47c07c4a8ec0078dcf0796a, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 15
+ - ActionId:
+ ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 27
+ TechType: 0
+ ActionName: "\u6DF1\u6D77"
+ Desc:
+ Icon: {fileID: 21300000, guid: e82f9e6d364fb3944bb6b9b126425fe0, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 26
+ TechType: 0
+ ActionName: "\u6D45\u6D77"
+ Desc:
+ Icon: {fileID: 21300000, guid: dc29ebac5875f2846b237edabd9eaeca, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 25
+ TechType: 0
+ ActionName: "\u722C\u5C71"
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 1
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: b68c20c19ee51ac418164b94e7019787, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 1
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: aa59e9b148de3fb43b3e4f8042e7aa1d, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 2
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 655bdf0e55ee85143a173eea225a7dd5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 3
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 08f4c6a6eed9d594399367adb9cef813, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 0
+ - ActionId:
+ ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 24
+ TechType: 0
+ ActionName: "\u5C71\u5730\u9632\u5FA1"
+ Desc:
+ Icon: {fileID: 21300000, guid: fa8d97e1797480549ac041965c2b1ee5, type: 3}
+ VarientIcon: 0
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: b68c20c19ee51ac418164b94e7019787, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 1
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: aa59e9b148de3fb43b3e4f8042e7aa1d, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 2
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 655bdf0e55ee85143a173eea225a7dd5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 3
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 08f4c6a6eed9d594399367adb9cef813, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 0
+ - ActionId:
+ ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 21
+ TechType: 0
+ ActionName: "\u68EE\u6797\u9632\u5FA1"
+ Desc:
+ Icon: {fileID: 21300000, guid: 4a8142ccbfb89ce439b20338bc2a4e28, type: 3}
+ VarientIcon: 0
+ IconList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: b68c20c19ee51ac418164b94e7019787, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 1
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: aa59e9b148de3fb43b3e4f8042e7aa1d, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 2
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 655bdf0e55ee85143a173eea225a7dd5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 3
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 08f4c6a6eed9d594399367adb9cef813, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ Cost: 0
+ - ActionId:
+ ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 22
+ TechType: 0
+ ActionName: "\u6D45\u6D77\u9632\u5FA1"
+ Desc:
+ Icon: {fileID: 21300000, guid: b0d7a8a4d66e01f4d8ee9bb77a7d0d39, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 23
+ TechType: 0
+ ActionName: "\u6DF1\u6D77\u9632\u5FA1"
+ Desc:
+ Icon: {fileID: 21300000, guid: adeae4c8fda9ba14383047d7c0fc0e8c, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 5
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 1
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u690D\u6811"
+ Desc: "\u5728\u5E73\u539F\u4E0A\u79CD\u690D\u4E00\u7247\u68EE\u6797\u3002"
+ Icon: {fileID: 21300000, guid: 61ce16f462c2eea4c87bd53ffc5ffc8b, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 5
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 3
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u711A\u6797\u57A6\u7530"
+ Desc: "\u5C06\u68EE\u6797\u6539\u9020\u4E3A\u5E84\u7A3C\u5730\u3002"
+ Icon: {fileID: 21300000, guid: 809c6a0190012f94c89d4d84daf31fc4, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 5
+ - ActionId:
+ ActionType: 5
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 4
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u62C6\u9664"
+ Desc: "\u62C6\u9664\u6B64\u5904\u7684\u5EFA\u7B51\u3002\u4E0D\u4F1A\u8FD4\u8FD8\u4EFB\u4F55\u8D44\u6E90\u3002"
+ Icon: {fileID: 21300000, guid: 6fd87d281339c7541a30879a712d7746, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 5
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 2
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u6E05\u9664\u68EE\u6797"
+ Desc: "\u6E05\u9664\u68EE\u6797\uFF0C\u5E76\u83B7\u5F971\u70B9\u91D1\u5E01\u3002"
+ Icon: {fileID: 21300000, guid: 6ee77c3a216954243a606c0a32556ad9, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: -1
+ - ActionId:
+ ActionType: 3
+ WonderType: 1
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u548C\u5E73\u5947\u89C2"
+ Desc:
+ Icon: {fileID: 21300000, guid: 9ae4068de3182e54c9c44e10b66089e6, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 3
+ WonderType: 2
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u667A\u6167\u5947\u89C2"
+ Desc:
+ Icon: {fileID: 21300000, guid: 5d2cbba21798bbf47af040f07f81ce58, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 3
+ WonderType: 3
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u8D38\u6613\u5947\u89C2"
+ Desc:
+ Icon: {fileID: 21300000, guid: 99f299139fee8074babe65db7c3ba2fc, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 3
+ WonderType: 4
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u8D22\u5BCC\u5947\u89C2"
+ Desc:
+ Icon: {fileID: 21300000, guid: 28481e4b4d1464f40b2463f41f7e0eb4, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 3
+ WonderType: 5
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u6743\u529B\u5947\u89C2"
+ Desc:
+ Icon: {fileID: 21300000, guid: 9654e91d69aca024c9a5f6e122007a1c, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 3
+ WonderType: 6
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u6587\u5316\u5947\u89C2"
+ Desc:
+ Icon: {fileID: 21300000, guid: c9a566b58f2082b4a9848735e022f3e7, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 3
+ WonderType: 7
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u5EFA\u9020\u63A2\u7D22\u5947\u89C2"
+ Desc:
+ Icon: {fileID: 21300000, guid: 6b82d407e72f5a04dad2051557c4a48c, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 1
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u53EC\u5524 \u8299\u5170\u6735\u9732\xB7\u65AF\u5361\u96F7\u7279"
+ Desc: "\u53EC\u5524<\u9A6C>\u804C\u9636\u4F1F\u4EBA\uFF0C\u7834\u5C40\u8005\u3002\\n\u62E5\u6709<\u56DB\u91CD\u5B58\u5728>\u6280\u80FD\u3002\\n\u5168\u573A\u53EA\u80FD\u5B58\u5728\u81F3\u591A4\u4E2A\u8299\u5170\u6735\u9732\u65AF\u5361\u96F7\u7279\u3002"
+ Icon: {fileID: 21300000, guid: f4a89946e6d83f5498b8da8784d65ac4, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 15
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 2
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u53EC\u5524 \u857E\u7C73\u8389\u4E9A\xB7\u65AF\u5361\u96F7\u7279"
+ Desc: "\u53EC\u5524<\u738B>\u804C\u9636\u4F1F\u4EBA\uFF0C\u94DC\u5899\u94C1\u58C1\u3002\\n\u62E5\u6709<\u5438\u8840\u76DB\u5BB4>\u6280\u80FD\u3002\\n\u5168\u573A\u53EA\u80FD\u5B58\u5728\u4E00\u4E2A\u857E\u7C73\u8389\u4E9A\u65AF\u5361\u96F7\u7279\u3002"
+ Icon: {fileID: 21300000, guid: a5f0d65989fcf8140b7434d09144f244, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 15
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 3
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u53EC\u5524 \u5341\u516D\u591C\u54B2\u591C"
+ Desc: "\u53EC\u5524<\u8F66>\u804C\u9636\u4F1F\u4EBA\uFF0C\u8D85\u9AD8\u673A\u52A8\u6027\u523A\u5BA2\uFF0C\\n\u62E5\u6709<\u65F6\u95F4\u505C\u6B62>\u6280\u80FD\u3002\\n\u5168\u573A\u53EA\u80FD\u5B58\u5728\u4E00\u4E2A\u5341\u516D\u591C\u54B2\u591C\u3002"
+ Icon: {fileID: 21300000, guid: 869a247f7a81bff4c872f47d8e8e9cfe, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 15
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 4
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u53EC\u5524 \u7EA2\u7F8E\u94C3"
+ Desc: "<\u8F66>\u804C\u9636\u4F1F\u4EBA\uFF0C\u72C2\u6218\u58EB\u3002\\n\u62E5\u6709<\u592A\u6781>\u6280\u80FD\u3002\\n\u5168\u573A\u53EA\u80FD\u5B58\u5728\u4E00\u4E2A\u7EA2\u7F8E\u94C3\u3002"
+ Icon: {fileID: 21300000, guid: 82b5cf2ca68e54d4ba986589c3e86efd, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 15
+ - ActionId:
+ ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 5
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ ActionName: "\u53EC\u5524 \u5E15\u79CB\u8389\u8BFA\u857E\u59EC"
+ Desc: "<\u76F8>\u804C\u9636\u4F1F\u4EBA\uFF0C\u5F3A\u5927\u8F85\u52A9\u3002\\n\u62E5\u6709<\u7687\u5BB6\u70C8\u7130>\u6280\u80FD\u3002\\n\u5168\u573A\u53EA\u80FD\u5B58\u5728\u4E00\u4E2A\u5E15\u79CB\u8389\u8BFA\u857E\u59EC\u3002"
+ Icon: {fileID: 21300000, guid: bd7e07fc549ba8a46a4eb79a62f9090b, type: 3}
+ VarientIcon: 0
+ IconList: []
+ Cost: 15
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 1
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 2
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 2
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 3
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 4
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 5
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 6
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 7
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 8
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 9
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 10
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 11
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 12
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 13
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 14
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 15
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 16
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 17
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 18
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 19
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 20
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 21
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 22
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 23
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 24
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 25
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 26
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 27
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 28
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 29
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
+ - ActionId:
+ ActionType: 9
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 30
+ ActionName:
+ Desc:
+ Icon: {fileID: 0}
+ VarientIcon: 0
+ IconList: []
+ Cost: 0
diff --git a/My project/Assets/Resources/Export/ActionDataAssets.asset.meta b/My project/Assets/Resources/Export/ActionDataAssets.asset.meta
new file mode 100644
index 000000000..43bcad469
--- /dev/null
+++ b/My project/Assets/Resources/Export/ActionDataAssets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 94ead1d9ef420884b8752757007e5f3d
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/AnimDataAssets.asset b/My project/Assets/Resources/Export/AnimDataAssets.asset
new file mode 100644
index 000000000..2784c6f3c
--- /dev/null
+++ b/My project/Assets/Resources/Export/AnimDataAssets.asset
@@ -0,0 +1,20 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 166f55de27df0d64e9e1565037a54aaa, type: 3}
+ m_Name: AnimDataAssets
+ m_EditorClassIdentifier:
+ AttackAnimTime: 0.15
+ AttackReturnAnimTime: 0.15
+ CounterAnimTime: 0.15
+ CounterReturnAnimTime: 0.15
+ BetweenAttackCounterAnimTime: 0.1
+ MoveAnimTime: 0.15
diff --git a/My project/Assets/Resources/Export/AnimDataAssets.asset.meta b/My project/Assets/Resources/Export/AnimDataAssets.asset.meta
new file mode 100644
index 000000000..863938435
--- /dev/null
+++ b/My project/Assets/Resources/Export/AnimDataAssets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6222b7477e5810544bbf3399b7c5a3bc
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/CivDataAssets.asset b/My project/Assets/Resources/Export/CivDataAssets.asset
new file mode 100644
index 000000000..29a9efd55
--- /dev/null
+++ b/My project/Assets/Resources/Export/CivDataAssets.asset
@@ -0,0 +1,31 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 9630c76bba8a46c41ae17a5d8119d9a7, type: 3}
+ m_Name: CivDataAssets
+ m_EditorClassIdentifier:
+ CivDataList:
+ - CivId: 0
+ Civ: 0
+ CivName: "\u57C3\u53CA\u5E1D\u56FD"
+ CityList:
+ - CivId: 0
+ Civ: 1
+ CivName: "\u6CD5\u5170\u897F\u5E1D\u56FD"
+ CityList:
+ - CivId: 0
+ Civ: 2
+ CivName: "\u666E\u9C81\u58EB\u5E1D\u56FD"
+ CityList:
+ - CivId: 0
+ Civ: 3
+ CivName: "\u5370\u5EA6\u5E1D\u56FD"
+ CityList:
diff --git a/My project/Assets/Resources/Export/CivDataAssets.asset.meta b/My project/Assets/Resources/Export/CivDataAssets.asset.meta
new file mode 100644
index 000000000..1b0df9f19
--- /dev/null
+++ b/My project/Assets/Resources/Export/CivDataAssets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 78fb95fe1cdf1d743a75761564e269a8
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/GridAndResourceDataAssets.asset b/My project/Assets/Resources/Export/GridAndResourceDataAssets.asset
new file mode 100644
index 000000000..056138a79
--- /dev/null
+++ b/My project/Assets/Resources/Export/GridAndResourceDataAssets.asset
@@ -0,0 +1,516 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fc0ffc5c3a687734695e3393089231be, type: 3}
+ m_Name: GridAndResourceDataAssets
+ m_EditorClassIdentifier:
+ TerrainInfoList:
+ - TerrainType: 1
+ Sprite: {fileID: 0}
+ VarientSprite: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 94d08b14820ccb24eb2b87e651486e99, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - TerrainType: 2
+ Sprite: {fileID: 21300000, guid: dc29ebac5875f2846b237edabd9eaeca, type: 3}
+ VarientSprite: 0
+ SpriteList: []
+ - TerrainType: 3
+ Sprite: {fileID: 21300000, guid: e82f9e6d364fb3944bb6b9b126425fe0, type: 3}
+ VarientSprite: 0
+ SpriteList: []
+ ResourceInfoList:
+ - Resource: 9
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 2
+ SpriteList: []
+ - Resource: 10
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 2
+ SpriteList: []
+ - Resource: 11
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 1
+ SpriteList: []
+ - Resource: 12
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 1
+ SpriteList: []
+ - Resource: 13
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 0
+ SpriteList: []
+ - Resource: 14
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 0
+ SpriteList: []
+ - Resource: 15
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 0
+ SpriteList: []
+ - Resource: 16
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 3
+ SpriteList: []
+ - Resource: 17
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 0
+ SpriteList: []
+ - Resource: 18
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 0
+ SpriteList: []
+ - Resource: 19
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 1
+ SpriteList: []
+ - Resource: 20
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 1
+ SpriteList: []
+ - Resource: 21
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 1
+ SpriteList: []
+ - Resource: 22
+ Sprite: {fileID: 0}
+ VarientSprite: 0
+ Exp: 1
+ SpriteList: []
+ WonderInfoList:
+ - Wonder: 0
+ WonderType: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 9ae4068de3182e54c9c44e10b66089e6, type: 3}
+ Name: "\u5362\u514B\u7D22\u795E\u5E99"
+ Exp: 3
+ - Wonder: 1
+ WonderType: 2
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 5d2cbba21798bbf47af040f07f81ce58, type: 3}
+ Name: "\u4E9A\u5386\u5C71\u5927\u56FE\u4E66\u9986"
+ Exp: 3
+ - Wonder: 2
+ WonderType: 3
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 99f299139fee8074babe65db7c3ba2fc, type: 3}
+ Name: "\u5B5F\u83F2\u65AF\u8001\u57CE"
+ Exp: 3
+ - Wonder: 3
+ WonderType: 4
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 28481e4b4d1464f40b2463f41f7e0eb4, type: 3}
+ Name: "\u5409\u8428\u5927\u91D1\u5B57\u5854"
+ Exp: 3
+ - Wonder: 4
+ WonderType: 5
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 9654e91d69aca024c9a5f6e122007a1c, type: 3}
+ Name: "\u963F\u5E03\u8F9B\u8D1D\u5927\u795E\u5E99"
+ Exp: 3
+ - Wonder: 5
+ WonderType: 6
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: c9a566b58f2082b4a9848735e022f3e7, type: 3}
+ Name: "\u72EE\u8EAB\u4EBA\u9762\u50CF"
+ Exp: 3
+ - Wonder: 6
+ WonderType: 7
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 6b82d407e72f5a04dad2051557c4a48c, type: 3}
+ Name: "\u5965\u91CC\u897F\u65AF\u795E\u5E99"
+ Exp: 3
+ - Wonder: 7
+ WonderType: 1
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: fd412cc9548c654409cc979745ed1d40, type: 3}
+ Name: "\u67AB\u4E39\u767D\u9732\u5BAB"
+ Exp: 3
+ - Wonder: 8
+ WonderType: 2
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 25959da9c2209d2479802619fc828f5c, type: 3}
+ Name: "\u7D22\u90A6\u5927\u5B66"
+ Exp: 3
+ - Wonder: 9
+ WonderType: 3
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 0f1fce644ced23c4e907dc62ff4f23be, type: 3}
+ Name: "\u4EA4\u6613\u6240\u5E7F\u573A"
+ Exp: 3
+ - Wonder: 10
+ WonderType: 4
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 936535b388150f648a819b20d93498bb, type: 3}
+ Name: "\u5362\u6D6E\u5BAB"
+ Exp: 3
+ - Wonder: 11
+ WonderType: 5
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: e82a494ae6572eb4c8e993dbdf382f26, type: 3}
+ Name: "\u51EF\u65CB\u95E8"
+ Exp: 3
+ - Wonder: 12
+ WonderType: 6
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 54ea1a42bea9909498e3e5b5aaadd3ff, type: 3}
+ Name: "\u5DF4\u9ECE\u5723\u6BCD\u9662"
+ Exp: 3
+ - Wonder: 13
+ WonderType: 7
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 803ed8a071ab0b0499b592b50c7f0f42, type: 3}
+ Name: "\u5DF4\u9ECE\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 14
+ WonderType: 1
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 193db0ee37259d547aae9e6db2e9ff94, type: 3}
+ Name: "\u52C3\u5170\u767B\u5821\u95E8"
+ Exp: 3
+ - Wonder: 15
+ WonderType: 2
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: c32e08acd22a79443ba4de942202f32a, type: 3}
+ Name: "\u6D77\u767B\u5821\u5927\u5B66"
+ Exp: 3
+ - Wonder: 16
+ WonderType: 3
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 3bbafdaa5d59eed4ba343507956871b8, type: 3}
+ Name: "\u6C49\u5821\u6E2F\u53E3\u4ED3\u5E93\u57CE"
+ Exp: 3
+ - Wonder: 10
+ WonderType: 4
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: ef75559cb243afb4eaaf79225304177c, type: 3}
+ Name: "\u65B0\u5929\u9E45\u5821"
+ Exp: 3
+ - Wonder: 11
+ WonderType: 5
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 8c1cd235d851c2c40b3a229ce02781e5, type: 3}
+ Name: "\u67CF\u6797\u80DC\u5229\u7EAA\u5FF5\u67F1"
+ Exp: 3
+ - Wonder: 12
+ WonderType: 6
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 989d2cba4eb64c04486da63a9842f061, type: 3}
+ Name: "\u62DC\u7F57\u4F0A\u7279\u8282\u65E5\u5267\u9662"
+ Exp: 3
+ - Wonder: 20
+ WonderType: 7
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: f91a3b4a4a0057c4885eaaf387c1415d, type: 3}
+ Name: "\u9F50\u67CF\u6797\u98DE\u8247\u57FA\u5730"
+ Exp: 3
+ - Wonder: 21
+ WonderType: 1
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 926d627f005830c45a4cd0a9340569a5, type: 3}
+ Name: "\u963F\u80B2\u738B\u67F1"
+ Exp: 3
+ - Wonder: 22
+ WonderType: 2
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 638b23f0a528a6a4fa053b4c322a94ab, type: 3}
+ Name: "\u90A3\u70C2\u9640\u5BFA"
+ Exp: 3
+ - Wonder: 23
+ WonderType: 3
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 888d8979643e94d4ea8df8d63c927f02, type: 3}
+ Name: "\u4EA8\u6BD4"
+ Exp: 3
+ - Wonder: 24
+ WonderType: 4
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 74c37acd0d1b4fb4d8518a6d51c83258, type: 3}
+ Name: "\u6CF0\u59EC\u9675"
+ Exp: 3
+ - Wonder: 25
+ WonderType: 5
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 4e0751845026b6346ba6859d3f42fa17, type: 3}
+ Name: "\u7EA2\u5821"
+ Exp: 3
+ - Wonder: 26
+ WonderType: 6
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: ffc907a38bd53504696e00ba1c3f464d, type: 3}
+ Name: "\u7C73\u7EB3\u514B\u5E0C\u795E\u5E99"
+ Exp: 3
+ - Wonder: 27
+ WonderType: 7
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 28
+ WonderType: 1
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 29
+ WonderType: 2
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 30
+ WonderType: 3
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 31
+ WonderType: 4
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 32
+ WonderType: 5
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 33
+ WonderType: 6
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 34
+ WonderType: 7
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 35
+ WonderType: 1
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 36
+ WonderType: 2
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 37
+ WonderType: 3
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 38
+ WonderType: 4
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 39
+ WonderType: 5
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 40
+ WonderType: 6
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 41
+ WonderType: 7
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 42
+ WonderType: 1
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 43
+ WonderType: 2
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 44
+ WonderType: 3
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 45
+ WonderType: 4
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 46
+ WonderType: 5
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 47
+ WonderType: 6
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 48
+ WonderType: 7
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 49
+ WonderType: 1
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 50
+ WonderType: 2
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 51
+ WonderType: 3
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 52
+ WonderType: 4
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 53
+ WonderType: 5
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 54
+ WonderType: 6
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ - Wonder: 55
+ WonderType: 7
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: b85e184e11cedba42b422bf7fb971ec6, type: 3}
+ Name: "\u7B80\u5854\u66FC\u5854\u5929\u6587\u53F0"
+ Exp: 3
+ MountainInfo:
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: b68c20c19ee51ac418164b94e7019787, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ VegetationInfo:
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 1
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: cb0267035ec3ed44d8c74b79c550f5ec, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
diff --git a/My project/Assets/Resources/Export/GridAndResourceDataAssets.asset.meta b/My project/Assets/Resources/Export/GridAndResourceDataAssets.asset.meta
new file mode 100644
index 000000000..425aea1cb
--- /dev/null
+++ b/My project/Assets/Resources/Export/GridAndResourceDataAssets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5c11ac7aa51414a428e81362c470f4d2
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/Multilingual.asset b/My project/Assets/Resources/Export/Multilingual.asset
new file mode 100644
index 000000000..169341a25
--- /dev/null
+++ b/My project/Assets/Resources/Export/Multilingual.asset
@@ -0,0 +1,14 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 6e289c7fba3b438986c71305e15708a1, type: 3}
+ m_Name: Multilingual
+ m_EditorClassIdentifier:
diff --git a/My project/Assets/Resources/Export/Multilingual.asset.meta b/My project/Assets/Resources/Export/Multilingual.asset.meta
new file mode 100644
index 000000000..22a593c77
--- /dev/null
+++ b/My project/Assets/Resources/Export/Multilingual.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8bd9188ad5a97c24ba7301b4e9d07658
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/PlayerDataAssets.asset b/My project/Assets/Resources/Export/PlayerDataAssets.asset
new file mode 100644
index 000000000..8b1c34f1e
--- /dev/null
+++ b/My project/Assets/Resources/Export/PlayerDataAssets.asset
@@ -0,0 +1,79 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 17f0807fe6351374dbcf9d6e3309d3cb, type: 3}
+ m_Name: PlayerDataAssets
+ m_EditorClassIdentifier:
+ PlayerDataList:
+ - ForceId: 0
+ CivId: 0
+ CivName: "\u57C3\u53CA\u5E1D\u56FD"
+ ForceName: "\u857E\u7C73\u8389\u4E9A"
+ LeaderName: "\u857E\u7C73\u8389\u4E9A"
+ LeaderIllustration: {fileID: 21300000, guid: d4661e5af1f33b94ea56ac7d7b30b512, type: 3}
+ TechPool: 000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e000000
+ TechStart: 0000000008000000
+ - ForceId: 1
+ CivId: 1
+ CivName: "\u6CD5\u5170\u897F\u5E1D\u56FD"
+ ForceName: "\u84EC\u83B1\u5C71\u8F89\u591C"
+ LeaderName: "\u84EC\u83B1\u5C71\u8F89\u591C"
+ LeaderIllustration: {fileID: 21300000, guid: e1ef5c5c40488ae40bbd2ed4cf35b89e, type: 3}
+ TechPool: 000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000010000000110000001200000013000000140000001500000016000000170000001800000019000000
+ TechStart: 0000000006000000
+ - ForceId: 2
+ CivId: 2
+ CivName: "\u666E\u9C81\u58EB\u5E1D\u56FD"
+ ForceName: "\u516B\u5742\u795E\u5948\u5B50"
+ LeaderName: "\u516B\u5742\u795E\u5948\u5B50"
+ LeaderIllustration: {fileID: 21300000, guid: 3756265d254e8e542b0c198d11bf75d4, type: 3}
+ TechPool: 000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000010000000110000001200000013000000140000001500000016000000170000001800000019000000
+ TechStart: 0000000010000000
+ - ForceId: 3
+ CivId: 3
+ CivName: "\u5370\u5EA6\u5E1D\u56FD"
+ ForceName: "\u53E4\u660E\u5730\u89C9"
+ LeaderName: "\u53E4\u660E\u5730\u89C9"
+ LeaderIllustration: {fileID: 21300000, guid: c31b7225b784dca488b6376ef5fe77d5, type: 3}
+ TechPool: 000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000010000000110000001200000013000000140000001500000016000000170000001800000019000000
+ TechStart: 0000000014000000
+ - ForceId: 4
+ CivId: 4
+ CivName: "\u5317\u6D77\u5E1D\u56FD"
+ ForceName: "\u535A\u4E3D\u7075\u68A6"
+ LeaderName: "\u535A\u4E3D\u7075\u68A6"
+ LeaderIllustration: {fileID: 21300000, guid: 7827e23a317aaac4c8d5131a85e63094, type: 3}
+ TechPool: 000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000010000000110000001200000013000000140000001500000016000000170000001800000019000000
+ TechStart: 00000000
+ - ForceId: 5
+ CivId: 5
+ CivName: "\u4E0D\u5217\u98A0\u5E1D\u56FD"
+ ForceName: "\u5723\u767D\u83B2"
+ LeaderName: "\u5723\u767D\u83B2"
+ LeaderIllustration: {fileID: 21300000, guid: 41bf66abdaa83a74e9a9b6cff7cda10f, type: 3}
+ TechPool: 000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000010000000110000001200000013000000140000001500000016000000170000001800000019000000
+ TechStart: 00000000
+ - ForceId: 6
+ CivId: 6
+ CivName: "\u8428\u73CA\u5E1D\u56FD"
+ ForceName: "\u4E30\u806A\u8033\u795E\u5B50"
+ LeaderName: "\u4E30\u806A\u8033\u795E\u5B50"
+ LeaderIllustration: {fileID: 21300000, guid: 031b6571f7cb19549a2f0f97b386481f, type: 3}
+ TechPool: 000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000010000000110000001200000013000000140000001500000016000000170000001800000019000000
+ TechStart: 00000000
+ - ForceId: 7
+ CivId: 7
+ CivName: "\u62DC\u5360\u5EAD\u5E1D\u56FD"
+ ForceName: "\u65E5\u767D\u6B8B\u65E0"
+ LeaderName: "\u65E5\u767D\u6B8B\u65E0"
+ LeaderIllustration: {fileID: 21300000, guid: c5feb7e3a8bc4384e955e9fa2218fc25, type: 3}
+ TechPool: 000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000010000000110000001200000013000000140000001500000016000000170000001800000019000000
+ TechStart: 00000000
diff --git a/My project/Assets/Resources/Export/PlayerDataAssets.asset.meta b/My project/Assets/Resources/Export/PlayerDataAssets.asset.meta
new file mode 100644
index 000000000..3bb1fd111
--- /dev/null
+++ b/My project/Assets/Resources/Export/PlayerDataAssets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 31f15e99e6e4e0d41982384fff6b674d
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/TechDataAssets.asset b/My project/Assets/Resources/Export/TechDataAssets.asset
new file mode 100644
index 000000000..ece6baf36
--- /dev/null
+++ b/My project/Assets/Resources/Export/TechDataAssets.asset
@@ -0,0 +1,1113 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 12c31a70cd45a804d95898ce5d2fd0ec, type: 3}
+ m_Name: TechDataAssets
+ m_EditorClassIdentifier:
+ TechList:
+ - TechType: 0
+ TechName: None
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 1
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 0
+ techActions:
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 1
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 2
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 4
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 6
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 1
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 3
+ WonderType: 5
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 3
+ WonderType: 6
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 3
+ WonderType: 7
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 3
+ WonderType: 1
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 3
+ WonderType: 2
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 3
+ WonderType: 3
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 3
+ WonderType: 4
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 1
+ TechName: "\u722C\u5C71"
+ Description: "\u53EF\u4EE5\u5728\u5C71\u5730\u79FB\u52A8\uFF0C\u5E76\u83B7\u5F97\u5C71\u5730\u9632\u5FA1"
+ icon: {fileID: 0}
+ CostLevel: 1
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 0
+ techActions:
+ - ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 26
+ TechType: 0
+ - ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 25
+ TechType: 0
+ - TechType: 2
+ TechName: "\u51A5\u60F3"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 1
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 21
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 2
+ WonderType: 1
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 3
+ TechName: "\u91C7\u77FF"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 1
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 10
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 4
+ TechName: "\u54F2\u5B66"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 2
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 9
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 2
+ WonderType: 2
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 5
+ TechName: "\u51B6\u70BC"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 3
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 7
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 14
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 26
+ TechName: "\u4F1F\u4EBA[\u8F66\u4E4B\u9636]"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 4
+ GiantTech: 1
+ GiantTechSet: 0100000002000000030000000500000004000000
+ FatherTechType: 0
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 1
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 6
+ TechName: "\u91C7\u96C6"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 1
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 0
+ techActions:
+ - ActionType: 0
+ WonderType: 0
+ ResourceType: 5
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 7
+ TechName: "\u7B56\u7565"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 6
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 4
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 8
+ TechName: "\u8015\u79CD"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 6
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 9
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 9
+ TechName: "\u5916\u4EA4"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 7
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 8
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 10
+ TechName: "\u5EFA\u8BBE"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 8
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 15
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 5
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 3
+ SkillType: 0
+ TechType: 0
+ - TechType: 27
+ TechName: "KING\u804C\u9636\u53EC\u5524"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 4
+ GiantTech: 1
+ GiantTechSet: 060000000700000008000000090000000a000000
+ FatherTechType: 0
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 2
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 11
+ TechName: "\u9A91\u9A6C"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 1
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 0
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 2
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 12
+ TechName: "\u81EA\u7531\u7CBE\u795E"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 11
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 19
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 7
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 14
+ TechName: "\u9053\u8DEF"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 11
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 2
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 17
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 2
+ WonderType: 3
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 13
+ TechName: "\u9A91\u58EB"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 12
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 5
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 5
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 4
+ SkillType: 0
+ TechType: 0
+ - TechType: 15
+ TechName: "\u8D38\u6613"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 14
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 18
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 2
+ WonderType: 4
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 28
+ TechName: "KNIGHTS\u804C\u9636\u53EC\u5524"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 4
+ GiantTech: 1
+ GiantTechSet: 0b0000000c0000000e0000000f0000000d000000
+ FatherTechType: 0
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 4
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 16
+ TechName: "\u72E9\u730E"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 1
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 0
+ techActions:
+ - ActionType: 0
+ WonderType: 0
+ ResourceType: 4
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 17
+ TechName: "\u4F10\u6728"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 16
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 11
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 5
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 2
+ SkillType: 0
+ TechType: 0
+ - TechType: 18
+ TechName: "\u7BAD\u672F"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 16
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 3
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 22
+ TechType: 0
+ - TechType: 19
+ TechName: "\u6570\u5B66"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 17
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 6
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 13
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 20
+ TechName: "\u79CD\u690D"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 18
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 13
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 20
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 5
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 1
+ SkillType: 0
+ TechType: 0
+ - TechType: 29
+ TechName: "\u4F1F\u4EBA[\u540E\u4E4B\u9636]"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 4
+ GiantTech: 1
+ GiantTechSet: 1000000011000000120000001300000014000000
+ FatherTechType: 0
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 5
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 21
+ TechName: "\u6E14\u730E"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 1
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 0
+ techActions:
+ - ActionType: 0
+ WonderType: 0
+ ResourceType: 1
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 12
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 27
+ TechType: 0
+ - TechType: 22
+ TechName: "\u767B\u9646\u8247"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 21
+ techActions:
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 12
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 23
+ TechName: "\u5E06\u8239"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 2
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 21
+ techActions:
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 11
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 28
+ TechType: 0
+ - TechType: 24
+ TechName: "\u6D77\u6D0B\u5B66"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 22
+ techActions:
+ - ActionType: 1
+ WonderType: 0
+ ResourceType: 22
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 23
+ TechType: 0
+ - ActionType: 8
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 24
+ TechType: 0
+ - TechType: 25
+ TechName: "\u8FDC\u6D0B\u5BFC\u822A"
+ Description:
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 0
+ GiantTechSet:
+ FatherTechType: 23
+ techActions:
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 0
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 5
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - ActionType: 6
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 13
+ GiantType: 0
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
+ - TechType: 30
+ TechName: "\u4F1F\u4EBA[\u76F8\u4E4B\u9636]"
+ Description: "\u53EF\u4EE5\u53EC\u5524\u8BE5\u9635\u8425\u201C\u76F8\u4E4B\u9636\u201D\u7684\u4F1F\u4EBA"
+ icon: {fileID: 0}
+ CostLevel: 3
+ GiantTech: 1
+ GiantTechSet: 1500000016000000170000001800000019000000
+ FatherTechType: 0
+ techActions:
+ - ActionType: 4
+ WonderType: 0
+ ResourceType: 0
+ FeatureType: 0
+ TerrainType: 0
+ UnitType: 14
+ GiantType: 3
+ Vegetation: 0
+ UnitActionType: 0
+ CityLevelUpActionType: 0
+ GridMiscActionType: 0
+ SkillType: 0
+ TechType: 0
diff --git a/My project/Assets/Resources/Export/TechDataAssets.asset.meta b/My project/Assets/Resources/Export/TechDataAssets.asset.meta
new file mode 100644
index 000000000..b64036122
--- /dev/null
+++ b/My project/Assets/Resources/Export/TechDataAssets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9b81b94a68d068c49a4d0f3e3f259784
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/UICenterMessageDataAssets.asset b/My project/Assets/Resources/Export/UICenterMessageDataAssets.asset
new file mode 100644
index 000000000..d978e7289
--- /dev/null
+++ b/My project/Assets/Resources/Export/UICenterMessageDataAssets.asset
@@ -0,0 +1,100 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: d63a7493de6142c48a7d620ce81ddfc5, type: 3}
+ m_Name: UICenterMessageDataAssets
+ m_EditorClassIdentifier:
+ UICenterMessageInfoList:
+ - Id: 1
+ Type: 1
+ Title: "\u5F00\u542F\u5947\u89C2\u84DD\u56FE!"
+ Message: "\u60A8\u5DF2\u5F00\u542F\u4E86\u5947\u89C2:{name}\u7684\u84DD\u56FE\u3002\u4FDD\u63015\u56DE\u5408\u4E0D\u4E3B\u52A8\u653B\u51FB\uFF0C\u4ECE\u800C\u83B7\u5F97\u8BE5\u5947\u89C2!"
+ WonderType: 1
+ - Id: 2
+ Type: 1
+ Title: "\u5F00\u542F\u5947\u89C2\u84DD\u56FE!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}\u7684\u84DD\u56FE\u3002\u7814\u53D1\u6240\u6709\u57FA\u7840\u79D1\u6280(\u4E0D\u5305\u62EC\u4F1F\u4EBA\u804C\u9636\u79D1\u6280)\uFF0C\u4ECE\u800C\u83B7\u5F97\u8BE5\u5947\u89C2!"
+ WonderType: 2
+ - Id: 3
+ Type: 1
+ Title: "\u5F00\u542F\u5947\u89C2\u84DD\u56FE!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}\u7684\u84DD\u56FE\u3002\u62E5\u67095\u5EA7\u4E0E\u9996\u90FD\u8054\u901A\u7684\u57CE\u5E02\uFF0C\u4ECE\u800C\u83B7\u5F97\u8BE5\u5947\u89C2!"
+ WonderType: 3
+ - Id: 4
+ Type: 1
+ Title: "\u5F00\u542F\u5947\u89C2\u84DD\u56FE!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}\u7684\u84DD\u56FE\u3002\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u62E5\u6709\u8D85\u8FC7100\u679A\u91D1\u5E01\uFF0C\u4ECE\u800C\u83B7\u5F97\u8BE5\u5947\u89C2!"
+ WonderType: 4
+ - Id: 5
+ Type: 1
+ Title: "\u5F00\u542F\u5947\u89C2\u84DD\u56FE!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}\u7684\u84DD\u56FE\u3002\u51FB\u674010\u540D\u654C\u4EBA\uFF0C\u4ECE\u800C\u83B7\u5F97\u8BE5\u5947\u89C2!"
+ WonderType: 5
+ - Id: 6
+ Type: 1
+ Title: "\u5F00\u542F\u5947\u89C2\u84DD\u56FE!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}\u7684\u84DD\u56FE\u3002\u62E5\u6709\u4E00\u5EA76\u7EA7\u53CA\u4EE5\u4E0A\u7684\u57CE\u5E02\uFF0C\u4ECE\u800C\u83B7\u5F97\u8BE5\u5947\u89C2!"
+ WonderType: 6
+ - Id: 7
+ Type: 1
+ Title: "\u5F00\u542F\u5947\u89C2\u84DD\u56FE!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}\u7684\u84DD\u56FE\u3002\u62E5\u6709\u5730\u56FE\u5168\u90E8\u56DB\u4E2A\u89D2\u843D\u7684\u89C6\u91CE\uFF0C\u4ECE\u800C\u83B7\u5F97\u8BE5\u5947\u89C2!"
+ WonderType: 7
+ - Id: 8
+ Type: 2
+ Title: "\u83B7\u5F97\u5947\u89C2!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}!\u5728\u5E73\u539F\u6216\u8005\u6D45\u6D77\u5730\u533A\u5EFA\u9020\u60A8\u7684\u5947\u89C2\u5427!"
+ WonderType: 1
+ - Id: 9
+ Type: 2
+ Title: "\u83B7\u5F97\u5947\u89C2!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}!\u5728\u5E73\u539F\u6216\u8005\u6D45\u6D77\u5730\u533A\u5EFA\u9020\u60A8\u7684\u5947\u89C2\u5427!"
+ WonderType: 2
+ - Id: 10
+ Type: 2
+ Title: "\u83B7\u5F97\u5947\u89C2!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}!\u5728\u5E73\u539F\u6216\u8005\u6D45\u6D77\u5730\u533A\u5EFA\u9020\u60A8\u7684\u5947\u89C2\u5427!"
+ WonderType: 3
+ - Id: 11
+ Type: 2
+ Title: "\u83B7\u5F97\u5947\u89C2!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}!\u5728\u5E73\u539F\u6216\u8005\u6D45\u6D77\u5730\u533A\u5EFA\u9020\u60A8\u7684\u5947\u89C2\u5427!"
+ WonderType: 4
+ - Id: 12
+ Type: 2
+ Title: "\u83B7\u5F97\u5947\u89C2!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}!\u5728\u5E73\u539F\u6216\u8005\u6D45\u6D77\u5730\u533A\u5EFA\u9020\u60A8\u7684\u5947\u89C2\u5427!"
+ WonderType: 5
+ - Id: 13
+ Type: 2
+ Title: "\u83B7\u5F97\u5947\u89C2!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}!\u5728\u5E73\u539F\u6216\u8005\u6D45\u6D77\u5730\u533A\u5EFA\u9020\u60A8\u7684\u5947\u89C2\u5427!"
+ WonderType: 6
+ - Id: 14
+ Type: 2
+ Title: "\u83B7\u5F97\u5947\u89C2!"
+ Message: "\u60A8\u5DF2\u83B7\u5F97\u4E86\u5947\u89C2:{name}!\u5728\u5E73\u539F\u6216\u8005\u6D45\u6D77\u5730\u533A\u5EFA\u9020\u60A8\u7684\u5947\u89C2\u5427!"
+ WonderType: 7
+ - Id: 15
+ Type: 3
+ Title: "\u9047\u5230\u65B0\u7684\u6587\u660E!"
+ Message: "{civName}-{forceName}\u7684\u9886\u8896{leaderName}\u5411\u60A8\u548C\u60A8\u7684\u4F1F\u5927\u6587\u660E\u81F4\u4EE5\u8BDA\u631A\u7684\u95EE\u5019\u3002\u60A8\u83B7\u5F97\u4E86{money}\u91D1\u5E01\u7684\u4E00\u6B21\u6027\u8D38\u6613\u5956\u52B1\u3002"
+ WonderType: 0
+ - Id: 16
+ Type: 4
+ Title: "\u80A9\u8D1F\u91CD\u4EFB!"
+ Message: "\u60A8\u5DF2\u88AB\u59D4\u4EFB\u7BA1\u7406\u57C3\u53CA\u5E1D\u56FD\u65AF\u5361\u96F7\u7279\u738B\u671D\u3002\u8FD0\u7528\u60A8\u7684\u667A\u6167\u3001\u52C7\u6C14\u548C\u8FD0\u6C14\uFF0C\u5E26\u9886\u56FD\u5BB6\u8D70\u5411\u7E41\u8363\uFF01"
+ WonderType: 0
+ - Id: 17
+ Type: 5
+ Title: "\u5E1D\u56FD\u9668\u843D!"
+ Message: "\u6614\u65E5\u8F89\u714C\u5982\u671D\u9633\u521D\u5347\uFF0C\u4ECA\u671D\u5374\u968F\u98CE\u5C18\u6E6E\u6CA1\u3002{name}\u672A\u80FD\u7ECF\u53D7\u65F6\u5149\u7684\u8003\u9A8C\uFF0C\u7EC8\u7A76\u6E6E\u6CA1\u4E8E\u5386\u53F2\u957F\u6CB3\u7684\u6D9B\u58F0\u4E4B\u4E2D\u3002"
+ WonderType: 0
diff --git a/My project/Assets/Resources/Export/UICenterMessageDataAssets.asset.meta b/My project/Assets/Resources/Export/UICenterMessageDataAssets.asset.meta
new file mode 100644
index 000000000..618c1875e
--- /dev/null
+++ b/My project/Assets/Resources/Export/UICenterMessageDataAssets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2946577c0524a2f4690e88c277934394
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Resources/Export/UnitTypeDataAssets.asset b/My project/Assets/Resources/Export/UnitTypeDataAssets.asset
new file mode 100644
index 000000000..e3515a820
--- /dev/null
+++ b/My project/Assets/Resources/Export/UnitTypeDataAssets.asset
@@ -0,0 +1,1065 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 9fbd62ca888146f48a93a9d7a749619a, type: 3}
+ m_Name: UnitTypeDataAssets
+ m_EditorClassIdentifier:
+ UnitTypeList:
+ - UnitType: 1
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Warrior
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 10
+ Attack: 2
+ Defense: 2
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 2
+ Skills: 0800000002000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 0aa305c6fa2a1e347b1a1654e9916749, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 9330e311cccff25489d5450f23d2253e, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 95717e953addf6240b8ecaf898fca81e, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: b51db890eefc4374e874192ade475c85, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 07b9340a256d3f14e98a07b26776a349, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 28d1ee7ca00bb3c47881397f736e8c20, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 257160dea0566b341b19e32538e6fa47, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 77633f6d7240ede4a920d754283da6aa, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: 0bfcd37e7e30c264581c539f549cbe4a, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: 1ce98d95ffda42c448ecec1d740308a6, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: ee2a37f0b15d4a04c915b3b588919ade, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: 4d7f7d86c71fe7847bac6a73bd7da56b, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 2
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Rider
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 10
+ Attack: 2
+ Defense: 1
+ AttackRange: 1
+ MoveRange: 2
+ Cost: 3
+ Skills: 020000000300000008000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: cd6bf02b5a50ab6478dfbaae0c78eda6, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 98fec5d917751bd41ae73dbf7bf01373, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 1ec120fb74395554fa5a801de623b4c0, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 1f2a855a54d796741811956bc7137c9f, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: d1218fb75bc29a4408e5906e4c4ca29b, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: ffd7dcc625013f146b9191e7fd105f1f, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 5351895aa45f40b45a5561176119406a, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 7e673585d951a1846a2c08da92b249d7, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: 3f52a414a7ee7e54c92cccfb7479f4b3, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: 58e4e610a0375094bb0e4b818aa5ea60, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 98fec5d917751bd41ae73dbf7bf01373, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: b59c14228aadc854694235a00648d628, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 98fec5d917751bd41ae73dbf7bf01373, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: a4625583072bae04e9384740da68dfcb, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 3
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Archer
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 10
+ Attack: 2
+ Defense: 1
+ AttackRange: 2
+ MoveRange: 1
+ Cost: 3
+ Skills: 0200000008000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: c309c0d82c57f074b8ce6c64daf8c235, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: a4dbe30fd684f8a48a3ae33a284af38c, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 58413c2a66dfde142b6a1ccbe9f27e68, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: daa30b0e1b7271a4bb9f40577a473b1d, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 776e928d9af60ec4ea93b81b182d9b42, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: f32883623a2bfed409bedb33822d1e15, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 1e8a896b0bff269469dc3932a8706cc9, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 255591125b1c7a6438f95cf86d1aba01, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: 4ed16c51ed1e9dc4aa3b0e0a6966038a, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: 2b89141b9f2ff9b47a4184bf99e9731f, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: 8d48016a6aabf6b4ea4b375c582edced, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: fcbcefd3d70e5154a86fd004e45d799c, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 4
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Defender
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 15
+ Attack: 1
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 3
+ Skills: 08000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: e2d90fea274788343beeb783be7239e1, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 8e7272e494ab917479612c6692fcc5fd, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 6b69822039c6f164eae13f3047ceddda, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 6733146b4df960548aedd36811a9baa4, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 3a5b08e2d8ef56244b76ddf8e86eb827, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: dedfe6f3d4085db48b22ab1be72d9f8f, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: d4a256b9eaa2b73488b9583b3cf3a0f0, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 1c85e0ba811f7d54cba77eb7ea79e753, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: 51ea55f1c84ada648a94a93fe739782b, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: 52193b203afe3c34ba275c70abb3dc70, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: 07e32464b0b47934b893256dfd14f846, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: 94aed792daeb2be4f9c9c35972d6ca41, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 5
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Knights
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 10
+ Attack: 3.5
+ Defense: 1
+ AttackRange: 1
+ MoveRange: 3
+ Cost: 8
+ Skills: 020000000800000004000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 0478030a95f1e8f4f89dba9caf11f942, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 243ed641870af284eb0a0d878dac3fb0, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: bc07a0e352dc0ec4d953da0ae702714e, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 2e03d095a8e86ba49a20f2807b8588af, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 6c1be9a2822f2dd499a2675c58880f9f, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 02215415af2798c44aa45773b94aa4a5, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 10d088e6f0a8082469f19b5de3341c6c, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 2911dc32957c52641aeadca23e2970c0, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: b1941f6ab8c997441a718d0e53025464, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: a63151f63178f4e49acfa1f47ed67cbc, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: d0559e5a753c03d4c9b9326bc54470c0, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: 3a211403aea11e64e8314e6037fcea4a, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 6
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Catapult
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 10
+ Attack: 4
+ Defense: 0
+ AttackRange: 3
+ MoveRange: 1
+ Cost: 8
+ Skills: 07000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: f506a24f1810cc94db88966c30141449, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: de95b228dfc345547bff906624cad9a9, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: de978a3bf7b28104db2d1bd96b32d1cd, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: c3e6856531b0bf04a98cc6eb1dd9714c, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: a68d85698d73d744bbaa558ec0f55baf, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 2998a053e47b6de44b12d01753d23538, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: dcab41c93277f734c83b8bc8582fbb81, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: ca83323a741a79d4182a15b087ba149e, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: 5cd790cb1bee3fa428cc825d9ee2e0e4, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: c6af6852ae7924544a955b143ff36791, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: 8adae9c7a81780c4ebc8d209fec3a751, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: dcc163110753b4f4a9de765e568b5773, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 7
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Swordsman
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 15
+ Attack: 3
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 5
+ Skills: 02000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 24f4ae4dfde76d049a508a0a16aa107f, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: a4ad472d5ef26724bbeec4f9c0af3f50, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 07b05b46de560ed46b5b8d4162e2cf93, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: e9a4c05ee2850524e9bad650f5aa5dfd, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: ecc257b0a99511942a1fda317f2eab92, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 336b7f197404c2b469b1b4b0d7b573e6, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: e1142a63bb18f3346a85900db3261624, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: ac751fec4bb4dc743933fa9723b6759c, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: ea163c6832846da449fab552d8bb6bff, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: 8b2ea904b630ecb43ad9117300c24f24, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: 5eea99cc728140242b03f99561d927ec, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: c1141cd0c49a88a459dd878b89ed0fdd, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 8
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Cloak
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 5
+ Attack: 0
+ Defense: 0.5
+ AttackRange: 1
+ MoveRange: 2
+ Cost: 8
+ Skills: 0a0000000c0000000e00000006000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 0
+ SpriteList: []
+ - UnitType: 9
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Minder
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 10
+ Attack: 0
+ Defense: 1
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 5
+ Skills: 070000000d000000090000000a000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 0
+ SpriteList: []
+ - UnitType: 10
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Boat
+ LandType: 2
+ NoMaxHealth: 1
+ MaxHealth: 0
+ Attack: 0
+ Defense: 1
+ AttackRange: 1
+ MoveRange: 2
+ Cost: 0
+ Skills: 0b000000070000000d000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 1c9954195b020524db73e59fe2bcd942, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 0dea3c24f166f714a8028462ec1eea83, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: d8525feb00d3d194ab00e921b95fa91f, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 65d29c3e990ebdb40a0cf30512899221, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 14d6cf99ea7fd2445b4b2294cff0886f, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: c1ed6890aeccfc74dabdbe0c560006e8, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 0cf133073a4a59e4f8cafea297ac4880, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 0d36e4b97133afd48b46a62903efd4c9, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: 689442c02868d4e4e8fb274e529e73e6, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: be10d7681071b98409478fefa36deeca, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: a1d722a5f1ed92d4e87faefd39a4e6b0, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: a9f2e00f462b1834c844e487024ae41f, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 11
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Ship
+ LandType: 2
+ NoMaxHealth: 1
+ MaxHealth: 0
+ Attack: 2
+ Defense: 2
+ AttackRange: 2
+ MoveRange: 3
+ Cost: 5
+ Skills: 0b0000000c0000000d000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 72cdea71c8955e84b8c971c2a98ed784, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: ae3ed06ce7b582b44902849276acdf1c, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: 5e45161bf08e1c24b925debded53cf25, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 65cf0e580755fe74381a6daab94c121c, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 5d6619e6a796e7b4daf82b8c2c20c6b8, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: a1187963324eed2459c4ff155cc08714, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 129c2dbbb67cb024399dfacb703aa61d, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 45ffad6f8a6c2d44a8f6c5d8fddb3d25, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: 3cb96aef75c0cca4b90d43eae6e5c993, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: a5d36183f5859fd479df321cce459b88, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: d2963f5a24c31e84292fb849a06b5d42, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: 5a6359eda86e7be4283951139d95ae12, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 12
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: RammerShip
+ LandType: 2
+ NoMaxHealth: 1
+ MaxHealth: 0
+ Attack: 3
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 3
+ Cost: 5
+ Skills: 0b0000000d000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: b52ff165cd4970749901916c78b227d5, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 6349d50edb541b847b474e4684f9dad3, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: fdddcfc4023434c44a0396de45ce2e3e, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 58891a9d6a1acc64485e1d890a0ed2c0, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 02a87bdfef4eb8d4eb1b1bd6702121f5, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 866e486f995cbd145a69e6cb6f1ebc57, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 77cd314448045a64b8c139052cb1b721, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 123c25e35caa14e408d1d3174510647a, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: c1581efbc7d74a44abbfde81e2dbe706, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: 263942c885955f74fa24d6bdb19057b5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: e529ffae398766f499240af69fa1f7f5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: 02984bc23fa48db40bf75c3cf59b8481, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 13
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: BomberShip
+ LandType: 2
+ NoMaxHealth: 1
+ MaxHealth: 0
+ Attack: 3
+ Defense: 1
+ AttackRange: 3
+ MoveRange: 2
+ Cost: 15
+ Skills: 0b000000050000000d000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: aab7c2c92a9b95244b970ca9e2427377, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: f998772f700a3fc478b1a8a63863b8ab, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: f4afefbd54b21c04cbaaf206729628c6, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: d95f1275e9d8223458c838d184dfd250, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: ca222ed49ae2bae488e23508059c6619, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 0c058113abf0aa8438f8cbbd17e16502, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: d692b5d8b47c07c4a8ec0078dcf0796a, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: ff736e832b89f074aa4bf3889c97eb9b, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: 3ace2de0a0533b1498a802b1d61811f4, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: 388c5aaa098090e43884e5312468bfe9, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: 5e0485c845b06c34eba8d15359f67c7e, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: 07beb72a104f11f47bef3e21d49dcbe5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 15
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Big Guy
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 40
+ Attack: 4
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 0
+ Skills: 0d000000
+ Sprite: {fileID: 0}
+ SpriteGlow: {fileID: 0}
+ IsSpriteVarient: 1
+ SpriteList:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 0
+ ForceId: 0
+ Sprite: {fileID: 21300000, guid: 15b8ae2a5f592ec41a4f61736b107770, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 07e9401a5c9a284458366bea7ce742c7, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 1
+ ForceId: 1
+ Sprite: {fileID: 21300000, guid: ccc50745a363dbe49903b67a049d1738, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 403db2268c1a7c94e86372f07d1cc2a0, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 2
+ ForceId: 2
+ Sprite: {fileID: 21300000, guid: 49c7859254c88494cbf8a1a436591a78, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 38993cfb951a1b74b835e705b0883530, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 3
+ ForceId: 3
+ Sprite: {fileID: 21300000, guid: 4aa7581f148af6848a76951c675e055e, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: fd98626cad07ace41b5cebd20394ea89, type: 3}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 4
+ ForceId: 4
+ Sprite: {fileID: 21300000, guid: fce14abbeab7ae243af2756fbee171f5, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 5
+ ForceId: 5
+ Sprite: {fileID: 21300000, guid: 404f75ec26bf74f4ab34209b4982283d, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 6
+ ForceId: 6
+ Sprite: {fileID: 21300000, guid: 2d752b19d157dbf448e3829a8975e605, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - IgnoreCivId: 0
+ IgnoreForceId: 0
+ CivId: 7
+ ForceId: 7
+ Sprite: {fileID: 21300000, guid: 40d73026131f19c4d8d7e1b56eeb529d, type: 3}
+ SpriteGlow: {fileID: 0}
+ Name:
+ - UnitType: 16
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Phantom
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 30
+ Attack: 4
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 15
+ Skills: 1c0000001b00000022000000290000002a00000001000000
+ Sprite: {fileID: 21300000, guid: 0aa305c6fa2a1e347b1a1654e9916749, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 5724de750e51c6a49a6b57d60106275e, type: 3}
+ IsSpriteVarient: 0
+ SpriteList: []
+ - UnitType: 17
+ GiantType: 0
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Dabber
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 30
+ Attack: 4
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 15
+ Skills: 1c0000001b00000022000000290000002a00000001000000
+ Sprite: {fileID: 21300000, guid: bd7e07fc549ba8a46a4eb79a62f9090b, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 5724de750e51c6a49a6b57d60106275e, type: 3}
+ IsSpriteVarient: 0
+ SpriteList: []
+ - UnitType: 14
+ GiantType: 1
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Egypt Flandre
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 20
+ Attack: 4
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 15
+ Skills: 0200000027000000030000000f00000006000000210000001d000000
+ Sprite: {fileID: 21300000, guid: f4a89946e6d83f5498b8da8784d65ac4, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: c7229ac6b9cbb3c48a0bf40d37f8d3b6, type: 3}
+ IsSpriteVarient: 0
+ SpriteList: []
+ - UnitType: 14
+ GiantType: 2
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Egypt Remilia
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 30
+ Attack: 4
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 15
+ Skills: 0800000023000000240000002b000000
+ Sprite: {fileID: 21300000, guid: a5f0d65989fcf8140b7434d09144f244, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 60e49b250aebf3e40aaa1aedaf039ad6, type: 3}
+ IsSpriteVarient: 0
+ SpriteList: []
+ - UnitType: 14
+ GiantType: 3
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Egypt Sakuya
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 30
+ Attack: 4
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 15
+ Skills: 25000000260000002c000000
+ Sprite: {fileID: 21300000, guid: 869a247f7a81bff4c872f47d8e8e9cfe, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: a03eb25b8ec6903448d09ffef670f2bd, type: 3}
+ IsSpriteVarient: 0
+ SpriteList: []
+ - UnitType: 14
+ GiantType: 4
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Egypt Meiling
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 30
+ Attack: 4
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 15
+ Skills: 020000001300000028000000
+ Sprite: {fileID: 21300000, guid: 82b5cf2ca68e54d4ba986589c3e86efd, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 1cc0759060f203c46866a3678781e048, type: 3}
+ IsSpriteVarient: 0
+ SpriteList: []
+ - UnitType: 14
+ GiantType: 5
+ GiantCivId: 0
+ GiantForceId: 0
+ Name: Egypt Patchouli
+ LandType: 1
+ NoMaxHealth: 0
+ MaxHealth: 30
+ Attack: 4
+ Defense: 3
+ AttackRange: 1
+ MoveRange: 1
+ Cost: 15
+ Skills: 1c0000001b00000022000000290000002a00000001000000
+ Sprite: {fileID: 21300000, guid: bd7e07fc549ba8a46a4eb79a62f9090b, type: 3}
+ SpriteGlow: {fileID: 21300000, guid: 5724de750e51c6a49a6b57d60106275e, type: 3}
+ IsSpriteVarient: 0
+ SpriteList: []
diff --git a/My project/Assets/Resources/Export/UnitTypeDataAssets.asset.meta b/My project/Assets/Resources/Export/UnitTypeDataAssets.asset.meta
new file mode 100644
index 000000000..1413fb1b4
--- /dev/null
+++ b/My project/Assets/Resources/Export/UnitTypeDataAssets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8266b710a198c864bb1b14405df1834d
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/My project/Assets/Scripts/DataAssetsScript/GridObjectDataAssets.cs b/My project/Assets/Scripts/DataAssetsScript/GridObjectDataAssets.cs
index 9fd4bda81..0adec0eb1 100644
--- a/My project/Assets/Scripts/DataAssetsScript/GridObjectDataAssets.cs
+++ b/My project/Assets/Scripts/DataAssetsScript/GridObjectDataAssets.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using Logic.Multilingual;
using UnityEngine;
using RuntimeData;
@@ -192,6 +193,7 @@ public class WonderInfo
public uint CivId;
public uint ForceId;
public Sprite Sprite;
+ [MultilingualField]
public string Name;
public int Exp;
diff --git a/My project/Assets/Scripts/Logic/Editor/AchievementEditorWindow.cs b/My project/Assets/Scripts/Logic/Editor/AchievementEditorWindow.cs
index f82c47380..bd0fcd809 100644
--- a/My project/Assets/Scripts/Logic/Editor/AchievementEditorWindow.cs
+++ b/My project/Assets/Scripts/Logic/Editor/AchievementEditorWindow.cs
@@ -7,10 +7,7 @@
using System.Collections.Generic;
-using System.Linq;
using Logic.Achievement;
-using Logic.AI;
-using RuntimeData;
using UnityEditor;
using UnityEngine;
diff --git a/My project/Assets/Scripts/Logic/Editor/InspectorUtils.cs b/My project/Assets/Scripts/Logic/Editor/InspectorUtils.cs
index b2e556ae4..19061d875 100644
--- a/My project/Assets/Scripts/Logic/Editor/InspectorUtils.cs
+++ b/My project/Assets/Scripts/Logic/Editor/InspectorUtils.cs
@@ -96,19 +96,19 @@ namespace Logic.Editor
{
var recordColor = GUI.contentColor;
GUI.contentColor = color;
- var textWidth = GUI.skin.toggle.CalcSize(new GUIContent(text)).x;
- EditorGUILayout.LabelField(text, GUILayout.Width(textWidth));
+ var size = GUI.skin.toggle.CalcSize(new GUIContent(text));
+ EditorGUILayout.LabelField(text, GUILayout.Width(size.x), GUILayout.Height(size.y));
GUI.contentColor = recordColor;
}
// 固化 Text 宽度并支持 rich text
public static void InspectorTextWidthRich(string text)
{
- var textWidth = GUI.skin.toggle.CalcSize(new GUIContent(text)).x;
+ var size = GUI.skin.toggle.CalcSize(new GUIContent(text));
GUIStyle richTextStyle = new GUIStyle(GUI.skin.label);
richTextStyle.richText = true;
- EditorGUILayout.LabelField(text, richTextStyle, GUILayout.Width(textWidth));
+ EditorGUILayout.LabelField(text, richTextStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
}
// 固化 Text 宽度并支持 rich text
diff --git a/My project/Assets/Scripts/Logic/Editor/MultilingualEditorWindow.cs b/My project/Assets/Scripts/Logic/Editor/MultilingualEditorWindow.cs
new file mode 100644
index 000000000..6dec1c564
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Editor/MultilingualEditorWindow.cs
@@ -0,0 +1,281 @@
+/*
+* @Author: 白哉
+* @Description:
+* @Date: 2025年05月26日 星期一 17:05:14
+* @Modify:
+*/
+
+
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+using Logic.Multilingual;
+using TMPro;
+using UnityEditor;
+using UnityEngine;
+
+
+namespace Logic.Editor
+{
+ public class MultilingualEditorWindow : EditorWindow
+ {
+ // 滑条
+ private Vector2 _barPosition;
+
+ // 背景
+ private GUIStyle _redBoxStyle;
+ private GUIStyle _whiteBoxStyle;
+
+ private MultilingualData _asset;
+
+ private Dictionary _zhStrDict = new Dictionary();
+ private uint _idIndex;
+
+
+ [MenuItem("Tools/多语言编辑器")]
+ private static void ShowWindow()
+ {
+ var window = CreateWindow();
+ window.titleContent = new GUIContent("多语言编辑器");
+ window.Show();
+ window.minSize = new Vector2(500, 600);
+ }
+
+ protected virtual void OnEnable()
+ {
+
+ }
+
+ private void OnDisable()
+ {
+
+ }
+
+ private void OnGUI()
+ {
+ if (!_asset)
+ {
+ var path = $"Assets/Resources/Export/Multilingual.asset";
+ _asset = AssetDatabase.LoadAssetAtPath(path);
+ if (!_asset)
+ {
+ _asset = CreateInstance();
+ AssetDatabase.CreateAsset(_asset, path);
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ }
+ }
+
+ if (_redBoxStyle == null)
+ {
+ _redBoxStyle = InspectorUtils.GetHelpBoxStyle();
+ InspectorUtils.AddBorder(_redBoxStyle, new Color(0.5f, 0.4f, 0.4f, 0.6f));
+ }
+
+ if (_whiteBoxStyle == null)
+ {
+ _whiteBoxStyle = InspectorUtils.GetHelpBoxStyle();
+ InspectorUtils.AddBorder(_whiteBoxStyle, new Color(1f, 1f, 1f, 0.2f));
+ }
+
+ GUI.skin.button.wordWrap = true;
+ _barPosition = EditorGUILayout.BeginScrollView(_barPosition);
+
+ EditorGUILayout.BeginHorizontal();
+ if (InspectorUtils.InspectorButtonWithTextWidth("保存"))
+ {
+ EditorUtility.SetDirty(_asset);
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ }
+
+ if (InspectorUtils.InspectorButtonWithTextWidth("导出 Excel"))
+ {
+ AssetExportToExcel();
+ }
+
+ if (InspectorUtils.InspectorButtonWithTextWidth("Excel 导回"))
+ {
+ ExcelExportToAsset();
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+ foreach (var item in _asset.Items) ShowMultilingualItem(item);
+ EditorGUILayout.EndScrollView();
+ }
+
+ private void ShowMultilingualItem(MultilingualItem item)
+ {
+ EditorGUILayout.BeginVertical(EditorStyles.helpBox);
+ InspectorUtils.InspectorTextWidthRich($"{item.ID} : ");
+ InspectorUtils.InspectorTextWidthRich($" 中文:{item.ZH} ");
+ if (!string.IsNullOrEmpty(item.EN))
+ InspectorUtils.InspectorTextWidthRich($" 英语:{item.EN} ");
+ if (!string.IsNullOrEmpty(item.JP))
+ InspectorUtils.InspectorTextWidthRich($" 日语:{item.JP} ");
+ if (!string.IsNullOrEmpty(item.KR))
+ InspectorUtils.InspectorTextWidthRich($" 韩语:{item.KR} ");
+ EditorGUILayout.EndVertical();
+ EditorGUILayout.Space();
+ }
+
+ private void ExcelExportToAsset()
+ {
+ _asset.Items.Clear();
+ // 读取整个文件(而不是按行)
+ string csvContent = File.ReadAllText("Assets/CSV/Multilingual.csv");
+ List lines = new List();
+ StringBuilder currentLine = new StringBuilder();
+ bool inQuotes = false;
+ foreach (char c in csvContent)
+ {
+ if (c == '"') inQuotes = !inQuotes; // 进入/退出引号模式
+ if (c == '\n' && !inQuotes) // 换行符且不在引号内
+ {
+ lines.Add(currentLine.ToString());
+ currentLine.Clear();
+ }
+ else currentLine.Append(c);
+ }
+ if (currentLine.Length > 0) lines.Add(currentLine.ToString());
+
+ foreach (string line in lines)
+ {
+ if (string.IsNullOrWhiteSpace(line)) continue; // 跳过空行
+
+ string[] cells = line.Split(','); // 按逗号分割
+ if (cells.Length == 0) continue;
+
+ var item = new MultilingualItem();
+ item.ID = uint.Parse(cells[0]);
+ if (cells.Length >= 2) item.ZH = cells[1];
+ if (cells.Length >= 3) item.EN = cells[2];
+ if (cells.Length >= 4) item.JP = cells[3];
+ if (cells.Length >= 5) item.KR = cells[4];
+ _asset.Items.Add(item);
+ }
+ }
+
+ private void AssetExportToExcel()
+ {
+ _zhStrDict.Clear();
+ _idIndex = 1;
+
+ var uiObj = GameObject.Find("UICanvas");
+ if (!uiObj)
+ {
+ Debug.LogError($"找不到UI根节点");
+ return;
+ }
+
+ var coms = uiObj.GetComponentsInChildren(true).ToList();
+ foreach (var com in coms)
+ {
+ if (!Regex.IsMatch(com.text, @"[\u4E00-\u9FFF\u3400-\u4DBF]")) continue;
+ var textCom = com.gameObject.GetComponent();
+ if (!textCom) textCom = com.gameObject.AddComponent();
+
+ if (_zhStrDict.ContainsKey(com.text))
+ {
+ textCom.ID = _zhStrDict[com.text];
+ }
+ else
+ {
+ textCom.ID = _idIndex;
+ _zhStrDict[com.text] = _idIndex;
+ _idIndex++;
+ }
+ }
+
+ var path = $"Assets/Resources/DataAssets/";
+ string[] assetPaths = Directory.GetFiles(path, "*.asset", SearchOption.AllDirectories);
+ foreach (var assetPath in assetPaths)
+ {
+ var asset = AssetDatabase.LoadAssetAtPath(assetPath);
+ if (!asset) continue;
+ var targetAsset = GetExportAsset(asset);
+ TraverseObject(targetAsset);
+ }
+
+ string dirPath = Path.Combine(Application.dataPath, "CSV");
+ string filePath = Path.Combine(dirPath, "Multilingual.csv");
+ if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
+ if (!File.Exists(filePath))
+ {
+ using (File.Create(filePath)) { } // 立即释放句柄
+ }
+ using (StreamWriter sw = new StreamWriter(filePath, false, Encoding.UTF8))
+ {
+ foreach (var kv in _zhStrDict)
+ {
+ var text = $"\"{kv.Key.Replace("\"", "\"\"")}\"";
+ sw.WriteLine($"{kv.Value.ToString()},{text}");
+ }
+ }
+ }
+
+ private ScriptableObject GetExportAsset(ScriptableObject origin)
+ {
+ var target = $"Assets/Resources/Export/{origin.name}.asset";
+ if (File.Exists(target)) AssetDatabase.DeleteAsset(target);
+ bool success = AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(origin), target);
+ if (!success)
+ {
+ Debug.LogError($"拷贝失败!!!");
+ return null;
+ }
+
+ return AssetDatabase.LoadAssetAtPath(target);
+ }
+
+ private void TraverseObject(object asset)
+ {
+ if (asset == null) return;
+
+ var fields = asset.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
+ foreach (var field in fields)
+ {
+ var attr = field.GetCustomAttribute();
+ if (attr != null)
+ {
+ var str = (string)field.GetValue(asset);
+ if (str != null)
+ {
+ if (_zhStrDict.ContainsKey(str))
+ {
+ field.SetValue(asset, _zhStrDict[str].ToString());
+ }
+ else
+ {
+ _zhStrDict[str] = _idIndex;
+ field.SetValue(asset, _zhStrDict[str].ToString());
+ _idIndex++;
+ }
+ }
+ }
+
+ var son = field.GetValue(asset);
+ if (son == null) continue;
+
+ // 如果是集合(如 List),遍历元素
+ if (son is IEnumerable enumerable && !(son is string))
+ {
+ foreach (object item in enumerable)
+ {
+ TraverseObject(item); // 递归处理集合项
+ }
+ }
+ // 如果是自定义对象(非基础类型),递归处理
+ else if (!son.GetType().IsPrimitive && son.GetType() != typeof(string))
+ {
+ TraverseObject(son);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Editor/MultilingualEditorWindow.cs.meta b/My project/Assets/Scripts/Logic/Editor/MultilingualEditorWindow.cs.meta
new file mode 100644
index 000000000..80c77aabb
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Editor/MultilingualEditorWindow.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a56ccdc761c744868140905781ad040f
+timeCreated: 1748250370
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Main/Main.cs b/My project/Assets/Scripts/Logic/Main/Main.cs
index b99c8ba1f..26cf27774 100644
--- a/My project/Assets/Scripts/Logic/Main/Main.cs
+++ b/My project/Assets/Scripts/Logic/Main/Main.cs
@@ -9,6 +9,7 @@
using System;
using Logic.AI;
using Logic.Audio;
+using Logic.Multilingual;
using UnityEngine;
using RuntimeData;
using Unity.VisualScripting;
@@ -91,6 +92,7 @@ namespace Logic
UIManager.Init();
AchievementDataManager.Instance.Init();
AudioManager.Instance.Init();
+ MultilingualManager.Instance.Init();
//StartGame(height,width,0,0);
// ContinueGame();
}
diff --git a/My project/Assets/Scripts/Logic/Multilingual.meta b/My project/Assets/Scripts/Logic/Multilingual.meta
new file mode 100644
index 000000000..d151fa726
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 907a3279633d429782dc50bb682d2891
+timeCreated: 1748228910
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Multilingual/MultilingualData.cs b/My project/Assets/Scripts/Logic/Multilingual/MultilingualData.cs
new file mode 100644
index 000000000..16dbf6c36
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual/MultilingualData.cs
@@ -0,0 +1,64 @@
+/*
+* @Author: 白哉
+* @Description:
+* @Date: 2025年05月26日 星期一 11:05:13
+* @Modify:
+*/
+
+
+using System.Collections.Generic;
+using UnityEngine;
+
+
+namespace Logic.Multilingual
+{
+ public enum MultilingualType
+ {
+ ZH,
+ EN,
+ JP,
+ KR,
+ }
+
+
+ public class MultilingualData : ScriptableObject
+ {
+ public List Items = new List();
+ private Dictionary _itemDict;
+
+
+ public string GetMultilingualStr(uint id, MultilingualType type)
+ {
+ if (_itemDict == null) RefreshDict();
+ if (_itemDict == null) return string.Empty;
+ if (!_itemDict.TryGetValue(id, out var item)) return string.Empty;
+
+ return type switch
+ {
+ MultilingualType.ZH => item.ZH,
+ MultilingualType.EN => item.EN,
+ MultilingualType.JP => item.JP,
+ MultilingualType.KR => item.KR,
+ _ => string.Empty,
+ };
+ }
+
+ public void RefreshDict()
+ {
+ if (_itemDict == null) _itemDict = new Dictionary();
+ if (_itemDict.Count == Items.Count) return;
+ _itemDict.Clear();
+ foreach (var item in Items) _itemDict[item.ID] = item;
+ }
+ }
+
+
+ public class MultilingualItem
+ {
+ public uint ID;
+ public string ZH;
+ public string EN;
+ public string JP;
+ public string KR;
+ }
+}
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Multilingual/MultilingualData.cs.meta b/My project/Assets/Scripts/Logic/Multilingual/MultilingualData.cs.meta
new file mode 100644
index 000000000..747fe8a2b
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual/MultilingualData.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6e289c7fba3b438986c71305e15708a1
+timeCreated: 1748228934
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Multilingual/MultilingualFieldAttribute.cs b/My project/Assets/Scripts/Logic/Multilingual/MultilingualFieldAttribute.cs
new file mode 100644
index 000000000..e4dbefbf1
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual/MultilingualFieldAttribute.cs
@@ -0,0 +1,19 @@
+/*
+* @Author: 白哉
+* @Description:
+* @Date: 2025年05月26日 星期一 16:05:17
+* @Modify:
+*/
+
+
+using UnityEngine;
+
+
+namespace Logic.Multilingual
+{
+ [System.AttributeUsage(System.AttributeTargets.Field)]
+ public class MultilingualFieldAttribute : PropertyAttribute
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Multilingual/MultilingualFieldAttribute.cs.meta b/My project/Assets/Scripts/Logic/Multilingual/MultilingualFieldAttribute.cs.meta
new file mode 100644
index 000000000..4d9520db1
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual/MultilingualFieldAttribute.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 10df0406f1b14e8cb5bda01644cc2b6b
+timeCreated: 1748249593
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Multilingual/MultilingualManager.cs b/My project/Assets/Scripts/Logic/Multilingual/MultilingualManager.cs
new file mode 100644
index 000000000..b0e024153
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual/MultilingualManager.cs
@@ -0,0 +1,65 @@
+/*
+* @Author: 白哉
+* @Description:
+* @Date: 2025年05月26日 星期一 14:05:31
+* @Modify:
+*/
+
+
+using System.Collections.Generic;
+using System.Linq;
+using TMPro;
+using UnityEngine;
+
+
+namespace Logic.Multilingual
+{
+ public class MultilingualManager
+ {
+ public static MultilingualManager Instance = new MultilingualManager();
+ private MultilingualData _multilingualData;
+ private MultilingualType _currentType;
+ private List _textComs;
+
+
+ public void Init()
+ {
+ _currentType = (MultilingualType)PlayerPrefs.GetInt("Multilingual", 0);
+ ChangedMultilingual(_currentType);
+ }
+
+ public string GetMultilingualText(uint id)
+ {
+ return _multilingualData.GetMultilingualStr(id, _currentType);
+ }
+
+ public void ChangedMultilingual(MultilingualType type)
+ {
+ RefreshTextComs();
+ _currentType = type;
+ foreach (var textCom in _textComs) textCom.OnMultilingualChanged();
+ }
+
+ public void SetUIText(TextMeshPro textCom, string id)
+ {
+ if (!textCom) return;
+ var multilingual = textCom.gameObject.GetComponent();
+
+ if (!multilingual) multilingual = textCom.gameObject.AddComponent();
+ multilingual.ID = uint.Parse(id);
+ multilingual.OnMultilingualChanged();
+ }
+
+ private void RefreshTextComs()
+ {
+ var uiObj = GameObject.Find("UICanvas");
+ if (!uiObj)
+ {
+ Debug.LogError($"找不到UI根节点");
+ return;
+ }
+
+ _textComs = uiObj.GetComponentsInChildren(true).ToList();
+ }
+ }
+}
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Multilingual/MultilingualManager.cs.meta b/My project/Assets/Scripts/Logic/Multilingual/MultilingualManager.cs.meta
new file mode 100644
index 000000000..ee6c26536
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual/MultilingualManager.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f989a0e085d3414da2d3073fc51a1f03
+timeCreated: 1748241627
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Multilingual/MultilingualTextMono.cs b/My project/Assets/Scripts/Logic/Multilingual/MultilingualTextMono.cs
new file mode 100644
index 000000000..afd37c778
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual/MultilingualTextMono.cs
@@ -0,0 +1,34 @@
+/*
+* @Author: 白哉
+* @Description:
+* @Date: 2025年05月26日 星期一 14:05:50
+* @Modify:
+*/
+
+
+using TMPro;
+using UnityEngine;
+
+
+namespace Logic.Multilingual
+{
+ public class MultilingualTextMono : MonoBehaviour
+ {
+ public uint ID = 0;
+
+
+ private void OnEnable()
+ {
+ if (ID == 0) return;
+ OnMultilingualChanged();
+ }
+
+ public void OnMultilingualChanged()
+ {
+ if (ID == 0) return;
+ var text = GetComponent();
+ if (!text) return;
+ text.text = MultilingualManager.Instance.GetMultilingualText(ID);
+ }
+ }
+}
\ No newline at end of file
diff --git a/My project/Assets/Scripts/Logic/Multilingual/MultilingualTextMono.cs.meta b/My project/Assets/Scripts/Logic/Multilingual/MultilingualTextMono.cs.meta
new file mode 100644
index 000000000..dde24c5fd
--- /dev/null
+++ b/My project/Assets/Scripts/Logic/Multilingual/MultilingualTextMono.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6b27f832d22e4a8d916272b644937774
+timeCreated: 1748241401
\ No newline at end of file
diff --git a/My project/sdk/Readme.txt b/My project/sdk/Readme.txt
new file mode 100644
index 000000000..a3decf9d9
--- /dev/null
+++ b/My project/sdk/Readme.txt
@@ -0,0 +1,1303 @@
+================================================================
+
+Copyright 1996-2024, Valve Corporation, All rights reserved.
+
+================================================================
+
+
+Welcome to the Steamworks SDK. For documentation please see our partner
+website at: http://partner.steamgames.com
+
+
+----------------------------------------------------------------
+v1.62 14th March 2025
+----------------------------------------------------------------
+
+ISteamFriends:
+* Removed SetPersonaName() and GetUserRestrictions().
+
+ISteamHTMLSurface:
+* Renamed EMouseCursor to EHTMLMouseCursor, and renamed values to match.
+
+ISteamRemotePlay:
+* Removed BStartRemotePlayTogether() since it's always available when a supported game launches.
+* Added ShowRemotePlayTogetherUI() to show the Remote Play Together UI in the game overlay.
+* Added functions to get remote keyboard and mouse input directly instead of simulating local input: BEnableRemotePlayTogetherDirectInput(), DisableRemotePlayTogetherDirectInput(), GetInput(), SetMouseVisibility(), SetMousePosition(), CreateMouseCursor(), SetMouseCursor().
+
+ISteamUGC:
+* Added SetSubscriptionsLoadOrder() to allow changing the load order.
+* Added SetItemsDisabledLocally() set an item as locally disabled or not.
+* GetNumSubscribedItems() and GetSubscribedItems() also takes an optional boolean to return locally disabled items as well.
+
+
+----------------------------------------------------------------
+v1.61 8th November 2024
+----------------------------------------------------------------
+
+ISteamTimeline:
+* Renamed Set/ClearTimelineStateDescription to Set/ClearTimelineTooltip to make it more clear where the text will appear.
+* Renamed AddTimelineEvent to AddInstantaneousTimelineEvent and removed the duration parameter.
+* Added AddRangeTimelineEvent for adding a a timeline event that happens over a period of time.
+* Added Start/Update/EndRangeTimelineEvent calls for situations where the caller doesn't know when the event will end before creating it.
+* Added RemoveTimelineEvent to let the game remove an event it previously added
+* Added DoesEventRecordingExist/OpenOverlayToTimelineEvent, which allow the game to show an event in the Steam overlay
+* Added Start/EndGamePhase, along with some supporting functions, to let the game identify meaningful time ranges like multiplayer matches or chapters in a single player game. See the Timeline documentation for more information.
+
+ISteamUserStats:
+* RequestCurrentStats is no longer necessary and has been removed. The Steam Client will synchronize this data before your game launches.
+
+ISteamInput:
+* Added glyph support for the Wireless HORIPAD for Steam
+
+
+----------------------------------------------------------------
+v1.60 19th June 2024
+----------------------------------------------------------------
+
+General
+* CSteamAPIContext has been removed. Please switch to using the Steam accessors where appropriate.
+
+ISteamTimeline
+* Added this new interface to allow games to provide information that supports the new Game Recording feature. See the [url=https://partner.steamgames.com/doc/features/timeline]Timeline[/url] documentation for more information.
+
+ISteamUGC
+* Added 64 bit m_ulTotalFilesSize to SteamUGCDetails_t which is the correct size of the content for Workshop items are larger than 2,147,483,647 bytes.
+* Added GetNumSupportedGameVersions() and GetSupportedGameVersionData() which can be used to determine what game beta branches a Workshop item supports/is valid for.
+* Added SetAdminQuery() to allow ISteamUGC to be used in a tools like environment for users who have the appropriate privileges for the calling appid.
+
+ISteamApps
+* Added API to allow the game to manage active beta branches.
+
+
+----------------------------------------------------------------
+v1.59 9th February 2024
+----------------------------------------------------------------
+General
+* Added new initialization method, SteamAPI_InitFlat
+
+ISteamUtils
+* Added DismissGamepadTextInput
+
+ISteamAppList
+* This interface has been removed from the SDK
+
+----------------------------------------------------------------
+v1.58a 26th October 2023
+----------------------------------------------------------------
+Fixes to steam_api_flat.h
+
+----------------------------------------------------------------
+v1.58 15th September 2023
+----------------------------------------------------------------
+ISteamRemotePlay
+* Added BStartRemotePlayTogether to start Remote Play Together and optionally show the UI in the overlay
+
+ISteamUGC
+* The function SetItemTags now takes in a parameter to allow the modification of admin tags through the SDK if the logged-in user has the appropriate permissions
+* Added GetUserContentDescriptorPreferences, which can be used to show the user their current set of preferences and then direct them to Steam to modify them at https://store.steampowered.com/account/preferences/
+
+Misc.
+* Added SteamAPI_InitEx and SteamGameServer_InitEx, which will return k_ESteamAPIInitResult_OK upon success or an error code specified in in ESteamAPIInitResult. An optional, non-localized error message can also be returned.
+* SteamAPI_Init() will now return false if the installed Steam client needs to be updated to support the games version of the SDK
+* Improved handling of corrupted tickets via updated sdkencryptedappticket.lib
+
+----------------------------------------------------------------
+v1.57 28th April 2022
+----------------------------------------------------------------
+User
+* Updated ISteamUser::GetAuthTicketForWebApi(), To create a ticket for use by the AuthenticateUserTicket Web API
+* Updated ISteamUser::GetAuthSessionTicket(), No longer to be used to create a ticket for use by the AuthenticateUserTicket Web API
+
+----------------------------------------------------------------
+v1.56 30th March 2023
+----------------------------------------------------------------
+User
+* Updated ISteamUser::GetAuthSessionTicket(), Add parameter SteamNetworkingIdentity
+
+----------------------------------------------------------------
+v1.55 29th July 2022
+----------------------------------------------------------------
+
+ISteamInput
+* Added SetDualSenseTriggerEffect and corresponding header isteamdualsense.h for setting the adaptive trigger effect on DualSense controllers
+
+Spacewar example:
+* Added an example of using SetDualSenseTriggerEffect
+
+----------------------------------------------------------------
+v1.54 16th June 2022
+----------------------------------------------------------------
+
+ISteamFriends
+* Added various functions to retrieve equipped Steam Community profile items and their properties
+** RequestEquippedProfileItems requests information on what Steam Community profile items a user has equipped. Will send callback EquippedProfileItems_t.
+** BHasEquippedProfileItem after calling RequestEquippedProfileItems, returns true/false depending on whether a user has a ECommunityProfileItemType equipped or not
+** GetProfileItemPropertyString returns a string property given a ECommunityProfileItemType and ECommunityProfileItemProperty
+** GetProfileItemPropertyUint returns an unsigned integer property given a ECommunityProfileItemType and ECommunityProfileItemProperty
+* Added callback EquippedProfileItemsChanged_t for when a user's equipped Steam Community profile items have changed. This will be sent for the current user and for their friends.
+
+Spacewar example:
+* Added examples for how to interact with various overlay related functions (e.g. ActivateGameOverlay, ActivateGameOverlayToUser, ActivateGameOverlayToWebPage, ActivateGameOverlayToStore, ActivateGameOverlayInviteDialogConnectString)
+* Fixed Steam Input example code not working on Linux
+
+----------------------------------------------------------------
+v1.53a 11th December 2021
+----------------------------------------------------------------
+
+macOS
+* Fixed libsdkencryptedappticket.dylib to include arm64 support
+
+----------------------------------------------------------------
+v1.53 23th November 2021
+----------------------------------------------------------------
+
+SteamNetworkingSockets:
+* Added support for connections to have multiple streams of messages, known as "lanes," with mechanisms to control bandwidth utilization and head-of-line blocking between lanes.
+* Added the "FakeIP" system, which can be useful to add P2P networking or Steam Datagram Relay support to games while retaining the assumption that network hosts are identified by an IPv4 address. Added steamnetworkingfakeip.h and ISteamNetworkingFakeUDPPort
+* Simplified interface for iterating config values.
+* Added SteamNetConnectionInfo_t::m_nFlags, which have misc info about a connection.
+
+ISteamInput
+* Added Steam Deck values to the EInputActionOrigin and ESteamInputType origins
+
+ISteamUGC:
+* Added SetTimeCreatedDateRange and SetTimeUpdatedDateRange
+
+ISteamUtils:
+* Added DismissFloatingGamepadTextInput
+
+Flat Interface:
+* For each interface accessor, there is now an inline, unversioned accessor that calls the versioned accessor exported by the .dll. This reduces the number of changes that need to be made when updating the SDK and accessing the flat interface directly, while still retaining version safety.
+
+General:
+* Removed definitions for many internal callback IDs that are not needed by general users of the SDK.
+
+Spacewar example:
+* Added CItemStore, which demonstrates how to interact with an in-game store
+
+----------------------------------------------------------------
+v1.52 14th September 2021
+----------------------------------------------------------------
+
+ISteamInput
+* Added support for bundling Steam Input API configurations w/ game depots. Allows developers to use the same configuration file across public/private AppIDs, check configurations into their revision control systems, more easily juggle changes between beta branches, and ensure game/config changes are done in-sync.
+* Added new glyph API support for SVG glyphs and multiple sizes of PNG files. Note: these images will be added in a subsequent Steam Beta Client release.
+* Added support for callbacks for action state changes, controller connect/disconnect, and controller mapping changes.
+* Added BNewDataAvailable function to reduce need to manually compare action data between frames.
+* Added BWaitForData helper function to wait on an event set when controller data is updated.
+* Added functions for getting the localized string for action names (GetStringForDigitalActionName and GetStringForAnalogActionName).
+* Added function to poll current Steam Input enable settings by controller type (GetSessionInputConfigurationSettings).
+
+ISteamGameServer
+* Renamed EnableHeartbeats to SetAdvertiseServerActive.
+* Deprecated the following methods (they have been renamed to *_DEPRECATED and will be removed in a future SDK update):
+** SendUserConnectAndAuthenticate
+** SendUserDisconnect
+** SetMasterServerHeartbeatInterval
+** ForceMasterServerHeartbeat
+
+ISteamRemoteStorage
+* Added GetLocalFileChangeCount and GetLocalFileChange which allows for iterating over Steam Cloud files that have changed locally after the initial sync on app start, when supported by the app. The callback notification is RemoteStorageLocalFileChange_t.
+* Added BeginFileWriteBatch and EndFileWriteBatch to hint to Steam that a set of files should be written to Steam Cloud together (e.g. a game save that requires updating more than one file).
+* Removed the following unused callbacks: RemoteStorageAppSyncedClient_t, RemoteStorageAppSyncedServer_t, RemoteStorageAppSyncProgress_t, and RemoteStorageAppSyncStatusCheck_t.
+
+ISteamUGC
+* Added ability to sort by "time last updated" (k_EUGCQuery_RankedByLastUpdatedDate).
+* Added ShowWorkshopEULA and GetWorkshopEULAStatus, which allows a game to have a separate EULA for the Steam Workshop.
+* Added UserSubscribedItemsListChanged_t callback.
+* Added WorkshopEULAStatus_t callback, which will be sent asynchronously after calling GetWorkshopEULAStatus.
+
+ISteamUser
+* Deprecated InitiateGameConnection and TerminateGameConnection (renamed to *_DEPRECATED). Please migrate to BeginAuthSession and EndAuthSession.
+
+ISteamUtils
+* Added IsSteamRunningOnSteamDeck - Can be used to optimize the experience of the game on Steam Deck, such as scaling the UI appropriately, applying performance related settings, etc.
+* Added SetGameLauncherMode - In game launchers that don't have controller support you can call this to have Steam Input translate the controller input into mouse/kb to navigate the launcher.
+* Added AppResumingFromSuspend_t callback - Sent after the device returns from sleep/suspend mode.
+* Added ShowFloatingGamepadTextInput - Activates the modal gamepad input keyboard which pops up over game content and sends OS keyboard keys directly to the game. Note: Currently this is only implemented in the Steam Deck UI.
+* Added FloatingGamepadTextInputDismissed_t callback - Sent after the floating gamepad input keyboard displayed via ShowFloatingGamepadTextInput has been dismissed.
+
+macOS
+* Added i386/x86_64/arm64 universal builds of libsdkencryptedappticket.dylib and libsteam_api.dylib
+
+Steamworks Example Project
+* Updated project to illustrate new Steam Input changes
+* Updated to build properly with macOS 11 SDK for arm64
+* Updated Windows project files to Visual Studio 2015
+* Windows project files now target Windows 8.1
+* Windows project files now set include and library path using DXSDK_DIR
+
+Misc.
+* ISteamAppList - Added m_iInstallFolderIndex to SteamAppInstalled_t and SteamAppUninstalled_t callbacks.
+* ISteamApps - Removed unused SteamGameServerApps() accessor.
+* CSteamGameServerAPIContext - removed SteamApps() accessor.
+* Cleanup of types and enums that were unnecessarily in the SDK.
+
+
+----------------------------------------------------------------
+v1.51 8th January 2021
+----------------------------------------------------------------
+ISteamUGC
+* Added GetQueryUGCNumTags(), GetQueryUGCTag(), and GetQueryUGCTagDisplayName() for access to an item's tags and the display names (e.g. localized versions) of those tags
+* A previous SDK update added (but failed to call out) AddRequiredTagGroup() which allows for matching at least one tag from the group (logical "or")
+
+ISteamInput & ISteamController
+* Added PS5 Action Origins
+
+ISteamFriends
+* Added ActivateGameOverlayInviteDialogConnectString - Activates the game overlay to open an invite dialog that will send the provided Rich Presence connect string to selected friends
+
+Steamworks Example
+* Updated to use latest SteamNetworkingSockets API
+
+Content Builder
+* Updated upload example to use a single script file to upload a simple depot
+
+----------------------------------------------------------------
+v1.50 29th August 2020
+----------------------------------------------------------------
+* Added ISteamUtils::InitFilterText() and ISteamUtils::FilterText() which allow a game to filter content and user-generated text to comply with China legal requirements, and reduce profanity and slurs based on user settings.
+* Added ISteamNetworkingMessages, a new non-connection-oriented API, similar to UDP. This interface is intended to make it easy to port existing UDP code while taking advantage of the features provided by ISteamNetworkingSockets, especially Steam Datagram Relay (SDR).
+* Added poll groups to ISteamNetworkingSockets. Poll groups are a way to receive messages from many different connections at a time.
+* ISteamNetworkingSockets::ReceiveMessagesOnListenSocket has been removed. (Use poll groups instead.)
+* Added symmetric connect mode to ISteamNetworkingSockets. This can be used to solve the coordination problem of establishing a single connection between two peers, when both peers may initiating the connection at the same time and neither peer is the server or client.
+* ISteamNetworking is deprecated and may be removed in a future version of the SDK. Please use ISteamNetworkingSockets or ISteamNetworkingMessages instead.
+
+
+----------------------------------------------------------------
+v1.49 12th June 2020
+----------------------------------------------------------------
+* Added ISteamApps::BIsTimedTrial() which allows a game to check if user only has limited playtime
+* Added ISteamFriends::RegisterProtocolInOverlayBrowser() which will enable dispatching callbacks when the overlay web browser navigates to a registered custom protocol, such as mygame://
+* Added ISteamuserStats::GetAchievementProgressLimits() which lets the game query at run-time the progress-based achievements bounds as set by the developers in the Steamworks application settings
+* Added tool to demonstrate processing the steam.signatures file that comes in the steam client package.
+
+
+----------------------------------------------------------------
+v1.48a 26th March 2020
+----------------------------------------------------------------
+
+macOS
+* Fixed notarization issues caused by missing code signature of libsdkencryptedappticket.dylib
+
+
+----------------------------------------------------------------
+v1.48 12th February 2020
+----------------------------------------------------------------
+
+ISteamNetworkingSockets
+* Added the concept of a "poll group", which is a way to receive messages from many connections at once, efficiently.
+* ReceiveMessagesOnListenSocket was deleted. To get the same functionality, create a poll group, and then add connections to this poll group when accepting the connection.
+
+Flat interface redesign
+* Fixed many missing interfaces and types.
+* All versions of overloaded functions are now available, using distinct names.
+* There are now simple, global versioned functions to fetch the interfaces. No more need to mess with HSteamPipes or HSteamUsers directly.
+* The json file now has much more detailed information and several errors have been fixed.
+* steam_api_interop.cs has been removed and will no longer be supported.
+* There is a new manual dispatch API for callbacks, which works similarly to a windows event loop. This is a replacement for the existing callback registeration and dispatch mechanisms, which which are nice in C++ but awkward to use outside of C++.
+
+
+----------------------------------------------------------------
+v1.47 3rd December 2019
+----------------------------------------------------------------
+
+macOS
+* Updated steamcmd binaries to be 64-bit
+
+ISteamNetworkingSockets
+* Added API to set configuration options atomically, at time of creation of the listen socket or connection
+* Added API to send multiple messages efficiently, without copying the message payload
+* Added API for relayed P2P connections where signaling/rendezvous goes through your own custom backend instead of the Steam servers
+
+ISteamRemotePlay
+* Added a function to invite friends to play via Remote Play Together
+
+
+----------------------------------------------------------------
+v1.46 26th July 2019
+----------------------------------------------------------------
+
+ISteamRemotePlay
+* Added a new interface to get information about Steam Remote Play sessions
+
+ISteamInput
+* Added the GetRemotePlaySessionID function to find out whether a controller is associated with a Steam Remote Play session
+
+
+----------------------------------------------------------------
+v1.45 25th June 2019
+----------------------------------------------------------------
+
+Steam Input and Steam Controller Interfaces
+* Added the GetDeviceBindingRevision function which allows developers of Steam Input API games to detect out of date user configurations. Configurations w/ out of date major revisions should be automatically updated by Steam to the latest official configuration, but configurations w/ out of date minor revisions will be left in-place.
+
+ISteamUser
+* Add duration control APIs to support anti-indulgence regulations in some territories. This includes callbacks when gameplay time thresholds have been passed, and an API to fetch the same data on the fly.
+
+ISteamUtils
+* Add basic text filtering API.
+
+----------------------------------------------------------------
+v1.44 13th March 2019
+----------------------------------------------------------------
+
+ISteamNetworkingSockets
+* Socket-style API that relays traffic on the Valve network
+
+ISteamNetworkingUtils
+* Tools for instantly estimating ping time between two network hosts
+
+----------------------------------------------------------------
+v1.43 20th February 2019
+----------------------------------------------------------------
+
+ISteamParties
+* This API can be used to selectively advertise your multiplayer game session in a Steam chat room group. Tell Steam the number of player spots that are available for your party, and a join-game string, and it will show a beacon in the selected group and allow that many users to follow the beacon to your party. Adjust the number of open slots if other players join through alternate matchmaking methods.
+
+ISteamController
+* This interface will be deprecated and replaced with ISteamInput. For ease in upgrading the SDK ISteamController currently has feature parity with ISteamInput, but future features may not be ported back. Please use ISteamInput for new projects.
+* Added GetActionOriginFromXboxOrigin, GetStringForXboxOrigin and GetGlyphForXboxOrigin to allow Xinput games to easily query glyphs for devices coming in through Steam Inputs Xinput emulation, ex: A button->Cross button on a PS4 controller. This is a simple translation of the button and does not take user remapping into account the full action based API is required for that.
+* Added TranslateActionOrigin which allows Steam Input API games to which are using look up tables to translate action origins from an recognized device released after the game was last built into origins they recognize.
+* Added count and max_possible fields to current enums to make using lookup tables easier
+
+ISteamInput
+* This new interface replaces ISteamController to better reflect the fact this API supports not just the Steam Controller but every controller connected to Steam including Xbox Controllers, Playstation Controllers and Nintendo Switch controllers. ISteamController currently has feature parity with the new features added in ISteamInput but new feature may not be ported back. Please use this interface instead of ISteamController for any new projects.
+* Migrating to ISteamInput from ISteamController should mostly be a search-replace operation but any action origin look up tables will need to be adjusted as some of the enum orders have changed.
+* Added GetActionOriginFromXboxOrigin, GetStringForXboxOrigin and GetGlyphForXboxOrigin to allow Xinput games to easily query glyphs for devices coming in through Steam Inputs Xinput emulation, ex: A button->Cross button on a PS4 controller. This is a simple translation of the button and does not take user remapping into account the full action based API is required for that.
+* Added TranslateActionOrigin which allows Steam Input API games to which are using look up tables to translate action origins from an recognized device released after the game was last built into origins they recognize.
+* Added count and max_possible fields to current enums to make using lookup tables easier
+
+ISteamFriends
+* ActivateGameOverlayToWebPage Added a new parameter to control how the created web browser window is displayed within the Steam Overlay. The default mode will create a new browser tab next to all other overlay windows that the user already has open. The new modal mode will create a new browser window and activate the Steam Overlay, showing only that window. When the browser window is closed, the Steam Overlay is automatically closed as well.
+
+ISteamInventory
+* GetItemsWithPrices and GetItemPrice - Added the ability to get the base price for a set of items, which you can use to markup in your own UI that items are on sale
+
+ISteamUGC
+* SetAllowLegacyUpload - Call to force the use of Steam Cloud for back-end storage (instead of Steam Pipe), which is faster and more efficient for uploading and downloading small files (less than 100MB).
+* CreateQueryAllUGCRequest - Added ability to page through query results using a cursor instead of a page number. This is more efficient and supports deep paging beyond page 1000. The old version of CreateQueryAllUGCRequest() that takes a page parameter is deprecated and cannot query beyond page 1000. Note that you will need to keep track of the previous cursor in order to go to a previous page.
+
+ISteamApps
+* GetLaunchCommandLine - Get command line if game was launched via Steam URL, e.g. steam://run////. If you get NewUrlLaunchParameters_t callback while running, call again to get new command line
+* BIsSubscribedFromFamilySharing - Check if subscribed app is temporarily borrowed via Steam Family Sharing
+
+Steam API
+* Refactored headers to minimize the number of headers that need to be included to use a single ISteam interface.
+* Renamed some macros with STEAM_ prefix to minimize conflicts in the global namespace
+
+
+
+----------------------------------------------------------------
+v1.42 3rd January 2018
+----------------------------------------------------------------
+
+ISteamInventory
+* Added ability to start a purchase process through the Steam Client via the StartPurchase call and a given set of item definition ids and quantities. Users will be prompted in the Steam Client overlay to complete the purchase, including funding their Steam Wallet if necessary. Returns a SteamInventoryStartPurchaseResult_t call result if the user authorizes the purchase.
+* Added ability to retrieve item definition prices via the RequestPrices call. Once the call result SteamInventoryRequestPricesResult_t is returned, GetNumItemsWithPrices, GetItemsWithPrices, and GetItemPrice can be called to retrieve the item definition prices in the user's local currency.
+* Added ability to modify whitelisted per item dynamic properties. The usage pattern is to call StartUpdateProperties, SetProperty or RemoveProperty, and finally SubmitUpdateProperties. The SteamInventoryCallback_t will be fired with the appropriate result handle on success or failure.
+* Deprecated TradeItems
+
+ISteamController
+* Added Action Set Layers Action Set Layers are optional sets of action bindings which can be overlaid upon an existing set of controls. In contrast to Action Sets, layers draw their actions from the Action Set they exist within and do not wholesale replace what is already active when applied, but apply small modifications. These can consist of setting changes as well as adding or removing bindings from the base action set. More than one layer can be applied at a time and will be applied consecutively, so an example might be the Sniper Class layer which includes tweaks or bindings specific to snipers in addition to the Scoped-In layer which alters look sensitivity.
+* Added ActivateActionSetLayer Activates the specified Layer.
+* Added DeactivateActionSetLayer Deactivates the specified Layer.
+* Added DeactivateAllActionSetLayers Deactivates all layers, resetting the mapping to the action base Action Set.
+* Added GetActiveActionSetLayers Returns all currently active Action Set Layers.
+* Added GetInputTypeForHandle - Returns the input type for a particular handle, such as Steam Controller, PS4 Controller, Xbox One or 360.
+
+ISteamHTMLSurface
+* Added HTML_BrowserRestarted_t callback which is fired when the browser has restarted due to an internal failure
+
+ISteamFriends
+* Added IsClanPublic
+* Added IsClanOfficialGameGroup
+
+Steam API
+* Removed the ISteamUnifiedMessages interface. It is no longer intended for public usage.
+
+
+----------------------------------------------------------------
+v1.41 13th July 2017
+----------------------------------------------------------------
+
+ISteamClient
+* Exposed ISteamParentalSettings interface. You can use this to determine if the user has parental settings turned on and for what high-level Steam features.
+
+* ISteamHTMLSurface
+* Added SetDPIScalingFactor - Scale the output display space by this factor, this is useful when displaying content on high dpi devices.
+
+ISteamUGC
+* Added ability to mark a piece of UGC as requiring a set of DLC (AppID). These relationships are managed via new AddAppDependency, RemoveAppDependency, and GetAppDependencies calls.
+* Ported over ability to delete UGC from ISteamRemoteStorage and called it DeleteItem. Note that this does *not* prompt the user in any way.
+* Added m_nPublishedFileId to SubmitItemUpdateResult_t so that it is easier to keep track of what item was updated.
+
+
+----------------------------------------------------------------
+v1.40 25th April 2017
+----------------------------------------------------------------
+
+ISteamInventory
+* Update API documentation
+* GetResultItemProperty - Retrieve dynamic properties for a given item returned in the result set.
+
+ISteamUtils
+* IsVRHeadsetStreamingEnabled - Returns true if the HMD content will be streamed via Steam In-Home Streaming
+* SetVRHeadsetStreamingEnabled - Set whether the HMD content will be streamed via Steam In-Home Streaming
+
+ISteamUser
+* GetAvailableVoice and GetVoice - Some parameters have become deprecated and now have default values.
+
+ISteamUGC
+* SetReturnPlaytimeStats - Set the number of days of playtime stats to return for a piece of UGC.
+* AddDependency and RemoveDependency - Useful for parent-child relationship or dependency management
+
+ISteamVideo
+* Added GetOPFSettings and GetOPFStringForApp for retrieving Open Projection Format data used in Steam 360 Video playback.
+* GetOPFSettings - Handle the GetOPFSettingsResult_t callback which is called when the OPF related data for the passed in AppID is ready for retrieval.
+* GetOPFStringForApp - Using the AppID returned in GetOPFSettingsResult_t pass in an allocated string buffer to get the OPF data.
+
+SteamPipe GUI Tool
+* A simple GUI wrapper for Steamcmd/SteamPipe has been added to the SDK in the tools\ContentBuilder folder. More details can be found here: http://steamcommunity.com/groups/steamworks/discussions/0/412449508292646864
+
+
+----------------------------------------------------------------
+v1.39 6th January 2017
+----------------------------------------------------------------
+
+ISteamController
+
+The two new Origin helper functions in this interface allow you to query a description and a glyph for types of controllers and inputs that are in the current SDK header, but also any type of controller that might be supported by the Steam client in the future. To achieve this, pass origin values directly returned from Get*ActionOrigin() functions into GetStringForActionOrigin() and GetGlyphForActionOrigin() and display the results programmatically without checking against the range of the Origin enumerations.
+
+* TriggerVibration - Trigger a vibration event on supported controllers
+* SetLEDColor - Set the controller LED color on supported controllers
+* GetStringForActionOrigin - Returns a localized string (from Steam's language setting) for the specified origin
+* GetGlyphForActionOrigin - Get a local path to art for on-screen glyph for a particular origin
+* Updated Spacewar example to include example usage
+
+ISteamFriends
+* Removed k_EFriendFlagSuggested, since it was unused
+
+ISteamInventory
+* Updated and corrected documentation in the API
+* RequestEligiblePromoItemDefinitionsIDs - Request the list of "eligible" promo items that can be manually granted to the given user. These are promo items of type "manual" that won't be granted automatically. An example usage of this is an item that becomes available every week.
+* GetEligiblePromoItemDefinitionIDs - After handling a SteamInventoryEligiblePromoItemDefIDs_t call result, use this function to pull out the list of item definition ids that the user can be manually granted via the AddPromoItems() call.
+
+
+----------------------------------------------------------------
+v1.38 14th October 2016
+----------------------------------------------------------------
+
+ISteamUGC
+* Added ability to track the playtime of Workshop items. Call StartPlaytimeTracking() and StopPlaytimeTracking() when appropriate. On application shutdown all playtime tracking will stop, but StopPlaytimeTrackingForAllItems() can also be used.
+* Added ability to query Workshop items by total playtime in a given period, total lifetime playtime, average playtime in a given period, lifetime average playtime, number of play sessions in a given period, and number of lifetime play sessions.
+* Added ability to retrieve item statistics for number of seconds played, number of play sessions, and number of comments.
+* Added SetReturnOnlyIDs() for queries. This is useful for retrieving the list of items a user has subscribed to or favorited without having to get all the details for those items.
+* Modified GetQueryUGCStatistic() to take in a uint64 instead of a uint32 to support larger values
+
+ISteamUser
+* Added BIsPhoneIdentifying()
+* Added BIsPhoneRequiringVerification()
+
+ISteamScreenshots
+* Added IsScreenshotsHooked() if the application has hooked the screenshot
+* Added ability to add a VR screenshot that was saved to disk to the user's library
+
+ISteamRemoteStorage
+* Modified GetQuota() to take in uint64 from int32, since Steam Cloud can now support quotas above 2GB
+* Removed RemoteStorageConflictResolution_t callback
+
+ISteamApps
+* Added GetFileDetails() which will return FileDetailsResult_t through a call result. The FileDetailsResult_t struct contains information on the original file's size, SHA1, etc.
+
+ISteamFriends
+* Deprecated k_EFriendRelationshipSuggested relationship type that was originally used by Facebook linking feature
+
+----------------------------------------------------------------
+v1.37 23rd May 2016
+----------------------------------------------------------------
+
+Starting with this release, SDK forward-compatibility has been improved. All executables and libraries built using the official C++ headers from this SDK will continue to work even when paired with runtime DLLs from future SDKs. This will eventually allow for the mixing of dynamic libraries (such as third-party plug-ins) built with different versions of Steamworks.
+
+The VERSION_SAFE_STEAM_API_INTERFACES compile-time flag is no longer necessary for cross-version compatibility, and the SteamAPI_InitSafe and SteamGameServer_InitSafe functions have been removed. Applications which currently use these InitSafe functions should be changed to use the normal Init functions instead.
+
+
+ISteamRemoteStorage
+* Removed unsed UGCHandle_t m_hFile from RemoteStoragePublishedFileUpdated_t
+
+ISteamUGC
+* Added ability to add additional preview types to UGC such as standard images, YouTube videos, Sketchfab models, etc.
+
+ISteamUser
+* Added BIsPhoneVerified()
+* Added BIsTwoFactorEnabled()
+
+ISteamUtils
+* Added IsSteamInBigPictureMode()
+* Added StartVRDashboard(), which asks Steam to create and render the OpenVR Dashboard
+
+ISteamApps
+* Added RequestAllProofOfPurchaseKeys
+
+
+----------------------------------------------------------------
+v1.36 9th February 2016
+----------------------------------------------------------------
+
+ISteamController:
+* added new function TriggerRepeatedHapticPulse()
+
+
+Revision History:
+
+----------------------------------------------------------------
+v1.35 21st September 2015
+----------------------------------------------------------------
+
+ISteamController:
+ * The controller API has been redesigned to work with production Steam Controllers and take advantage of the configuration panel inside of Steam. The documentation on the partner site has a full overview of the new API.
+
+ISteamRemoteStorage:
+ * Added asynchronous file read and write methods. These methods will not block your calling thread for the duration of the disk IO. Additionally, the IO is performed in a worker thread in the Steam engine, so they will not impact other Steam API calls.
+ - FileWriteAsync: Similar in use to FileWrite, however it returns a SteamAPICall_t handle. Use the RemoteStorageFileWriteAsyncComplete_t structure with your asynchronous Steam API handler, and that will indicate the results of the write. The data buffer passed in to FileWriteAsync is immediately copied, so you do not have to ensure it is valid throughout the entire asynchronous process.
+ - FileReadAsync: This function queues an asynchronous read on the file specified, and also returns a SteamAPICall_t handle. The completion event uses the new RemoteStorageFileReadAsyncComplete_t structure. Upon successful completion, you can use the new FileReadAsyncComplete function to read the data -- passing in the original call handle, a pointer to a buffer for the data, and the amount to read (which generally should be equal to the amount read as specified by the callback structure, which generally will be equal to the amount requested). Additionally, the FileReadAsync function lets you specify an offset to read at, so it is no longer necessary to read the entire file in one call.
+
+
+----------------------------------------------------------------
+v1.34 28th July 2015
+----------------------------------------------------------------
+ISteamUGC:
+
+* Added ability to set and retrieve key-value tags on an item. There can be multiple values for each key.
+* Added ability to query all UGC that have matching key-value tags.
+* Added ability to specify a title and description on an item for a specific language (defaults to English).
+* Added ability to query for items and return the title and description in a preferred language.
+* Added ability to vote on an item and retrieve the current user's vote on a given item (duplicated from ISteamRemoteStorage).
+
+
+----------------------------------------------------------------
+v1.33 6th May 2015
+----------------------------------------------------------------
+
+UGC:
+* Added DownloadItem(), which will force download a piece of UGC (it will be cached based on usage). This can be used by stand-alone game servers.
+* Renamed GetItemUpdateInfo() => GetItemDownloadInfo() and added GetItemState() which can be used to determine whether an item is currently being downloaded, has already been downloaded, etc.
+* Added ability to set and retrieve developer metadata for an item
+* Added ability to modify a user's favorites list
+* Added ability to retrieve preview image & video URLs
+* Added ability to retrieve "children" for an item (e.g. for collections)
+* Added ability to retrieve stats, such as current number of subscribers, lifetime unique subscribers, etc.
+
+SteamVR
+* steamvr.h has been removed. You can use the OpenVR SDK to access those interfaces: https://github.com/ValveSoftware/openvr
+
+SteamVideo
+* Added ability to check if a user is currently broadcasting
+
+
+----------------------------------------------------------------
+v1.32 5th February 2015
+----------------------------------------------------------------
+
+General:
+* Added an auto-generated "flat" C-style API for common Steamworks features (steam_api_flat.h)
+* Added an auto-generated C# binding for common Steamworks features (steam_api_interop.cs)
+* Expanded the ISteamFriends interface to include steam levels and friends groups
+* Expanded the ISteamHTTP interface to include cookie handling, SSL certificate verification, and network timeouts
+* Fixed typos in ISteamHTMLSurface interface constants
+
+Inventory:
+* Added the initial version of ISteamInventory, a developer-preview release of our new Steam Inventory Service for managing and tracking a Steam-compatible inventory of in-game items. Please see the documentation for the Inventory Service on the partner website for more details.
+
+
+
+----------------------------------------------------------------
+v1.31 8th September 2014
+----------------------------------------------------------------
+
+UGC:
+* The Workshop item content API in ISteamUGC now supports legacy workshop items uploaded via the ISteamRemoteStorage interface. ISteamUGC::GetItemInstallInfo(). This will return whether the item was a legacy item or a new item. If it is a legacy item, then the pchFolder variable will be the full path to the file.
+
+HTML:
+* Added initial version of ISteamHTMLSurface API, which allows games to get textures for html pages and interact with them. There is also a sample implementation in the SteamworksExample.
+
+Virtual Reality:
+* Added VR_IsHmdPresent, which returns true if an HMD appears to be present but does not initialize the VR API. This is useful when enabling/disabling UI elements to offer VR mode to a user.
+* Added VR_GetStringForHmdError which turns an HmdError enum value into a string.
+
+SteamPipe
+* The example Steampipe batch file (run_build.bat) now uses run_app_build_http instead of run_app_build by default.
+
+ContentPrep.app
+* Updated wxPython requirements for this app (version 2.7 and 2.8 supported). App will prompt with updated URL to download compatible packages if necessary.
+
+
+
+----------------------------------------------------------------
+v1.30 10th July 2014
+----------------------------------------------------------------
+
+General:
+* Added a new Workshop item content API in ISteamUGC that is easy to use and allows multiple files per item without any size limits. It uses the same
+ content system that handles regular content depots, resulting in faster and smaller downloads due to delta patching. Subscribed workshop items will
+ be placed in unique subfolders in the install folder, so the game doesn't need to fetch them using ISteamRemoteStorage anymore. The new API is not
+ backwards compatible with old items created with ISteamRemoteStorage. Added Workshop feature to steamworksexample using ISteamUGC.
+
+
+Steam VR:
+* VR_Init now requires that you call SteamAPI_Init first.
+
+
+----------------------------------------------------------------
+v1.29 24th April 2014
+----------------------------------------------------------------
+
+General:
+* Adjust game server login to use a token instead of username/password. Tokens are randomly generated at account creation time and can be reset.
+* Added existing text param to ISteamUtils::ShowGamepadTextInput() so games can prepopulate control before displaying to user.
+* Updated retail disc installer to use a single multi-language steamsetup.exe replacing all Steam install MSI packages.
+* Removed redistributable Steam libraries for dedicated servers. Standalone dedicated server should use shared "Steamworks SDK Redist" depots.
+* steamcmd is now included for Linux and OSX.
+
+Music:
+* Introducing API to control the Steam Music Player from external software. As an example this gives games the opportunity to pause the music or lower the volume, when an important cut scene is shown, and start playing afterwards.
+* Added menu and code to the Steamworks Example to demonstrate this API.
+* This feature is currently limited to users in the Steam Music Player Beta. It will have no effect on other users.
+
+UGC:
+* ISteamUGC - Add m_bCachedData to SteamUGCQueryCompleted_t and SteamUGCRequestUGCDetailsResult_t which can be used to determine if the data was retrieved from the cache.
+* ISteamUGC - Allow clients to get cached responses for ISteamUGC queries. This is so client code doesn't have to build their own caching layer on top of ISteamUGC.
+* ISteamRemoteStorage - add the name of the shared file to RemoteStorageFileShareResult_t so it can be matched up to the request if a game has multiple outstanding FileShare requests going on at the same time
+
+Steam VR:
+* Renamed GetEyeMatrix to GetHeadFromEyePose and made it return an HmdMatrix34t. This doesn't actually change the values it was returning, it just updates the name to match the values that were already being returned. Changed the driver interface too.
+* Renamed GetWorldFromHeadPose to GetTrackerFromHeadPose to avoid confusion about the game's world space vs. the tracker's coordinate system.
+* Also renamed GetLastWorldFromHeadPose to GetLastTrackerFromHeadPose.
+* Added GetTrackerZeroPose method to get the tracker zero pose.
+* Added VR support to the Linux/SDL version of the Steamworks Example.
+
+----------------------------------------------------------------
+v1.28 28th January 2014
+----------------------------------------------------------------
+
+* Added Steamworks Virtual Reality API via steamvr.h.
+* Added ISteamUtils::IsSteamRunningInVRMode, which returns true if the Steam Client is running in VR mode.
+* Deprecated ISteamGameserver::GetGameplayStats and ISteamGameserver::GetServerReputation. These calls already return no data and will be removed in a future SDK update.
+* Added result code k_EResultRateLimitExceeded, which can now be returned if a user has too many outstanding friend requests.
+
+----------------------------------------------------------------
+v1.26a 14th November 2013
+----------------------------------------------------------------
+
+* Fix missing accessor function in steam_api.h for SteamUGC()
+
+----------------------------------------------------------------
+v1.26 6th November 2013
+----------------------------------------------------------------
+* Includes libsteam_api.so for 64-bit Linux.
+* Callbacks ValidateAuthTicketResponse_t and GSClientApprove_t now contain the SteamID of the owner of current game. If the game is borrowed, this is different than the player's SteamID.
+* Added ISteamFriends::GetPlayerNickname, which returns the nickname the current user has set for the specified player.
+* Fix p2p networking apis on Linux so they work with dedicated servers
+* Fix command line argument handling bug in SteamAPI_RestartAppIfNecessary on Linux and OSX.
+* Added ISteamApps::GetLaunchQueryParam, which will get the value associated with the given key if a game is launched via a url with query paramaters, such as steam://run///?param1=value1;param2=value2;param3=value3. If the game is already running when such a url is executed, instead it will receive a NewLaunchQueryParameters_t callback.
+* Added EUGCReadAction parameter to ISteamRemoteStorage:UGCRead that allows the game to keep the file open if it needs to seek around the file for arbitrary data, rather than always closing the file when the last byte is read.
+* Added new ISteamUGC interface that is used for querying for lists of UGC details (e.g. Workshop items, screenshots, videos, artwork, guides, etc.). The ISteamUGC interface should be used instead of ISteamRemoteStorage, which contains similar, but less flexible and powerful functionality.
+* Removed tools for deprecated content system
+
+
+----------------------------------------------------------------
+v1.25 1st October 2013
+----------------------------------------------------------------
+* Fixed a crash in the 1.24 SDK update when attempting to call ISteamRemoteStorage::GetPublishedFileDetails by adding a missing parameter unMaxSecondsOld, which allows a game to request potentially-cached details (passing a value of 0 retains the previous behavior).
+
+----------------------------------------------------------------
+v1.24 17th July 2013
+----------------------------------------------------------------
+
+User:
+* Added ISteamUser::GetBadgeLevel and ISteamUser::GetPlayerSteamLevel functions
+
+Friends:
+* Games can now initiate Steam Friend requests, removals, request -accepts and request-ignores via ISteamFriends ActivateGameOverlayToUser API. This prompts the user for confirmation before action is taken.
+
+Mac:
+* Updated the OS X Content Prep tool and game wrapper for improved compatibility with OS X 10.8 (Mountain Lion).
+
+Linux:
+* Added install script for the Steam Linux Runtime tools (run "bash tools/linux/setup.sh" to install), see tools/linux/README.txt for details.
+* SteamworksExample is now available on Linux
+
+----------------------------------------------------------------
+v1.23a 25th February 2013
+----------------------------------------------------------------
+
+Windows:
+* Fix passing command-line parameters across SteamApi_RestartAppIfNeccessary()
+
+----------------------------------------------------------------
+v1.23 19th February 2013
+----------------------------------------------------------------
+
+Cloud:
+* Added ISteamScreenshots::TagPublishedFile() which allows tagging workshop content that is visible or active when a screenshot is taken.
+* Added ISteamRemoteStorage::UGCDownloadToLocation() which allows a developer to specify a location on disk to download workshop content.
+
+Setup tool:
+* Added Arabic to the supported languages for the PC Gold Master Setup Tool
+* Fixed regression in localized EULA support in Mac OS X Gold Master Setup Tool
+
+Windows:
+* Fix SteamAPI_RestartAppIfNecessary() on 64 bit Windows
+* When launching a game's development build from outside of Steam, fixed using steam_appid.txt in the Steam Overlay and for authorizing microtransactions (broken in the SDK 1.22)
+
+Mac:
+* Fixed many Steam callbacks not working for 64 bit OS X games due to mismatched structure alignment between the SDK and the Steam client
+* Implemented SteamAPI_RestartAppIfNecessary()
+
+Linux:
+* Removed the need to redistribute libtier0_s.so and libvstdlib_s.so
+* Fixed finding and loading steamclient.so, so LD_LIBRARY_PATH does not need to be set for game to talk with Steam
+* Implemented SteamAPI_RestartAppIfNecessary()
+
+
+----------------------------------------------------------------
+v1.22 12th December 2012
+----------------------------------------------------------------
+
+Apps
+* Added new API call ISteamApps::MarkContentCorrupt() so a game can hint Steam that some of it's local content seems corrupt. Steam will verify the content next time the game is started.
+* Added new API call ISteamApps::GetCurrentBetaName() so a game can get the current content beta branch name if the user chose to opt-in to a content beta.
+
+Cloud
+* Added an offset parameter to ISteamRemoteStorage::UGCRead() to allow reading files in chunks, and increased the limit from 100MB to 200MB when downloading files this way.
+
+HTTP
+* Added support for streaming HTTP requests with ISteamHTTP::SendHTTPRequestAndStreamResponse() and ISteamHTTP::GetHTTPStreamingResponseBodyData()
+
+Linux
+* Updated libsteam_api.so to find Steam in its new install location
+
+
+----------------------------------------------------------------
+v1.21 25th October 2012
+----------------------------------------------------------------
+
+Big Picture
+* Added ISteamUtils::ShowGamepadTextInput() to enable usage of the Big Picture gamepad text input control in-game. UI is rendered by the Steam Overlay.
+* Added ISteamUtils::GetEnteredGamepadTextLength() and ISteamUtils::GetEnteredGamepadTextInput() to retrieve entered gamepad text.
+* Added GamepadTextInputDismissed_t callback to detect when the user has entered gamepad data.
+
+
+----------------------------------------------------------------
+v1.20 30th August 2012
+----------------------------------------------------------------
+
+SteamPipe
+* Added local server and builder tools for new content system.
+
+Mac
+* OSX Supports 64 bit build targets.
+* Spacewar has been updated to be buildable as a 64 bit OSX sample application.
+
+Friends
+* Added a callback for the result of ISteamFriends::SetPersonaName().
+* Changed ISteamFriends::ActivateGameOverlayToStore() to take an additional parameter so app can be directly added to the cart.
+
+Cloud
+* Added ISteamRemoteStorage::FileWriteStreamOpen(), FileWriteStreamWriteChunk(), FileWriteStreamClose() and FileWriteStreamCancel() for streaming operations.
+* Changed parameters to ISteamRemoteStorage::PublisheVideo().
+* Added file type to ISteamRemoteStorage::GetPublishedFileDetails() callback result (RemoteStorageGetPublishedFileDetailsResult_t).
+* Added a callback to indicate that a published file that a user owns was deleted (RemoteStoragePublishedFileDeleted_t).
+
+ISteamUserStats
+* Added ISteamUserStats::GetNumAchievements() and ISteamUserStats::GetAchievementName().
+
+
+----------------------------------------------------------------
+v1.19 22nd March 2012
+----------------------------------------------------------------
+
+Friends
+* Added ISteamFriends::GetFollowerCount()
+* Added ISteamFriends::IsFollowing()
+* Added ISteamFriends::EnumerateFollowingList()
+
+Cloud
+* Added ISteamRemoteStorage::UpdatePublishedFileSetChangeDescription()
+* Added ISteamRemoteStorage::GetPublishedItemVoteDetails()
+* Added ISteamRemoteStorage::UpdateUserPublishedItemVote()
+* Added ISteamRemoteStorage::GetUserPublishedItemVoteDetails()
+* Added ISteamRemoteStorage::EnumerateUserSharedWorkshopFiles()
+* Added ISteamRemoteStorage::PublishVideo()
+* Added ISteamRemoteStorage::SetUserPublishedFileAction()
+* Added ISteamRemoteStorage::EnumeratePublishedFilesByUserAction()
+* Added ISteamRemoteStorage::EnumeratePublishedWorkshopFiles()
+
+ISteamGameServer
+* Updated callback for SteamGameServer::ComputeNewPlayerCompatibility to include the steam id the compatibility was calculated for
+
+
+----------------------------------------------------------------
+v1.18 7th February 2012
+----------------------------------------------------------------
+
+Cloud
+* Removed ISteamRemoteStorage::PublishFile() and consolidated the API to PublishWorkshopFile()
+* Updated ISteamRemoteStorage::PublishWorkshopFile() to better define the type of workshop file being published
+* Replaced ISteamRemoteStorage::UpdatePublishedFile() with a new mechanism to update existing files through CreatePublishedFileUpdateRequest() UpdatePublishedFile[Property](), and CommitPublishedFileUpdate()
+* Increased the description field for a workshop file from 256 -> 8000 characters
+* Added ISteamRemoteStorage::GetUGCDownloadProgress()
+* Added file size limit of 100MB to ISteamRemoteStorage::FileWrite()
+
+Apps:
+* Added ISteamApps::RequestAppProofOfPurchaseKey
+
+----------------------------------------------------------------
+v1.17 2nd November 2011
+----------------------------------------------------------------
+
+Cloud
+* Added ISteamRemoteStorage::PublishFile(), PublishWorkshopFile(), UpdatePublishedFile(), DeletePublishedFile() which enables sharing, updating, and unsharing of cloud content with the Steam community
+* Added ISteamRemoteStorage::EnumerateUserPublishedFiles to enumerate content that a user has shared with the Steam community
+* Added ISteamRemoteStorage::GetPublishedFileDetails() which gets the metadata associated with a piece of community shared content
+* Added ISteamRemoteStorage::SubscribePublishedFile(), EnumerateUserSubscribedFiles(), and UnsubscribePublishedFiles() which allow for management of community content that a user is interested in and marked as a favorite
+
+User
+* Updated ISteamUser::GetAuthSessionTicket(), When creating a ticket for use by the AuthenticateUserTicket Web API, the calling application should wait for the callback GetAuthSessionTicketResponse_t generated by the API call before attempting to use the ticket to ensure that the ticket has been communicated to the server. If this callback does not come in a timely fashion ( 10 - 20 seconds ), your client is not connected to Steam, and the AuthenticeUserTicket will fail because it can not authenticate the user.
+
+Friends
+* Added ISteamFriends::RequestFriendRichPresence, which allows requesting rich presence keys for any Steam user playing the same game as you
+* Added a set of functions to ISteamFriends which allow games to integrate with Steam Chat. Games can both join group chats, as well as get friends chats and show them in-line in the game. This API isnt currently used in a game, so there may be some rough edges around the user experience to work out, and some experimentation is required.
+
+Game Servers
+* Removed the ISteamMasterServerUpdater interface. It has been merged into the ISteamGameServer interface, which is used to communicate all game server state changes.
+* Significant changes to the game server init sequence. (See the comments for SteamGameServer_Init and the ISteamGameServer interface.)
+* Removed interface to legacy master server mode
+* Groundwork for implementing named steam accounts for game servers
+* Old player auth system is deprecated. It may be removed in a future version of the SDK.
+
+Tools
+* Added tool for automated DRM submissions in /sdk/tools/drm/
+
+----------------------------------------------------------------
+v1.16 29th July 2011
+----------------------------------------------------------------
+
+HTTP
+* added ISteamHTTP::SetHTTPRequestRawPostBody() to set the raw body of a POST request
+Screenshots
+* added ISteamScreenshots interface, which enables adding screenshots to the user's screenshot library and tagging them with location data or relevant players that are visible in the screenshot. A game can provide screenshots based on game events using WriteScreenshot, AddScreenshotToLibrary, or TriggerScreenshot. A game can also choose to provide its own screenshots when the Steam screenshot hotkey is pressed by calling HookScreenshots() and listening for the ScreenshotRequested_t callback.
+
+----------------------------------------------------------------
+v1.15 1st June 2011
+----------------------------------------------------------------
+
+Bug fixes
+* Fixed exposing HTTP interface
+* Fixed setting AppID for game processes started outside of Steam or which require administrative privileges
+
+
+----------------------------------------------------------------
+v1.14 16th May 2011
+----------------------------------------------------------------
+
+Stats and Achievements
+* Added a set of functions for accessing global achievement unlock percentages
+** RequestGlobalAchievementPercentages() to request the completion percentages from the backend
+** GetMostAchievedAchievementInfo() and GetNextMostAchievedAchievementInfo() to iterate achievement completion percentages
+** GetAchievementAchievedPercent() to query the global unlock percentage for a specific achievement
+* Added a set of functions for accessing global stats values. To enable a global stats set stats as "aggregated" from the Steamworks admin page.
+** RequestGlobalStats() to request the global stats data from the backend
+** GetGlobalStat() to get the global total for a stat
+** GetGlobalStatHistory() to get per day totals for a stat
+
+HTTP
+* added ISteamHTTP::GetHTTPDownloadProgressPct() get the progress of an HTTP request
+
+
+----------------------------------------------------------------
+v1.13 26th April 2011
+----------------------------------------------------------------
+
+Rich Presence
+* added a new Rich Presence system to allow for sharing game specific per user data between users
+* ISteamFriends::SetRichPresense() can be used to set key/value presence data for the current user
+* ISteamFriends::GetFriendRichPresence() and related functions can be used to retrieve presence data for a particular user
+* Two special presence keys exist:
+** the "connect" key can be set to specify a custom command line used by friends when joining that user
+** the "status" key can be set to specify custom text that will show up in the 'view game info' dialog in the Steam friends list
+
+HTTP
+* added ISteamHTTP, which exposes methods for making HTTP requests
+
+Downloadable Content
+* added ISteamApps::GetDLCCount() and ISteamApps::BGetDLCDataByIndex() to allow for enumerating DLC content for the current title
+* added ISteamApps::InstallDLC() and ISteamApps::UninstallDLC() to control installing optional content
+
+P2P Networking
+* added ISteamNetworking::CloseP2PChannelWithUser(), to allow for closing a single channel to a user. When all channels are closed, the connection to that user is automatically closed.
+* added ISteamNetworking::AllowP2PPacketRelay(), which can be used to prevent allowing P2P connections from falling back to relay
+
+Voice
+* ISteamUser::GetAvailableVoice() & ISteamUser::GetVoice() now take the desired sample rate to determine the number of uncompressed bytes to return
+* added ISteamUser::GetVoiceOptimalSampleRate() to return the frequency of the voice data as it's stored internally
+
+Friends
+* added ISteamFriends methods to retrieve the list of users the player has recently played with
+
+Content Tool
+* all files are now encrypted by default
+* add command line option to app creation wizard
+* add command line edit option by right clicking on app
+* update cache size in CDDB after each build
+* look for install scripts at build time and automatically add CDDB flag
+* fix language names for chinese
+* add menu button to easily rev version
+* warn if rebuilding existing version
+* allow specifying subfolder when ftp-ing depots to valve
+* better error messaging if ftp fails
+* clean up various small display bugs
+* don't trash ValidOSList tag when updating CDDB
+
+OSX DirectX to OpenGL
+* added the graphics layer used to port Valve games to OSX which can now be used by all Steamworks developers
+* included in the Steamworks Example application. Can be enabled by building with DX9MODE=1
+
+
+----------------------------------------------------------------
+v1.12 10th November 2010
+----------------------------------------------------------------
+
+Cloud
+* added a set of function to handle publishing User Generated Content (UGC) files to the backend, and to download others users UGC files. This enables games to have users easily publish & share content with each other.
+* Added ISteamRemoteStorage::FileForget() which tells a file to remain on disk but to be removed from the backend. This can be used to manage which files should be synchronized if you have more files to store than your quota allows.
+* Added ISteamRemoteStorage::FilePersisted() to tell if the file is set to be synchronized with the backend.
+* Added ISteamRemoteStorage::FileDelete() which tells a file to be deleted locally, from cloud, and from other clients that have the file. This can be used to properly delete a save file rather than writing a 1-byte file as a sentinel.
+* Added ISteamRemoteStorage::SetSyncPlatforms(), GetSyncPlatforms() to tell steam which platforms a file should be synchronized to. This allows OSX not to download PC-specific files, or vice-versa.
+* Added ISteamRemoteStorage::IsCloudEnabledForAccount(), IsCloudEnabledForApp(), and SetCloudEnabledForApp(). When cloud is disabled the APIs still work as normal and an alternate location on disk is not needed. It just means the files will not be synchronized with the backend.
+
+Leaderboards
+* added ISteamUserStats::DownloadLeaderboardEntriesForUsers(), which downloads scores for an arbitrary set of users
+* added ISteamUserStats::AttachLeaderboardUGC(), to attach a clouded file to a leaderboard entry
+
+Friends
+* added ISteamFriends::RequestUserInformation(), to asynchronously request a users persona name & avatar by steamID
+* added ISteamFriends::RequestClanOfficerList(), to asynchronously download the set of officers for a clan. GetClanOwner(), GetClanOfficerCount(), and GetClanOfficerByIndex() can then be used to access the data.
+
+Matchmaking
+* added k_ELobbyTypePrivate option to creating lobbies - this means that the lobby won't show up to friends or be returned in searches
+* added LobbyDataUpdate_t::m_bSuccess, to easily check if a RequestLobbyData() call failed to find the specified lobby
+
+Authentication
+* added ISteamApps::GetEarliestPurchaseUnixTime(), for games that want to reward users who have played for a long time
+* added ISteamApps::BIsSubscribedFromFreeWeekend(), so games can show different offers or information for users who currently only have rights to play the game due to a free weekend promotion
+* added ISteamGameServer::GetAuthSessionTicket(), BeginAuthSession(), EndAuthSession(), and CancelAuthTicket(), matching what exists in ISteamUser. This allows game servers and clients to authenticate each other in a unified manner.
+
+OSX
+* The Steamworks Spacewar example now builds/runs on OS X
+* The OSX retail install setup application is now contained in goldmaster\disk_assets\SteamRetailInstaller.dmg
+
+PS3
+* added several functions regarding PS3 support. This is still a work in progress, and no PS3 binaries are included.
+
+
+----------------------------------------------------------------
+v1.11 23rd August 2010
+----------------------------------------------------------------
+
+Networking
+* added virtual ports to the P2P networking API to help with routing messages to different systems
+* added ISteamUser::BIsBehindNAT() to detect when a user is behind a NAT
+
+Friends / Matchmaking
+* added support for retrieving large (184x184) avatars
+* added ISteamUser::AdvertiseGame() which can be used send join game info to friends without using the game server APIs
+
+64-bit support
+* 64-bit windows binaries are included in the sdk/redistributable_bin/ folder
+* VAC and CEG are not yet supported
+
+Authentication
+* added ticket based remote authentication library
+
+Other
+* added ISteamUser::CheckFileSignature which can be used in conjunction with the signing tab on the partner site to verify that an executable has not been modified
+
+
+----------------------------------------------------------------
+v1.10 20th July 2010
+----------------------------------------------------------------
+
+Friends / Matchmaking
+* added function ISteamFriends::GetClanTag(), which returns the abbreviation set for a group
+* added "stats" and "achievements" options to ISteamFriends::ActivateGameOverlayToUser()
+* added function ISteamFriends::ActivateGameOverlayInviteDialog() to open the invite dialog for a specific lobby
+* renamed ISteamMatchmaking::SetGameType() to the more correct SetGameTags()
+
+Authentication
+* added ISteamUtils::CheckFileSignature(), which can be used to verify that a binary has a valid signature
+
+Other
+* added #pragma pack() in several places around structures in headers
+
+
+----------------------------------------------------------------
+v1.09 12th May 2010
+----------------------------------------------------------------
+
+Mac Steamworks!
+* new binaries in the sdk/redistributable_bin/osx/ folder
+
+Other
+* explicit pragma( pack, 8 ) added around all callbacks and structures, for devs who have use a different default packing
+* renamed function ISteamGameServer::SetGameType() to the more accurate ISteamGameServer::SetGameTags()
+
+
+----------------------------------------------------------------
+v1.08 27st January 2010
+----------------------------------------------------------------
+
+Matchmaking
+* added function ISteamMatching::AddRequestLobbyListDistanceFilter(), to specify how far geographically you want to search for other lobbies
+* added function ISteamMatching::AddRequestLobbyListResultCountFilter(), to specify how the maximum number of lobby you results you need (less is faster)
+
+Stats & Achievements
+* added interface ISteamGameServerStats, which enables access to stats and achievements for users to the game server
+* removed function ISteamGameServer::BGetUserAchievementStatus(), now handled by ISteamGameServerStats
+* added ISteamUserStats::GetAchievementAndUnlockTime(), which returns if and when a user unlocked an achievement
+
+Other
+* added new constant k_cwchPersonaNameMax (32), which is the maximum number of unicode characters a users name can be
+* removed ISteamRemoteStorage::FileDelete() - NOTE: it will be back, it's only removed since it hadn't been implemented on the back-end yet
+* added function ISteamGameServer::GetServerReputation(), gives returns a game server reputation score based on how long users typically play on the server
+
+
+----------------------------------------------------------------
+v1.07 16th December 2009
+----------------------------------------------------------------
+
+* Replaced SteamAPI_RestartApp() with SteamAPI_RestartAppIfNecessary(). This new function detects if the process was started through Steam, and starts the current game through Steam if necessary.
+* Added ISteamUtils::BOverlayNeedsPresent() so games with event driven rendering can determine when the Steam overlay needs to draw
+
+
+----------------------------------------------------------------
+v1.06 30th September 2009
+----------------------------------------------------------------
+
+Voice
+* ISteamUser::GetCompressedVoice() has been replaced with ISteamUser::GetVoice which can be used to retrieve compressed and uncompressed voice data
+* Added ISteamUser::GetAvailableVoice() to retrieve the amount of captured audio data that is available
+
+Matchmaking
+* Added a new callback LobbyKicked_t that is sent when a user has been disconnected from a lobby
+* Through ISteamMatchmakingServers, multiple server list requests of the same type can now be outstanding at the same time
+
+Steamworks Setup Application:
+* Streamlined configuration process
+* Now supports EULAs greater than 32k bytes
+
+Content Tool
+* Added DLC checkbox to depot creation wizard
+
+Other
+* Added SteamAPI_IsSteamRunning()
+* Added SteamAPI_RestartApp() so CEG users can restart their game through Steam if launched through Windows Games Explorer
+
+
+
+----------------------------------------------------------------
+v1.05 11th June 2009
+----------------------------------------------------------------
+
+Matchmaking
+* Added the SteamID of the gameserver to the gameserveritem_t structure (returned only by newer game servers)
+* Added ISteamUserStats::GetNumberOfCurrentPlayers(), asyncronously returns the number users currently running this game
+* Added k_ELobbyComparisonNotEqual comparision functions for filters
+* Added option to use comparison functions for string filters
+* Added ISteamMatchmaking::AddRequestLobbyListFilterSlotsAvailable( int nSlotsAvailable ) filter function, so you can find a lobby for a group of users to join
+* Extended ISteamMatchmaking::CreateLobby() to take the max number of users in the lobby
+* Added ISteamMatchmaking::GetLobbyDataCount(), ISteamMatchmaking::GetLobbyDataByIndex() so you can iterate all the data set on a lobby
+* Added ISteamMatchmaking::DeleteLobbyData() so you can clear a key from a lobby
+* Added ISteamMatchmaking::SetLobbyOwner() so that ownership of a lobby can be transferred
+* Added ISteamMatchmaking::SetLobbyJoinable()
+* Added ISteamGameServer::SetGameData(), so game server can set more information that can be filtered for in the server pinging API
+
+Networking
+* Added a set of connectionless networking functions for easy use for making peer-to-peer (NAT traversal) connections. Includes supports for windowed reliable sendsand fragementation/re-assembly of large packets. See ISteamNetworking.h for more details.
+
+Leaderboards
+* Added enum ELeaderboardUploadScoreMethod and changed ISteamUserStats::UploadLeaderboardScore() to take this - lets you force a score to be changed even if it's worse than the prior score
+
+Callbacks
+* Added CCallbackManual<> class to steam_api.h, a version of CCallback<> that doesn't register itself automatically in it's the constructor
+
+Downloadable Content
+* Added ISteamUser::UserHasLicenseForApp() and ISteamGameServer::UserHasLicenseForApp() to enable checking if a user owns DLC in multiplayer. See the DLC documentation for more info.
+
+Game Overlay
+* ISteamFriends::ActivateGameOverlay() now accepts "Stats" and "Achievements"
+
+
+
+----------------------------------------------------------------
+v1.04 9th Mar 2009
+----------------------------------------------------------------
+
+Added Peer To Peer Multi-Player Authentication/Authorization:
+* Allows each peer to verify the unique identity of the peers ( by steam account id ) in their game and determine if that user is allowed access to the game.
+* Added to the ISteamUser interface: GetAuthSessionTicket(), BeginAuthSession(), EndAuthSession() and CancelAuthTicket()
+* Additional information can be found in the API Overview on the Steamworks site
+
+Added support for purchasing downloadable content in game:
+* Added ISteamApps::BIsDlcInstalled() and the DlcInstalled_t callback, which enable a game to check if downloadable content is owned and installed
+* Added ISteamFriends::ActivateGameOverlayToStore(), which opens the Steam game overlay to the store page for an appID (can be a game or DLC)
+
+Gold Master Creation:
+* It is no longer optional to encrypt depots on a GM
+* The GM configuration file now supports an included_depots key, which along with the excluded_depots key, allows you to specify exactly which depots are placed on a GM
+* Simplified the configuration process for the setup application
+* The documentation for creating a Gold Master has been rewritten and extended. See the Steamworks site for more information.
+
+Added Leaderboards:
+* 10k+ leaderboards can now be created programmatically per game, and queried globally or compared to friends
+* Added to ISteamUserStats interface
+* See SteamworksExample for a usage example
+
+Other:
+* Added SteamShutdown_t callback, which will alert the game when Steam wants to shut down
+* Added ISteamUtils::IsOverlayEnabled(), which can be used to detect if the user has disabled the overlay in the Steam settings
+* Added ISteamUserStats::ResetAllStats(), which can be used to reset all stats (and optionally achievements) for a user
+* Moved SetWarningMessageHook() from ISteamClient to ISteamUtils
+* Added SteamAPI_SetTryCatchCallbacks, sets whether or not Steam_RunCallbacks() should do a try {} catch (...) {} around calls to issuing callbacks
+* In CCallResult callback, CCallResult::IsActive() will return false and can now reset the CCallResult
+* Added support for zero-size depots
+* Properly strip illegal characters from depot names
+
+
+
+----------------------------------------------------------------
+v1.03 16th Jan 2009
+----------------------------------------------------------------
+
+Major changes:
+* ISteamRemoteStorage interface has been added, which contains functions to store per-user data in the Steam Cloud back-end.
+** To use this, you must first use the partner web site to enable Cloud for your game.
+** The current setting is allowing 1MB of storage per-game per-user (we hope to increase this over time).
+
+Lobby & Matchmaking related changes:
+* ISteamFriends::GetFriendGamePlayed() now also return the steamID of the lobby the friend is in, if any. It now takes a pointer to a new FriendGameInfo_t struct, which it fills
+* Removed ISteamFriends::GetFriendsLobbies(), since this is now redundant to ISteamFriends::GetFriendGamePlayed()
+* Added enum ELobbyComparison, to set the comparison operator in ISteamMatchmaking::AddRequestLobbyListNumericalFilter()
+* Changed ISteamMatchmaking::CreateLobby(), JoinLobby() and RequestLobbyList() to now return SteamAPICall_t handles, so you can easily track if a particular call has completed (see below)
+* Added ISteamMatchmaking::SetLobbyType(), which can switch a lobby between searchable (public) and friends-only
+* Added ISteamMatchmaking::GetLobbyOwner(), which returns the steamID of the user who is currently the owner of the lobby. The back-end ensures that one and only one user is ever the owner. If that user leaves the lobby, another user will become the owner.
+
+Steam game-overlay interaction:
+* Added a new callback GameLobbyJoinRequested_t, which is sent to the game if the user selects 'Join friends game' from the Steam friends list, and that friend is in a lobby. The game should initiate connection to that lobby.
+* Changed ISteamFriends::ActivateGameOverlay() can now go to "Friends", "Community", "Players", "Settings", "LobbyInvite", "OfficialGameGroup"
+* Added ISteamFriends::ActivateGameOverlayToUser(), which can open a either a chat dialog or another users Steam community profile
+* Added ISteamFriends::ActivateGameOverlayToWebPage(), which opens the Steam game-overlay web browser to the specified url
+
+Stats system changes:
+* Added ISteamUserStats::RequestUserStats(), to download the current game stats of another user
+* Added ISteamUserStats::GetUserStat() and ISteamUserStats::GetUserAchievement() to access the other users stats, once they've been downloaded
+
+Callback system changes:
+* Added new method for handling asynchronous call results, currently used by CreateLobby(), JoinLobby(), RequestLobbyList(), and RequestUserStats(). Each of these functions returns a handle, SteamAPICall_t, that can be used to track the completion state of a call.
+* Added new object CCallResult<>, which can map the completion of a SteamAPICall_t to a function, and include the right data. See SteamworksExample for a usage example.
+* Added ISteamUtils::IsAPICallCompleted(), GetAPICallFailureReason(), and GetAPICallResult(), which can be used to track the state of a SteamAPICall_t (although it is recommended to use CCallResult<>, which wraps these up nicely)
+
+Other:
+* Added ISteamGameServer::GetPublicIP(), which is the IP address of a game server as seen by the Steam back-end
+* Added "allow relay" parameter to ISteamNetworking::CreateP2PConnectionSocket() and CreateListenSocket(), which specified if being bounced through Steam relay servers is OK if a direct p2p connection fails (will have a much higher latency, but increases chance of making a connection)
+* Added IPCFailure_t callback, which will be posted to the game if Steam itself has crashed, or if Steam_RunCallbacks() hasn't been called in a long time
+
+
+
+----------------------------------------------------------------
+v1.02 4th Sep 2008
+----------------------------------------------------------------
+
+The following interfaces have been updated:
+
+ISteamUser
+
+ // Starts voice recording. Once started, use GetCompressedVoice() to get the data
+ virtual void StartVoiceRecording( ) = 0;
+
+ // Stops voice recording. Because people often release push-to-talk keys early, the system will keep recording for
+ // a little bit after this function is called. GetCompressedVoice() should continue to be called until it returns
+ // k_eVoiceResultNotRecording
+ virtual void StopVoiceRecording( ) = 0;
+
+ // Gets the latest voice data. It should be called as often as possible once recording has started.
+ // nBytesWritten is set to the number of bytes written to pDestBuffer.
+ virtual EVoiceResult GetCompressedVoice( void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten ) = 0;
+
+ // Decompresses a chunk of data produced by GetCompressedVoice(). nBytesWritten is set to the
+ // number of bytes written to pDestBuffer. The output format of the data is 16-bit signed at
+ // 11025 samples per second.
+ virtual EVoiceResult DecompressVoice( void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten ) = 0;
+
+virtual int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure ) = 0;
+
+This has been extended to be usable for games that don't use the other parts of Steamworks matchmaking. This allows any multiplayer game to easily notify the Steam client of the IP:Port of the game server the user is connected to, so that their friends can join them via the Steam friends list. Empty values are taken for auth blob.
+
+ virtual bool GetUserDataFolder( char *pchBuffer, int cubBuffer ) = 0;
+
+This function returns a hint as a good place to store per- user per-game data.
+
+
+
+ISteamMatchmaking
+
+Added a set of server-side lobby filters, as well as voice chat, lobby member limits, and a way of quickly accessing the list of lobbies a users friends are in.
+
+ // filters for lobbies
+ // this needs to be called before RequestLobbyList() to take effect
+ // these are cleared on each call to RequestLobbyList()
+ virtual void AddRequestLobbyListFilter( const char *pchKeyToMatch, const char *pchValueToMatch ) = 0;
+ // numerical comparison - 0 is equal, -1 is the lobby value is less than nValueToMatch, 1 is the lobby value is greater than nValueToMatch
+ virtual void AddRequestLobbyListNumericalFilter( const char *pchKeyToMatch, int nValueToMatch, int nComparisonType /* 0 is equal, -1 is less than, 1 is greater than */ ) = 0;
+ // sets RequestLobbyList() to only returns lobbies which aren't yet full - needs SetLobbyMemberLimit() called on the lobby to set an initial limit
+ virtual void AddRequestLobbyListSlotsAvailableFilter() = 0;
+
+ // returns the details of a game server set in a lobby - returns false if there is no game server set, or that lobby doesn't exist
+ virtual bool GetLobbyGameServer( CSteamID steamIDLobby, uint32 *punGameServerIP, uint16 *punGameServerPort, CSteamID *psteamIDGameServer ) = 0;
+
+ // set the limit on the # of users who can join the lobby
+ virtual bool SetLobbyMemberLimit( CSteamID steamIDLobby, int cMaxMembers ) = 0;
+ // returns the current limit on the # of users who can join the lobby; returns 0 if no limit is defined
+ virtual int GetLobbyMemberLimit( CSteamID steamIDLobby ) = 0;
+
+ // asks the Steam servers for a list of lobbies that friends are in
+ // returns results by posting one RequestFriendsLobbiesResponse_t callback per friend/lobby pair
+ // if no friends are in lobbies, RequestFriendsLobbiesResponse_t will be posted but with 0 results
+ // filters don't apply to lobbies (currently)
+ virtual bool RequestFriendsLobbies() = 0;
+
+
+ISteamUtils
+ // Sets the position where the overlay instance for the currently calling game should show notifications.
+ // This position is per-game and if this function is called from outside of a game context it will do nothing.
+ virtual void SetOverlayNotificationPosition( ENotificationPosition eNotificationPosition ) = 0;
+
+
+ISteamFriends
+ virtual int GetFriendAvatar( CSteamID steamIDFriend, int eAvatarSize ) = 0;
+
+This function now takes an eAvatarSize parameter, which can be k_EAvatarSize32x32 or k_EAvatarSize64x64 (previously it always just returned a handle to the 32x32 image)
+
+
+----------------------------------------------------------------
+v1.01 8th Aug 2008
+----------------------------------------------------------------
+
+The Steamworks SDK has been updated to simplfy game server authentication and better expose application state
+
+
+----------------------------------------------------------------
+v1.0:
+----------------------------------------------------------------
+
+- Initial Steamworks SDK release
diff --git a/My project/sdk/glmgr/cglmbuffer.cpp b/My project/sdk/glmgr/cglmbuffer.cpp
new file mode 100644
index 000000000..6ef3917be
--- /dev/null
+++ b/My project/sdk/glmgr/cglmbuffer.cpp
@@ -0,0 +1,367 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmbuffer.cpp
+//
+//===============================================================================
+
+#include "glmgr.h"
+#include "glmdisplay.h"
+#include "cglmbuffer.h"
+
+#ifdef OSX
+// Debugger - 10.8
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+// void BindBufferARB(enum target, uint buffer);
+// void DeleteBuffersARB(sizei n, const uint *buffers);
+// void GenBuffersARB(sizei n, uint *buffers);
+// boolean IsBufferARB(uint buffer);
+//
+// void BufferDataARB(enum target, sizeiptrARB size, const void *data,
+// enum usage);
+// void BufferSubDataARB(enum target, intptrARB offset, sizeiptrARB size,
+// const void *data);
+// void GetBufferSubDataARB(enum target, intptrARB offset,
+// sizeiptrARB size, void *data);
+//
+// void *MapBufferARB(enum target, enum access);
+// boolean UnmapBufferARB(enum target);
+//
+// void GetBufferParameterivARB(enum target, enum pname, int *params);
+// void GetBufferPointervARB(enum target, enum pname, void **params);
+//
+//New Tokens
+//
+// Accepted by the parameters of BindBufferARB, BufferDataARB,
+// BufferSubDataARB, MapBufferARB, UnmapBufferARB,
+// GetBufferSubDataARB, GetBufferParameterivARB, and
+// GetBufferPointervARB:
+//
+// ARRAY_BUFFER_ARB 0x8892
+// ELEMENT_ARRAY_BUFFER_ARB 0x8893
+//
+// Accepted by the parameter of GetBooleanv, GetIntegerv,
+// GetFloatv, and GetDoublev:
+//
+// ARRAY_BUFFER_BINDING_ARB 0x8894
+// ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+// VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+// NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+// COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+// INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+// TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+// EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+// SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+// FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+// WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+//
+// Accepted by the parameter of GetVertexAttribivARB:
+//
+// VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+//
+// Accepted by the parameter of BufferDataARB:
+//
+// STREAM_DRAW_ARB 0x88E0
+// STREAM_READ_ARB 0x88E1
+// STREAM_COPY_ARB 0x88E2
+// STATIC_DRAW_ARB 0x88E4
+// STATIC_READ_ARB 0x88E5
+// STATIC_COPY_ARB 0x88E6
+// DYNAMIC_DRAW_ARB 0x88E8
+// DYNAMIC_READ_ARB 0x88E9
+// DYNAMIC_COPY_ARB 0x88EA
+//
+// Accepted by the parameter of MapBufferARB:
+//
+// READ_ONLY_ARB 0x88B8
+// WRITE_ONLY_ARB 0x88B9
+// READ_WRITE_ARB 0x88BA
+//
+// Accepted by the parameter of GetBufferParameterivARB:
+//
+// BUFFER_SIZE_ARB 0x8764
+// BUFFER_USAGE_ARB 0x8765
+// BUFFER_ACCESS_ARB 0x88BB
+// BUFFER_MAPPED_ARB 0x88BC
+//
+// Accepted by the parameter of GetBufferPointervARB:
+//
+// BUFFER_MAP_POINTER_ARB 0x88BD
+
+// http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt
+// Accepted by the parameters of BindBuffer, BufferData,
+// BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData,
+// GetBufferParameteriv, and GetBufferPointerv:
+// PIXEL_PACK_BUFFER_ARB 0x88EB
+// PIXEL_UNPACK_BUFFER_ARB 0x88EC
+
+
+ // gl_bufmode: zero means we mark all vertex/index buffers static
+
+ // non zero means buffers are initially marked static..
+ // ->but can shift to dynamic upon first 'discard' (orphaning)
+
+//ConVar gl_bufmode( "gl_bufmode", "1" );
+int gl_bufmode = 1;
+
+CGLMBuffer::CGLMBuffer( GLMContext *ctx, EGLMBufferType type, uint size, uint options )
+{
+ m_ctx = ctx;
+ m_type = type;
+ switch(m_type)
+ {
+ case kGLMVertexBuffer: m_buffGLTarget = GL_ARRAY_BUFFER_ARB; break;
+ case kGLMIndexBuffer: m_buffGLTarget = GL_ELEMENT_ARRAY_BUFFER_ARB; break;
+ case kGLMUniformBuffer: m_buffGLTarget = GL_UNIFORM_BUFFER_EXT; break;
+ case kGLMPixelBuffer: m_buffGLTarget = GL_PIXEL_UNPACK_BUFFER_ARB; break;
+
+ default: //Assert(!"Unknown buffer type" );
+ break;
+ }
+ m_size = size;
+ m_bound = false;
+ m_mapped = false;
+ m_lastMappedAddress = NULL;
+
+ m_enableAsyncMap = false;
+ m_enableExplicitFlush = false;
+ m_dirtyMinOffset = m_dirtyMaxOffset = 0; // adjust/grow on lock, clear on unlock
+
+ m_ctx->CheckCurrent();
+ m_revision = rand();
+
+ // make a decision about pseudo mode
+ // this looked like it didn't help much or was actually slower, so leave it available but only as opt-in.
+ // a more clever implementation would be able to select pseudo buf storage for small batches only..
+ m_pseudo = false; // (m_type==kGLMIndexBuffer) && (CommandLine()->FindParm("-gl_enable_pseudobufs"));
+ if (m_pseudo)
+ {
+ m_name = 0;
+ m_pseudoBuf = (char*)malloc( size );
+
+ m_ctx->BindBufferToCtx( m_type, NULL ); // exit with no buffer bound
+ }
+ else
+ {
+ glGenBuffersARB( 1, &m_name );
+ GLMCheckError();
+
+ m_ctx->BindBufferToCtx( m_type, this ); // causes glBindBufferARB
+
+ // buffers start out static, but if they get orphaned and gl_bufmode is non zero,
+ // then they will get flipped to dynamic.
+
+ GLenum hint = GL_STATIC_DRAW_ARB;
+ switch(m_type)
+ {
+ case kGLMVertexBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
+ case kGLMIndexBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
+ case kGLMUniformBuffer: hint = GL_DYNAMIC_DRAW_ARB; break; // "fwiw" - shrug
+ case kGLMPixelBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
+
+ default: //Assert(!"Unknown buffer type" );
+ break;
+ }
+
+ glBufferDataARB( m_buffGLTarget, m_size, NULL, hint ); // may ultimately need more hints to set the usage correctly (esp for streaming)
+
+ this->SetModes( false, true, true );
+
+ m_ctx->BindBufferToCtx( m_type, NULL ); // unbind me
+ }
+}
+
+CGLMBuffer::~CGLMBuffer( )
+{
+ m_ctx->CheckCurrent();
+
+ if (m_pseudo)
+ {
+ free (m_pseudoBuf);
+ m_pseudoBuf = NULL;
+ }
+ else
+ {
+ glDeleteBuffersARB( 1, &m_name );
+ GLMCheckError();
+ }
+
+ m_ctx = NULL;
+ m_name = 0;
+ m_bound = 0;
+
+ m_lastMappedAddress = NULL;
+}
+
+void CGLMBuffer::SetModes ( bool asyncMap, bool explicitFlush, bool force )
+{
+ // assumes buffer is bound. called by constructor and by Lock.
+
+ if (m_pseudo)
+ {
+ // ignore it...
+ }
+ else
+ {
+ if (force || (m_enableAsyncMap != asyncMap) )
+ {
+ // note the sense of the parameter, it's TRUE if you *want* serialization, so for async you turn it to false.
+ glBufferParameteriAPPLE( this->m_buffGLTarget, GL_BUFFER_SERIALIZED_MODIFY_APPLE, asyncMap==false );
+ m_enableAsyncMap = asyncMap;
+ }
+
+ if (force || (m_enableExplicitFlush != explicitFlush) )
+ {
+ // note the sense of the parameter, it's TRUE if you *want* auto-flush-on-unmap, so for explicit-flush, you turn it to false.
+ glBufferParameteriAPPLE( this->m_buffGLTarget, GL_BUFFER_FLUSHING_UNMAP_APPLE, explicitFlush==false );
+ m_enableExplicitFlush = explicitFlush;
+ }
+ }
+}
+
+void CGLMBuffer::FlushRange ( uint offset, uint size )
+{
+ if (m_pseudo)
+ {
+ // nothing to do
+ }
+ else
+ {
+ // assumes buffer is bound.
+ glFlushMappedBufferRangeAPPLE(this->m_buffGLTarget, (GLintptr)offset, (GLsizeiptr)size);
+ }
+}
+
+//ConVar gl_buffer_alignment_quantum ( "gl_buffer_alignment_quantum", "32" ); // the alignment we use pre-SLGU
+//ConVar gl_buffer_alignment_quantum_slgu( "gl_buffer_alignment_quantum_slgu", "2" ); // alignment used post-SLGU
+
+int gl_buffer_alignment_quantum = 32;
+int gl_buffer_alignment_quantum_slgu = 2;
+
+void CGLMBuffer::Lock( GLMBuffLockParams *params, char **addressOut )
+{
+ char *resultPtr = NULL;
+
+ //Assert( !m_mapped);
+
+ m_ctx->CheckCurrent();
+ GLMCheckError();
+
+ if (params->m_offset >= m_size)
+ Debugger();
+
+ if (params->m_offset + params->m_size > m_size)
+ Debugger();
+
+ // bind (yes, even for pseudo - this binds name 0)
+ m_ctx->BindBufferToCtx( this->m_type, this );
+
+ if (m_pseudo)
+ {
+ // discard is a no-op
+
+ // async map modes are a no-op
+
+ // latch last mapped address (silly..)
+ m_lastMappedAddress = (float*)m_pseudoBuf;
+
+ // calc lock address
+ resultPtr = m_pseudoBuf + params->m_offset;
+
+ // dirty range is a no-op
+ }
+ else
+ {
+ // perform discard if requested
+ if (params->m_discard)
+ {
+ // observe gl_bufmode on any orphan event.
+ // if orphaned and bufmode is nonzero, flip it to dynamic.
+ GLenum hint = gl_bufmode /*.GetInt()*/ ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB;
+ glBufferDataARB( m_buffGLTarget, m_size, NULL, hint );
+
+ m_lastMappedAddress = NULL;
+
+ m_revision++; // revision grows on orphan event
+ }
+
+ // adjust async map option appropriately, leave explicit flush unchanged
+ this->SetModes( params->m_nonblocking, m_enableExplicitFlush );
+
+ // map
+ char *mapPtr = (char*)glMapBufferARB( this->m_buffGLTarget, GL_READ_WRITE_ARB );
+
+ if (!mapPtr)
+ {
+ Debugger();
+ }
+
+ if (m_lastMappedAddress)
+ {
+ // just check if it moved
+ //Assert (m_lastMappedAddress == (float*)mapPtr);
+ }
+
+ m_lastMappedAddress = (float*)mapPtr;
+
+ // calculate offset location
+ resultPtr = mapPtr + params->m_offset;
+
+ // adjust dirty range
+ if (m_dirtyMinOffset != m_dirtyMaxOffset)
+ {
+ // grow range
+ m_dirtyMinOffset = std::min( m_dirtyMinOffset, params->m_offset );
+ m_dirtyMaxOffset = std::min( m_dirtyMaxOffset, params->m_offset+params->m_size );
+ }
+ else
+ {
+ // set range
+ m_dirtyMinOffset = params->m_offset;
+ m_dirtyMaxOffset = params->m_offset+params->m_size;
+ }
+
+ // pad and clamp dirty range to choice of boundary
+ uint quantum = (m_ctx->Caps().m_hasPerfPackage1) ? gl_buffer_alignment_quantum_slgu /*.GetInt()*/ : gl_buffer_alignment_quantum /*.GetInt()*/ ;
+ uint quantum_mask = quantum - 1;
+
+ m_dirtyMinOffset = m_dirtyMinOffset & (~quantum_mask);
+ m_dirtyMaxOffset = (m_dirtyMaxOffset + quantum_mask) & (~quantum_mask);
+ m_dirtyMaxOffset = std::min( m_dirtyMaxOffset, m_size );
+ }
+
+ m_mapped = true;
+
+ *addressOut = resultPtr;
+}
+
+void CGLMBuffer::Unlock( void )
+{
+ m_ctx->CheckCurrent();
+
+ //Assert (m_mapped);
+
+ if (m_pseudo)
+ {
+ // nothing to do actually
+ }
+ else
+ {
+ m_ctx->BindBufferToCtx( this->m_type, this );
+
+ // time to do explicit flush
+ if (m_enableExplicitFlush)
+ {
+ this->FlushRange( m_dirtyMinOffset, m_dirtyMaxOffset - m_dirtyMinOffset );
+ }
+
+ // clear dirty range no matter what
+ m_dirtyMinOffset = m_dirtyMaxOffset = 0; // adjust/grow on lock, clear on unlock
+
+ glUnmapBuffer( this->m_buffGLTarget );
+
+ }
+
+ m_mapped = false;
+}
diff --git a/My project/sdk/glmgr/cglmbuffer.h b/My project/sdk/glmgr/cglmbuffer.h
new file mode 100644
index 000000000..9c7d222d7
--- /dev/null
+++ b/My project/sdk/glmgr/cglmbuffer.h
@@ -0,0 +1,91 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmprogram.h
+// GLMgr buffers (index / vertex)
+// ... maybe add PBO later as well
+//===============================================================================
+
+#ifndef CGLMBUFFER_H
+#define CGLMBUFFER_H
+
+#pragma once
+
+// ext links
+
+// http://www.opengl.org/registry/specs/ARB/vertex_buffer_object.txt
+
+//===============================================================================
+
+// forward declarations
+
+class GLMContext;
+
+enum EGLMBufferType
+{
+ kGLMVertexBuffer,
+ kGLMIndexBuffer,
+ kGLMUniformBuffer, // for bindable uniform
+ kGLMPixelBuffer, // for PBO
+
+ kGLMNumBufferTypes
+};
+
+ // pass this in "options" to constructor to make a dynamic buffer
+#define GLMBufferOptionDynamic 0x00000001
+
+struct GLMBuffLockParams
+{
+ uint m_offset;
+ uint m_size;
+ bool m_nonblocking;
+ bool m_discard;
+};
+
+class CGLMBuffer
+{
+
+public:
+ void Lock( GLMBuffLockParams *params, char **addressOut );
+ void Unlock( void );
+
+//protected:
+ friend class GLMContext; // only GLMContext can make CGLMBuffer objects
+ friend class GLMTester;
+ friend struct IDirect3D9;
+ friend struct IDirect3DDevice9;
+
+ CGLMBuffer ( GLMContext *ctx, EGLMBufferType type, uint size, uint options );
+ ~CGLMBuffer ( );
+
+ void SetModes ( bool asyncMap, bool explicitFlush, bool force = false );
+ void FlushRange ( uint offset, uint size );
+
+ GLMContext *m_ctx; // link back to parent context
+ EGLMBufferType m_type;
+ uint m_size;
+ GLenum m_buffGLTarget; // GL_ARRAY_BUFFER_ARB / GL_ELEMENT_BUFFER_ARB
+ GLuint m_name; // name of this program in the context
+ uint m_revision; // bump anytime the size changes or buffer is orphaned
+ bool m_enableAsyncMap; // mirror of the buffer state
+ bool m_enableExplicitFlush; // mirror of the buffer state
+
+ bool m_bound; // true if bound to context
+ bool m_mapped; // is it currently mapped
+ uint m_dirtyMinOffset; // when equal, range is empty
+ uint m_dirtyMaxOffset;
+
+ float *m_lastMappedAddress;
+
+ // --------------------- pseudo-VBO support below here (explicitly for dynamic index buffers)
+ bool m_pseudo; // true if the m_name is 0, and the backing is plain RAM
+
+ // in pseudo mode, there is just one RAM buffer that acts as the backing.
+ // expectation is that this mode would only be used for dynamic indices.
+ // since indices have to be consumed (copied to command stream) prior to return from a drawing call,
+ // there's no need to do any fencing or multibuffering. orphaning in particular becomes a no-op.
+
+ char *m_pseudoBuf; // storage for pseudo buffer
+};
+
+
+#endif
diff --git a/My project/sdk/glmgr/cglmfbo.cpp b/My project/sdk/glmgr/cglmfbo.cpp
new file mode 100644
index 000000000..5f3479c29
--- /dev/null
+++ b/My project/sdk/glmgr/cglmfbo.cpp
@@ -0,0 +1,356 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmfbo.cpp
+//
+//===============================================================================
+
+#include "glmgr.h"
+#include "cglmfbo.h"
+// #include "../shaderapidx9/dxabstract.h"
+
+#ifdef OSX
+// Debugger - 10.8
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+CGLMFBO::CGLMFBO( GLMContext *ctx )
+{
+ m_ctx = ctx;
+ m_ctx->CheckCurrent();
+
+ glGenFramebuffersEXT( 1, &m_name );
+ GLMCheckError();
+
+ memset( m_attach, 0, sizeof( m_attach ) );
+
+ m_sizeX = m_sizeY = 0;
+}
+
+
+CGLMFBO::~CGLMFBO( )
+{
+ m_ctx->CheckCurrent();
+
+ // detach all known attached textures first... necessary ?
+ for( int index = 0; index < kAttCount; index++)
+ {
+ if (m_attach[ index ].m_tex)
+ {
+ TexDetach( (EGLMFBOAttachment)index );
+ GLMCheckError();
+ }
+ }
+
+ glDeleteFramebuffersEXT( 1, &m_name );
+ GLMCheckError();
+
+ m_name = 0;
+ m_ctx = NULL;
+}
+
+// the tex attach path should also select a specific slice of the texture...
+// and we need a way to make renderbuffers..
+
+static GLenum EncodeAttachmentFBO( EGLMFBOAttachment index )
+{
+ if (index < kAttDepth)
+ {
+ return GL_COLOR_ATTACHMENT0_EXT + (int) index;
+ }
+ else
+ {
+ switch( index )
+ {
+ case kAttDepth:
+ return GL_DEPTH_ATTACHMENT_EXT;
+ break;
+
+ case kAttStencil:
+ return GL_STENCIL_ATTACHMENT_EXT;
+ break;
+
+ case kAttDepthStencil:
+ return GL_DEPTH_STENCIL_ATTACHMENT_EXT;
+ break;
+
+ default:
+ GLMStop(); // bad news
+ return 0;
+ break;
+ }
+ }
+}
+
+void CGLMFBO::TexAttach( GLMFBOTexAttachParams *params, EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
+{
+ // force our parent context to be current
+ m_ctx->MakeCurrent();
+
+ // bind to context (will cause FBO object creation on first use)
+ m_ctx->BindFBOToCtx( this, fboBindPoint );
+
+ // it's either a plain 2D, a 2D face of a cube map, or a slice of a 3D.
+ CGLMTex *tex = params->m_tex;
+
+ // always detach what is currently there, if anything
+ this->TexDetach( attachIndex, fboBindPoint );
+
+ if (!tex)
+ {
+ // andif they pass NULL to us, then we are done.
+ return;
+ }
+
+ GLMTexLayout *layout = tex->m_layout;
+ GLenum target = tex->m_layout->m_key.m_texGLTarget;
+
+ GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
+
+ switch( target )
+ {
+ case GL_TEXTURE_2D:
+ {
+ // we will attach the underlying RBO on a multisampled tex, iff the tex hasone, **and** we're not being asked to attach it to the read buffer.
+ // if we get a req to attach an MSAA tex to the read buffer, chances are it's BlitTex calling, andit has already resolved the tex, so in those
+ // cases you really do want to attach the texture and not the RBO to the FBO in question.
+
+ bool useRBO = false; // initial state
+
+ if (layout->m_key.m_texFlags & kGLMTexMultisampled)
+ {
+ // it is an MSAA tex
+ if (fboBindPoint == GL_READ_FRAMEBUFFER_EXT)
+ {
+ // I think you just want to read a resolved tex.
+ // But I will check that it is resolved first..
+ Assert( tex->m_rboDirty == false );
+ }
+ else
+ {
+ // you want to draw into it. You get the RBO bound instead of the tex.
+ useRBO = true;
+ }
+ }
+
+ if (useRBO)
+ {
+ // MSAA path - attach the RBO, not the texture, and mark the RBO dirty
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // you have to attach it both places...
+ // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
+
+ // bind the RBO to the GL_RENDERBUFFER_EXT target
+ glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
+ GLMCheckError();
+
+ // attach the GL_RENDERBUFFER_EXT target to the depth and stencil attach points
+ glFramebufferRenderbufferEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
+ GLMCheckError();
+
+ glFramebufferRenderbufferEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
+ GLMCheckError();
+
+ // no need to leave the RBO hanging on
+ glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ GLMCheckError();
+ }
+ else
+ {
+ // color attachment (likely 0)
+ glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
+ GLMCheckError();
+
+ glFramebufferRenderbufferEXT( fboBindPoint, attachIndexGL, GL_RENDERBUFFER_EXT, tex->m_rboName);
+ GLMCheckError();
+
+ glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ GLMCheckError();
+ }
+ tex->m_rboDirty = true;
+ }
+ else
+ {
+ // regular path - attaching a texture2d
+
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // you have to attach it both places...
+ // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
+
+ glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
+ GLMCheckError();
+
+ glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
+ GLMCheckError();
+ }
+ else
+ {
+ glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
+ GLMCheckError();
+ }
+ }
+ }
+ break;
+
+ case GL_TEXTURE_3D:
+ {
+ glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip, params->m_zslice );
+ GLMCheckError();
+ }
+ break;
+
+ case GL_TEXTURE_CUBE_MAP:
+ {
+ // adjust target to steer to the proper face of the cube map
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + params->m_face;
+
+ glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
+ GLMCheckError();
+ }
+ break;
+ }
+
+ // log the attached tex
+ m_attach[ attachIndex ] = *params;
+
+ // indicate that the tex has been bound to an RT
+ tex->m_rtAttachCount++;
+}
+
+void CGLMFBO::TexDetach( EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
+{
+ // force our parent context to be current
+ m_ctx->MakeCurrent();
+
+ // bind to context (will cause FBO object creation on first use)
+ m_ctx->BindFBOToCtx( this, fboBindPoint );
+
+ if (m_attach[ attachIndex ].m_tex)
+ {
+ CGLMTex *tex = m_attach[ attachIndex ].m_tex;
+ GLMTexLayout *layout = tex->m_layout;
+ GLenum target = tex->m_layout->m_key.m_texGLTarget;
+
+ GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
+
+ switch( target )
+ {
+ case GL_TEXTURE_2D:
+ {
+ if (layout->m_key.m_texFlags & kGLMTexMultisampled)
+ {
+ // MSAA path - detach the RBO, not the texture
+ // (is this the right time to resolve? probably better to wait until someone tries to sample the texture)
+
+ glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ GLMCheckError();
+
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // detach the GL_RENDERBUFFER_EXT target at depth and stencil attach points
+ glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
+ GLMCheckError();
+
+ glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
+ GLMCheckError();
+ }
+ else
+ {
+ // color attachment (likely 0)
+ glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, 0);
+ GLMCheckError();
+ }
+ }
+ else
+ {
+ // plain tex detach
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // you have to detach it both places...
+ // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
+
+ glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, 0,0,0 );
+ glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, 0,0,0 );
+ }
+ else
+ {
+ glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, 0, 0, 0 );
+ }
+ }
+ }
+ break;
+
+ case GL_TEXTURE_3D:
+ {
+ glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, 0, 0, 0, 0 );
+ GLMCheckError();
+ }
+ break;
+
+ case GL_TEXTURE_CUBE_MAP:
+ {
+ glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, 0, 0, 0 );
+ GLMCheckError();
+ }
+ break;
+ }
+
+ // un-log the attached tex
+ memset( &m_attach[ attachIndex ], 0, sizeof( m_attach[0] ) );
+
+ // drop the RT attach count
+ tex->m_rtAttachCount--;
+ }
+ else
+ {
+ //Debugger(); // odd, but not harmful - typ comes from D3D code passing NULL into SetRenderTarget
+ }
+}
+
+void CGLMFBO::TexScrub( CGLMTex *tex )
+{
+ // see if it's attached anywhere
+ for( int attachIndex = 0; attachIndex < kAttCount; attachIndex++ )
+ {
+ if (m_attach[ attachIndex ].m_tex == tex)
+ {
+ // blammo
+ TexDetach( (EGLMFBOAttachment)attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
+ }
+ }
+}
+
+
+bool CGLMFBO::IsReady( void )
+{
+ bool result = false;
+
+ // ensure our parent context is current
+ m_ctx->CheckCurrent();
+
+ // bind to context (will cause FBO object creation on first use)
+ m_ctx->BindFBOToCtx( this );
+
+ GLenum status;
+ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ switch(status)
+ {
+ case GL_FRAMEBUFFER_COMPLETE_EXT:
+ result = true;
+ break;
+
+ case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+ result = false;
+ Debugger();
+ /* choose different formats */
+ break;
+
+ default:
+ result = false;
+ Debugger();
+ /* programming error; will fail on all hardware */
+ break;
+ }
+ return result;
+}
diff --git a/My project/sdk/glmgr/cglmfbo.h b/My project/sdk/glmgr/cglmfbo.h
new file mode 100644
index 000000000..15342fe67
--- /dev/null
+++ b/My project/sdk/glmgr/cglmfbo.h
@@ -0,0 +1,91 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmfbo.h
+// GLMgr FBO's (render targets)
+//
+//===============================================================================
+
+#ifndef CGLMFBO_H
+#define CGLMFBO_H
+
+#pragma once
+
+#include "cglmtex.h"
+
+// good FBO references / recaps
+// http://www.songho.ca/opengl/gl_fbo.html
+// http://www.gamedev.net/reference/articles/article2331.asp
+
+// ext links
+
+// http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt
+// http://www.opengl.org/registry/specs/EXT/framebuffer_multisample.txt
+
+//===============================================================================
+
+// tokens not in the SDK headers
+
+#ifndef GL_DEPTH_STENCIL_ATTACHMENT_EXT
+ #define GL_DEPTH_STENCIL_ATTACHMENT_EXT 0x84F9
+#endif
+
+//===============================================================================
+
+// forward declarations
+
+class GLMContext;
+
+// implicitly 16 maximum color attachments possible
+enum EGLMFBOAttachment {
+ kAttColor0, kAttColor1, kAttColor2, kAttColor3,
+ kAttColor4, kAttColor5, kAttColor6, kAttColor7,
+ kAttColor8, kAttColor9, kAttColor10, kAttColor11,
+ kAttColor12, kAttColor13, kAttColor14, kAttColor15,
+ kAttDepth, kAttStencil, kAttDepthStencil,
+ kAttCount
+};
+
+struct GLMFBOTexAttachParams
+{
+ CGLMTex *m_tex;
+ int m_face; // keep zero if not cube map
+ int m_mip; // keep zero if notmip mapped
+ int m_zslice; // keep zero if not a 3D tex
+};
+
+class CGLMFBO
+{
+
+public:
+
+protected:
+ friend class GLMContext; // only GLMContext can make CGLMFBO objects
+ friend class GLMTester;
+ friend class CGLMTex;
+
+ friend struct IDirect3D9;
+ friend struct IDirect3DDevice9;
+
+ CGLMFBO( GLMContext *ctx );
+ ~CGLMFBO( );
+
+ void TexAttach( GLMFBOTexAttachParams *params, EGLMFBOAttachment attachIndex, GLenum fboBindPoint = GL_FRAMEBUFFER_EXT );
+ void TexDetach( EGLMFBOAttachment attachIndex, GLenum fboBindPoint = GL_FRAMEBUFFER_EXT );
+ // you can also pass GL_READ_FRAMEBUFFER_EXT or GL_DRAW_FRAMEBUFFER_EXT to selectively bind the receiving FBO to one or the other.
+
+ void TexScrub( CGLMTex *tex );
+ // search and destroy any attachment for the named texture
+
+ bool IsReady( void ); // aka FBO completeness check - ready to draw
+
+ GLMContext *m_ctx; // link back to parent context
+
+ GLuint m_name; // name of this FBO in the context
+
+ GLMFBOTexAttachParams m_attach[ kAttCount ]; // indexed by EGLMFBOAttachment
+
+ int m_sizeX,m_sizeY;
+};
+
+
+#endif
diff --git a/My project/sdk/glmgr/cglmprogram.cpp b/My project/sdk/glmgr/cglmprogram.cpp
new file mode 100644
index 000000000..f27c96b9d
--- /dev/null
+++ b/My project/sdk/glmgr/cglmprogram.cpp
@@ -0,0 +1,1448 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmprogram.cpp
+//
+//===============================================================================
+
+#include "glmgr.h"
+#include "cglmprogram.h"
+#include "dxabstract.h"
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wunused-variable"
+#endif
+
+#ifdef OSX
+// Debugger - 10.8
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+//===============================================================================
+
+#if 0
+ ConVar gl_shaderpair_cacherows_lg2( "gl_paircache_rows_lg2", "10"); // 10 is minimum
+ ConVar gl_shaderpair_cacheways_lg2( "gl_paircache_ways_lg2", "5"); // 5 is minimum
+ ConVar gl_shaderpair_cachelog( "gl_shaderpair_cachelog", "0" );
+#else
+ int gl_shaderpair_cacherows_lg2 = 10;
+ int gl_shaderpair_cacheways_lg2 = 5;
+ int gl_shaderpair_cachelog = 0;
+#endif
+
+//===============================================================================
+
+
+GLenum GLMProgTypeToARBEnum( EGLMProgramType type )
+{
+ GLenum result = 0;
+ switch(type)
+ {
+ case kGLMVertexProgram: result = GL_VERTEX_PROGRAM_ARB; break;
+ case kGLMFragmentProgram: result = GL_FRAGMENT_PROGRAM_ARB; break;
+ default: Assert( !"bad program type"); result = 0; break;
+ }
+ return result;
+}
+
+GLenum GLMProgTypeToGLSLEnum( EGLMProgramType type )
+{
+ GLenum result = 0;
+ switch(type)
+ {
+ case kGLMVertexProgram: result = GL_VERTEX_SHADER_ARB; break;
+ case kGLMFragmentProgram: result = GL_FRAGMENT_SHADER_ARB; break;
+ default: Assert( !"bad program type"); result = 0; break;
+ }
+ return result;
+}
+
+static uint g_shader_serial = 1000000;
+
+CGLMProgram::CGLMProgram( GLMContext *ctx, EGLMProgramType type )
+{
+ m_ctx = ctx;
+ m_ctx->CheckCurrent();
+
+ m_type = type;
+ m_serial = g_shader_serial++;
+ m_text = NULL; // no text yet
+
+#if GLMDEBUG
+ m_editable = NULL;
+#endif
+
+ memset( &m_descs, 0, sizeof( m_descs ) );
+
+ m_samplerMask = 0; // dxabstract sets this field later
+
+ // create an ARB vp/fp program object name. No need to bind it yet.
+ GLMShaderDesc *arbDesc = &m_descs[ kGLMARB ];
+ glGenProgramsARB( 1, &arbDesc->m_object.arb );
+
+ // create a GLSL shader object.
+ GLMShaderDesc *glslDesc = &m_descs[ kGLMGLSL ];
+ GLenum glslStage = GLMProgTypeToGLSLEnum( m_type );
+
+ glslDesc->m_object.glsl = glCreateShaderObjectARB( glslStage );;
+
+ // no text has arrived yet. That's done in SetProgramText.
+}
+
+CGLMProgram::~CGLMProgram( )
+{
+ m_ctx->CheckCurrent();
+
+ // if there is an arb program, delete it
+ GLMShaderDesc *arbDesc = &m_descs[ kGLMARB ];
+ if (arbDesc->m_object.arb)
+ {
+ glDeleteProgramsARB( 1, &arbDesc->m_object.arb );
+ GLMCheckError();
+ arbDesc->m_object.arb = 0;
+ }
+
+ // if there is a GLSL shader, delete it
+ GLMShaderDesc *glslDesc = &m_descs[kGLMGLSL];
+ if (glslDesc->m_object.glsl)
+ {
+ glDeleteShader( (uintptr_t)glslDesc->m_object.glsl ); // why do I need a cast here again ?
+ GLMCheckError();
+ glslDesc->m_object.glsl = 0;
+ }
+
+#if GLMDEBUG
+ if (m_editable)
+ {
+ delete m_editable;
+ m_editable = NULL;
+ }
+#endif
+
+ if (m_text)
+ {
+ free( m_text );
+ m_text = NULL;
+ }
+ m_ctx = NULL;
+}
+
+enum EShaderSection
+{
+ kGLMARBVertex, kGLMARBVertexDisabled,
+ kGLMARBFragment, kGLMARBFragmentDisabled,
+ kGLMGLSLVertex, kGLMGLSLVertexDisabled,
+ kGLMGLSLFragment, kGLMGLSLFragmentDisabled,
+
+};
+
+const char *g_shaderSectionMarkers[] = // match ordering of enum
+{
+ "!!ARBvp", "-!!ARBvp", // enabled and disabled markers. so you can have multiple flavors in a blob and activate the one you want.
+ "!!ARBfp", "-!!ARBfp",
+ "//GLSLvp", "-//GLSLvp",
+ "//GLSLfp", "-//GLSLfp",
+ NULL
+};
+
+void CGLMProgram::SetProgramText( char *text )
+{
+ // free old text if any
+ // clone new text
+ // scan newtext to find sections
+ // walk sections, and mark descs to indicate where text is at
+
+ if (m_text)
+ {
+ free( m_text );
+ m_text = NULL;
+ }
+
+ // scrub desc text references
+ for( int i=0; im_textPresent = false;
+ desc->m_textOffset = 0;
+ desc->m_textLength = 0;
+ }
+
+ m_text = strdup( text );
+ Assert( m_text != NULL );
+
+ #if 0 // disabled in sample for now GLMDEBUG
+ // create editable text item, if it does not already exist
+ if (!m_editable)
+ {
+ char *suffix = "";
+
+ switch(m_type)
+ {
+ case kGLMVertexProgram: suffix = ".vsh"; break;
+ case kGLMFragmentProgram: suffix = ".fsh"; break;
+ default: GLMDebugger();
+ }
+
+ m_editable = new CGLMEditableTextItem( m_text, strlen(m_text), false, "/debugshaders/", suffix );
+
+ // pull our string back from the editable (it has probably munged it)
+ if (m_editable->HasData())
+ {
+ ReloadStringFromEditable();
+ }
+ }
+ #endif
+
+
+ // scan the text and find sections
+ CGLMTextSectioner sections( m_text, strlen( m_text ), g_shaderSectionMarkers );
+
+ int sectionCount = sections.Count();
+ for( int i=0; i < sectionCount; i++ )
+ {
+ uint subtextOffset = 0;
+ uint subtextLength = 0;
+ int markerIndex = 0;
+
+ sections.GetSection( i, &subtextOffset, &subtextLength, &markerIndex );
+
+ // act on the section
+ GLMShaderDesc *desc = NULL;
+ switch( m_type )
+ {
+ case kGLMVertexProgram:
+ switch( markerIndex )
+ {
+ case kGLMARBVertex:
+ case kGLMGLSLVertex:
+ desc = &m_descs[ (markerIndex==kGLMARBVertex) ? kGLMARB : kGLMGLSL];
+
+ // these steps are generic across both langs
+ desc->m_textPresent = true;
+ desc->m_textOffset = subtextOffset;
+ desc->m_textLength = subtextLength;
+ desc->m_compiled = false;
+ desc->m_valid = false;
+ break;
+
+ case kGLMARBVertexDisabled:
+ case kGLMGLSLVertexDisabled:
+ // ignore quietly
+ break;
+
+ default: Assert(!"Mismatched section marker seen in SetProgramText (VP)"); break;
+ }
+ break;
+
+ case kGLMFragmentProgram:
+ switch( markerIndex )
+ {
+ case kGLMARBFragment:
+ case kGLMGLSLFragment:
+ desc = &m_descs[ (markerIndex==kGLMARBFragment) ? kGLMARB : kGLMGLSL];
+
+ // these steps are generic across both langs
+ desc->m_textPresent = true;
+ desc->m_textOffset = subtextOffset;
+ desc->m_textLength = subtextLength;
+ desc->m_compiled = false;
+ desc->m_valid = false;
+ break;
+
+ case kGLMARBFragmentDisabled:
+ case kGLMGLSLFragmentDisabled:
+ // ignore quietly
+ break;
+
+ default: Assert(!"Mismatched section marker seen in SetProgramText (VP)"); break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+bool CGLMProgram::CompileActiveSources ( void )
+{
+ bool result = true; // assume success
+
+ // compile everything we have text for
+ for( int i=0; im_object.arb ); // object created or just re-bound
+ GLMCheckError();
+
+ char *section = m_text + arbDesc->m_textOffset;
+ char *lastCharOfSection = section + arbDesc->m_textLength; // actually it's one past the last textual character
+
+ #if GLMDEBUG
+ if(noisy)
+ {
+ GLMPRINTF((">-D- CGLMProgram::Compile submitting following text for ARB %s program (name %d) ---------------------",
+ arbTarget == GL_FRAGMENT_PROGRAM_ARB ? "fragment" : "vertex",
+ arbDesc->m_object.arb ));
+
+ // we don't have a "print this many chars" call yet
+ // just temporarily null terminate the text we want to print
+
+ char saveChar = *lastCharOfSection;
+
+ *lastCharOfSection= 0;
+ GLMPRINTTEXT(( section, eDebugDump ));
+ *lastCharOfSection= saveChar;
+
+ GLMPRINTF(("<-D- CGLMProgram::Compile ARB EOT--" ));
+ }
+ #endif
+
+ glProgramStringARB( arbTarget, GL_PROGRAM_FORMAT_ASCII_ARB, arbDesc->m_textLength, section );
+ GLMCheckError( true, false );
+ arbDesc->m_compiled = true; // compiled but not necessarily valid
+
+ CheckValidity( lang );
+ GLMCheckError();
+ // leave it bound n enabled, don't care (draw will sort it all out)
+
+ result = arbDesc->m_valid;
+ }
+ break;
+
+ case kGLMGLSL:
+ {
+ GLMShaderDesc *glslDesc;
+
+ glslDesc = &m_descs[ kGLMGLSL ];
+
+ GLenum glslStage = GLMProgTypeToGLSLEnum( m_type );
+
+ // there's no binding to do for GLSL. but make sure no ARB stuff is bound for tidiness.
+ glSetEnable( GL_VERTEX_PROGRAM_ARB, false );
+ glSetEnable( GL_FRAGMENT_PROGRAM_ARB, false ); // add check errors on these
+
+ glBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 );
+ glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, 0 );
+
+ // no GLSL program either
+ glUseProgram(0);
+
+ // pump text into GLSL shader object
+
+ char *section = m_text + glslDesc->m_textOffset;
+ char *lastCharOfSection = section + glslDesc->m_textLength; // actually it's one past the last textual character
+
+ #if GLMDEBUG
+ if(noisy)
+ {
+ GLMPRINTF((">-D- CGLMProgram::Compile submitting following text for GLSL %s program (name %d) ---------------------",
+ glslStage == GL_FRAGMENT_SHADER_ARB ? "fragment" : "vertex",
+ glslDesc->m_object.glsl ));
+
+ // we don't have a "print this many chars" call yet
+ // just temporarily null terminate the text we want to print
+
+ char saveChar = *lastCharOfSection;
+
+ *lastCharOfSection= 0;
+ GLMPRINTTEXT(( section, eDebugDump ));
+ *lastCharOfSection= saveChar;
+
+ GLMPRINTF(("<-D- CGLMProgram::Compile GLSL EOT--" ));
+ }
+ #endif
+
+ glShaderSourceARB( glslDesc->m_object.glsl, 1, (const GLchar **)§ion, &glslDesc->m_textLength);
+ GLMCheckError( true, false );
+
+ // compile
+ glCompileShaderARB( glslDesc->m_object.glsl );
+ glslDesc->m_compiled = true; // compiled but not necessarily valid
+ GLMCheckError( true, false );
+
+ CheckValidity( lang );
+ GLMCheckError();
+
+ if (loglevel>=2)
+ {
+ char tempname[128];
+ int tempindex = -1;
+ int tempcombo = -1;
+
+ //GetLabelIndexCombo( tempname, sizeof(tempname), &tempindex, &tempcombo );
+ //printf("\ncompile: - [ %s/%d/%d ] on GL name %d ", tempname, tempindex, tempcombo, glslDesc->m_object.glsl );
+
+
+ GetComboIndexNameString( tempname, sizeof(tempname) );
+ printf("\ncompile: %s on GL name %p ", tempname, glslDesc->m_object.glsl );
+ }
+
+ result = glslDesc->m_valid;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return result;
+}
+
+#if GLMDEBUG
+
+ bool CGLMProgram::PollForChanges( void )
+ {
+ bool result = false;
+ if (m_editable)
+ {
+ result = m_editable->PollForChanges();
+ }
+ return result;
+ }
+
+ void CGLMProgram::ReloadStringFromEditable( void )
+ {
+ uint dataSize=0;
+ char *data=NULL;
+
+ m_editable->GetCurrentText( &data, &dataSize );
+
+ char *buf = (char *)malloc( dataSize+1 ); // we will NULL terminate it, since the mirror copy might not be
+ memcpy( buf, data, dataSize );
+ buf[dataSize] = 0;
+
+ SetProgramText( buf );
+
+ free( buf );
+ }
+
+ bool CGLMProgram::SyncWithEditable( void )
+ {
+ bool result = false;
+
+ if (m_editable->PollForChanges())
+ {
+ ReloadStringFromEditable();
+
+ CompileActiveSources();
+
+ // invalidate shader pair cache entries using this shader..
+ m_ctx->m_pairCache->PurgePairsWithShader( this );
+
+ result = true; // result true means "it changed"
+ }
+ return result;
+ }
+
+#endif
+
+
+// attributes which are general to both stages
+// VP and FP:
+//
+// 0x88A0 PROGRAM_INSTRUCTIONS_ARB VP FP
+// 0x88A1 MAX_PROGRAM_INSTRUCTIONS_ARB VP FP
+// 0x88A2 PROGRAM_NATIVE_INSTRUCTIONS_ARB VP FP
+// 0x88A3 MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB VP FP
+//
+// 0x88A4 PROGRAM_TEMPORARIES_ARB VP FP
+// 0x88A5 MAX_PROGRAM_TEMPORARIES_ARB VP FP
+// 0x88A6 PROGRAM_NATIVE_TEMPORARIES_ARB VP FP
+// 0x88A7 MAX_PROGRAM_NATIVE_TEMPORARIES_ARB VP FP
+//
+// 0x88A8 PROGRAM_PARAMETERS_ARB VP FP
+// 0x88A9 MAX_PROGRAM_PARAMETERS_ARB VP FP
+// 0x88AA PROGRAM_NATIVE_PARAMETERS_ARB VP FP
+// 0x88AB MAX_PROGRAM_NATIVE_PARAMETERS_ARB VP FP
+//
+// 0x88AC PROGRAM_ATTRIBS_ARB VP FP
+// 0x88AD MAX_PROGRAM_ATTRIBS_ARB VP FP
+// 0x88AE PROGRAM_NATIVE_ATTRIBS_ARB VP FP
+// 0x88AF MAX_PROGRAM_NATIVE_ATTRIBS_ARB VP FP
+//
+// 0x88B4 MAX_PROGRAM_LOCAL_PARAMETERS_ARB VP FP
+// 0x88B5 MAX_PROGRAM_ENV_PARAMETERS_ARB VP FP
+// 0x88B6 PROGRAM_UNDER_NATIVE_LIMITS_ARB VP FP
+//
+// VP only:
+//
+// 0x88B0 PROGRAM_ADDRESS_REGISTERS_ARB VP
+// 0x88B1 MAX_PROGRAM_ADDRESS_REGISTERS_ARB VP
+// 0x88B2 PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB VP
+// 0x88B3 MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB VP
+//
+// FP only:
+//
+// 0x8805 PROGRAM_ALU_INSTRUCTIONS_ARB FP
+// 0x880B MAX_PROGRAM_ALU_INSTRUCTIONS_ARB FP
+// 0x8808 PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB FP
+// 0x880E MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB FP
+
+// 0x8806 PROGRAM_TEX_INSTRUCTIONS_ARB FP
+// 0x880C MAX_PROGRAM_TEX_INSTRUCTIONS_ARB FP
+// 0x8809 PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB FP
+// 0x880F MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB FP
+
+// 0x8807 PROGRAM_TEX_INDIRECTIONS_ARB FP
+// 0x880D MAX_PROGRAM_TEX_INDIRECTIONS_ARB FP
+// 0x880A PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB FP
+// 0x8810 MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB FP
+
+struct GLMShaderLimitDesc
+{
+ GLenum m_valueEnum;
+ GLenum m_limitEnum;
+ const char *m_debugName;
+ const char m_flags;
+ // m_flags - 0x01 for VP, 0x02 for FP, or set both if applicable to both
+};
+
+// macro to help make the table of what to check
+#ifndef LMD
+#define LMD( val, flags ) { GL_PROGRAM_##val##_ARB, GL_MAX_PROGRAM_##val##_ARB, #val, flags }
+#else
+#error you need to use a different name for this macro.
+#endif
+
+GLMShaderLimitDesc g_glmShaderLimitDescs[] =
+{
+ // VP and FP..
+ LMD( INSTRUCTIONS, 3 ),
+ LMD( NATIVE_INSTRUCTIONS, 3 ),
+ LMD( NATIVE_TEMPORARIES, 3 ),
+ LMD( PARAMETERS, 3 ),
+ LMD( NATIVE_PARAMETERS, 3 ),
+ LMD( ATTRIBS, 3 ),
+ LMD( NATIVE_ATTRIBS, 3 ),
+
+ // VP only..
+ LMD( ADDRESS_REGISTERS, 1 ),
+ LMD( NATIVE_ADDRESS_REGISTERS, 1 ),
+
+ // FP only..
+ LMD( ALU_INSTRUCTIONS, 2 ),
+ LMD( NATIVE_ALU_INSTRUCTIONS, 2 ),
+ LMD( TEX_INSTRUCTIONS, 2 ),
+ LMD( NATIVE_TEX_INSTRUCTIONS, 2 ),
+ LMD( TEX_INDIRECTIONS, 2 ),
+ LMD( NATIVE_TEX_INDIRECTIONS, 2 ),
+
+ { 0, 0, NULL, 0 }
+};
+
+#undef LMD
+
+bool CGLMProgram::CheckValidity( EGLMProgramLang lang )
+{
+ static const char *targnames[] = { "vertex", "fragment" };
+
+ switch(lang)
+ {
+ case kGLMARB:
+ {
+ GLMShaderDesc *arbDesc;
+ arbDesc = &m_descs[ kGLMARB ];
+
+ GLenum arbTarget = GLMProgTypeToARBEnum( m_type );
+
+ Assert( arbDesc->m_compiled );
+
+ arbDesc->m_valid = true; // assume success til we see otherwise
+
+ // assume program is bound. is there anything wrong with it ?
+
+ GLint isNative=0;
+ glGetProgramivARB( arbTarget, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative );
+ GLMCheckError();
+
+ // If the program is over the hardware's limits, print out some information
+ if (isNative!=1)
+ {
+ arbDesc->m_valid = false;
+
+ // check everything we can check
+ char checkmask = (1<m_valueEnum !=0; desc++ )
+ {
+ if ( desc->m_flags & checkmask )
+ {
+ // test it
+ GLint value = 0;
+ GLint limit = 0;
+ glGetProgramivARB(arbTarget, desc->m_valueEnum, &value);
+ GLMCheckError();
+
+ glGetProgramivARB(arbTarget, desc->m_limitEnum, &limit);
+ GLMCheckError();
+
+ if (value > limit)
+ {
+ GLMPRINTF(("-D- Invalid %s program: program has %d %s; limit is %d", targnames[ m_type ], value, desc->m_debugName, limit ));
+ }
+ }
+ }
+ }
+
+ // syntax error check
+ GLint errorLine;
+ glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errorLine );
+ GLMCheckError();
+
+ if ( errorLine!=-1 )
+ {
+ const GLubyte* errorString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
+ GLMPRINTF(( "-D- Syntax error in ARB %s program: %s",targnames[ m_type ], errorString ));
+ arbDesc->m_valid = false;
+ }
+ if (!arbDesc->m_valid)
+ {
+ char *temp = strdup(m_text);
+ temp[ arbDesc->m_textOffset + arbDesc->m_textLength ] = 0;
+ GLMPRINTF(("-D- ----- ARB compile failed; bad source follows -----" ));
+ GLMPRINTTEXT(( temp + arbDesc->m_textOffset, eDebugDump, GLMPRINTTEXT_NUMBEREDLINES ));
+ GLMPRINTF(("-D- -----end-----" ));
+ free( temp );
+ }
+
+ return arbDesc->m_valid;
+ }
+ break;
+
+ case kGLMGLSL:
+ {
+ GLMShaderDesc *glslDesc;
+ glslDesc = &m_descs[ kGLMGLSL ];
+
+ GLenum glslStage = GLMProgTypeToGLSLEnum( m_type );
+
+ Assert( glslDesc->m_compiled );
+
+ glslDesc->m_valid = true; // assume success til we see otherwise
+
+ // GLSL error check
+ int compiled = 0, length = 0, laux = 0;
+
+ glGetObjectParameterivARB( (GLhandleARB)glslDesc->m_object.glsl, GL_OBJECT_COMPILE_STATUS_ARB, &compiled);
+ glGetObjectParameterivARB( (GLhandleARB)glslDesc->m_object.glsl, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
+ GLcharARB *logString = (GLcharARB *)malloc(length * sizeof(GLcharARB));
+ glGetInfoLogARB((GLhandleARB)glslDesc->m_object.glsl, length, &laux, logString);
+
+ // we may not be able to check "native limits" stuff until link time. meh
+
+ if (!compiled)
+ {
+ glslDesc->m_valid = false;
+ }
+
+ if (!glslDesc->m_valid)
+ {
+ char *temp = strdup(m_text);
+ temp[ glslDesc->m_textOffset + glslDesc->m_textLength ] = 0;
+ GLMPRINTF(("-D- ----- GLSL compile failed: \n %s \n",logString ));
+ GLMPRINTTEXT(( temp + glslDesc->m_textOffset, eDebugDump, GLMPRINTTEXT_NUMBEREDLINES ));
+ GLMPRINTF(("-D- -----end-----" ));
+ free( temp );
+ }
+
+ free( logString );
+
+ return glslDesc->m_valid;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void CGLMProgram::LogSlow( EGLMProgramLang lang )
+{
+ // find the desc, see if it's marked
+ GLMShaderDesc *desc = &m_descs[ lang ];
+
+ if (!desc->m_slowMark)
+ {
+ // log it
+ printf( "\n-------------- Slow %s ( CGLMProgram @ %p, lang %s, name %d ) : \n%s \n",
+ m_type==kGLMVertexProgram ? "VS" : "FS",
+ this,
+ lang==kGLMGLSL ? "GLSL" : "ARB",
+ (int)(uintptr_t)(lang==kGLMGLSL ? (uintptr_t)desc->m_object.glsl : (uintptr_t)desc->m_object.arb),
+ m_text
+ );
+ }
+ else // complain on a decreasing basis (powers of two)
+ {
+ if ( (desc->m_slowMark & (desc->m_slowMark-1)) == 0 )
+ {
+ // short blurb
+ printf( "\n Slow %s ( CGLMProgram @ %p, lang %s, name %d ) (%d times)",
+ m_type==kGLMVertexProgram ? "VS" : "FS",
+ this,
+ lang==kGLMGLSL ? "GLSL" : "ARB",
+ (int)(lang==kGLMGLSL ? (uintptr_t)desc->m_object.glsl : (uintptr_t)desc->m_object.arb),
+ desc->m_slowMark+1
+ );
+ }
+ }
+
+ // mark it
+ desc->m_slowMark++;
+
+
+}
+
+void CGLMProgram::GetLabelIndexCombo ( char *labelOut, int labelOutMaxChars, int *indexOut, int *comboOut )
+{
+ // find the label string
+ // example:
+ // trans#2871 label:vs-file vertexlit_and_unlit_generic_vs20 vs-index 294912 vs-combo 1234
+
+ *labelOut = 0;
+ *indexOut = -1;
+
+ char *lineStr = strstr( m_text, "// trans#" );
+ if (lineStr)
+ {
+ char temp1[1024];
+ int temp2,temp3;
+ int scratch=-1;
+ temp1[0] = 0;
+ temp2 = -1;
+ temp3 = -1;
+
+ if (this->m_type==kGLMVertexProgram)
+ {
+ sscanf( lineStr, "// trans#%d label:vs-file %s vs-index %d vs-combo %d", &scratch, temp1, &temp2, &temp3 );
+ }
+ else
+ {
+ sscanf( lineStr, "// trans#%d label:ps-file %s ps-index %d ps-combo %d", &scratch, temp1, &temp2, &temp3 );
+ }
+
+ if ( (strlen(temp1)!=0) )
+ {
+ strncpy( labelOut, temp1, labelOutMaxChars );
+ *indexOut = temp2;
+ *comboOut = temp3;
+ }
+ }
+}
+
+void CGLMProgram::GetComboIndexNameString ( char *stringOut, int stringOutMaxChars ) // mmmmmmmm-nnnnnnnn-filename
+{
+ // find the label string
+ // example:
+ // trans#2871 label:vs-file vertexlit_and_unlit_generic_vs20 vs-index 294912 vs-combo 1234
+
+ *stringOut = 0;
+
+ char *lineStr = strstr( m_text, "// trans#" );
+ if (lineStr)
+ {
+ char temp1[1024];
+ int temp2,temp3;
+ int scratch=-1;
+
+ temp1[0] = 0;
+ temp2 = -1;
+ temp3 = -1;
+
+ if (this->m_type==kGLMVertexProgram)
+ {
+ sscanf( lineStr, "// trans#%d label:vs-file %s vs-index %d vs-combo %d", &scratch, temp1, &temp2, &temp3 );
+ }
+ else
+ {
+ sscanf( lineStr, "// trans#%d label:ps-file %s ps-index %d ps-combo %d", &scratch, temp1, &temp2, &temp3 );
+ }
+
+ int len = strlen(temp1);
+
+ if ( (len+20) < stringOutMaxChars )
+ {
+ // output formatted version
+ sprintf( stringOut, "%08X-%08X-%s", temp3, temp2, temp1 );
+ }
+ }
+}
+
+//===============================================================================
+
+
+CGLMShaderPair::CGLMShaderPair( GLMContext *ctx )
+{
+ m_ctx = ctx;
+ m_ctx->MakeCurrent();
+
+ m_vertexProg = m_fragmentProg = NULL;
+
+ m_program = glCreateProgramObjectARB();
+ GLMCheckError();
+
+ m_locVertexParams = -1;
+ m_locVertexInteger0 = -1; // "i0"
+ m_locVertexBool0 = -1; // "b0"
+ m_locVertexBool1 = -1; // "b1"
+ m_locVertexBool2 = -1; // "b2"
+ m_locVertexBool3 = -1; // "b3"
+
+ m_locFragmentParams = -1;
+ m_locFragmentFakeSRGBEnable = -1;
+ m_fakeSRGBEnableValue = -1.0f;
+
+ memset( m_locSamplers, 0xFF, sizeof( m_locSamplers ) );
+
+ m_valid = false;
+ m_samplersFixed = false; // fix them at draw time, and only do it once.
+ m_revision = 0; // bumps to 1 once linked
+}
+
+CGLMShaderPair::~CGLMShaderPair( )
+{
+ if (m_program)
+ {
+ glDeleteObjectARB( (GLhandleARB)m_program );
+ m_program = 0;
+ }
+}
+
+bool CGLMShaderPair::SetProgramPair ( CGLMProgram *vp, CGLMProgram *fp )
+{
+ m_valid = false; // assume failure
+
+ // true result means successful link and query
+ bool vpgood = (vp!=NULL) && (vp->m_descs[ kGLMGLSL ].m_valid);
+ bool fpgood = (fp!=NULL) && (fp->m_descs[ kGLMGLSL ].m_valid);
+
+ if (!fpgood)
+ {
+ // fragment side allowed to be "null".
+ fp = m_ctx->m_nullFragmentProgram;
+ }
+
+ if (vpgood && fpgood)
+ {
+ // attempt link. but first, detach any previously attached programs
+ if (m_vertexProg)
+ {
+ glDetachObjectARB(m_program, m_vertexProg->m_descs[kGLMGLSL].m_object.glsl);
+ GLMCheckError();
+ m_vertexProg = NULL;
+ }
+
+ if (m_fragmentProg)
+ {
+ glDetachObjectARB(m_program, m_fragmentProg->m_descs[kGLMGLSL].m_object.glsl);
+ GLMCheckError();
+ m_fragmentProg = NULL;
+ }
+
+ // now attach
+
+ glAttachObjectARB(m_program, vp->m_descs[kGLMGLSL].m_object.glsl);
+ m_vertexProg = vp;
+ GLMCheckError();
+
+ glAttachObjectARB(m_program, fp->m_descs[kGLMGLSL].m_object.glsl);
+ m_fragmentProg = fp;
+ GLMCheckError();
+
+ // force the locations for input attributes v0-vN to be at locations 0-N
+ // use the vertex attrib map to know which slots are live or not... oy! we don't have that map yet... but it's OK.
+ // fallback - just force v0-v15 to land in locations 0-15 as a standard.
+
+ if (vp->m_descs[kGLMGLSL].m_valid)
+ {
+ for( int i=0; i < 16; i++)
+ {
+ char tmp[16];
+ sprintf(tmp, "v%d", i); // v0 v1 v2 ... et al
+
+ glBindAttribLocationARB( m_program, i, tmp );
+ GLMCheckError();
+ }
+ }
+
+ // now link
+ glLinkProgramARB( m_program );
+ GLMCheckError();
+
+ // check for success
+ GLint result = 0;
+ glGetObjectParameterivARB(m_program,GL_OBJECT_LINK_STATUS_ARB,&result); // want GL_TRUE
+
+ if (result == GL_TRUE)
+ {
+ // success
+
+ m_valid = true;
+ m_revision++;
+ }
+ else
+ {
+ GLint length = 0;
+ GLint laux = 0;
+
+ // do some digging
+ glGetObjectParameterivARB(m_program,GL_OBJECT_INFO_LOG_LENGTH_ARB,&length);
+
+ GLcharARB *logString = (GLcharARB *)malloc(length * sizeof(GLcharARB));
+ glGetInfoLogARB(m_program, length, &laux, logString);
+
+ char *vtemp = strdup(vp->m_text);
+ vtemp[ vp->m_descs[kGLMGLSL].m_textOffset + vp->m_descs[kGLMGLSL].m_textLength ] = 0;
+
+ char *ftemp = strdup(fp->m_text);
+ ftemp[ fp->m_descs[kGLMGLSL].m_textOffset + fp->m_descs[kGLMGLSL].m_textLength ] = 0;
+
+ GLMPRINTF(("-D- ----- GLSL link failed: \n %s ",logString ));
+
+ GLMPRINTF(("-D- ----- GLSL vertex program selected: %08x (handle %08x)", vp, vp->m_descs[kGLMGLSL].m_object.glsl ));
+ GLMPRINTTEXT(( vtemp + vp->m_descs[kGLMGLSL].m_textOffset, eDebugDump, GLMPRINTTEXT_NUMBEREDLINES ));
+
+ GLMPRINTF(("-D- ----- GLSL fragment program selected: %08x (handle %08x)", fp, vp->m_descs[kGLMGLSL].m_object.glsl ));
+ GLMPRINTTEXT(( ftemp + fp->m_descs[kGLMGLSL].m_textOffset, eDebugDump, GLMPRINTTEXT_NUMBEREDLINES ));
+
+ GLMPRINTF(("-D- -----end-----" ));
+
+ free( ftemp );
+ free( vtemp );
+ free( logString );
+ }
+ }
+ else
+ {
+ // fail
+ Assert(!"Can't link these programs");
+ }
+
+ if (m_valid)
+ {
+ m_locVertexParams = glGetUniformLocationARB( m_program, "vc");
+ GLMCheckError();
+
+ m_locVertexInteger0 = glGetUniformLocationARB( m_program, "i0");
+ GLMCheckError();
+
+ m_locVertexBool0 = glGetUniformLocationARB( m_program, "b0");
+ GLMCheckError();
+ m_locVertexBool1 = glGetUniformLocationARB( m_program, "b1");
+ GLMCheckError();
+ m_locVertexBool2 = glGetUniformLocationARB( m_program, "b2");
+ GLMCheckError();
+ m_locVertexBool3 = glGetUniformLocationARB( m_program, "b3");
+ GLMCheckError();
+
+ m_locFragmentParams = glGetUniformLocationARB( m_program, "pc");
+ GLMCheckError();
+
+ m_locFragmentFakeSRGBEnable = glGetUniformLocationARB( m_program, "flSRGBWrite");
+ GLMCheckError();
+ m_fakeSRGBEnableValue = -1.0f;
+
+ for( int sampler=0; sampler<16; sampler++)
+ {
+ char tmp[16];
+ sprintf(tmp, "sampler%d", sampler); // sampler0 .. sampler1.. etc
+
+ m_locSamplers[sampler] = glGetUniformLocationARB( m_program, tmp );
+ GLMCheckError();
+ }
+ }
+ else
+ {
+ m_locVertexParams = -1;
+
+ m_locVertexInteger0 = -1;
+ m_locVertexBool0 = -1;
+ m_locVertexBool1 = -1;
+ m_locVertexBool2 = -1;
+ m_locVertexBool3 = -1;
+
+ m_locFragmentParams = -1;
+ m_locFragmentFakeSRGBEnable = -1;
+ m_fakeSRGBEnableValue = -999;
+
+ memset( m_locSamplers, 0xFF, sizeof( m_locSamplers ) );
+
+ m_revision = 0;
+ }
+
+ return m_valid;
+}
+
+
+bool CGLMShaderPair::RefreshProgramPair ( void )
+{
+ // re-link and re-query the uniforms.
+
+ // since SetProgramPair knows how to detach previously attached shader objects, just pass the same ones in again.
+ CGLMProgram *vp = m_vertexProg;
+ CGLMProgram *fp = m_fragmentProg;
+
+ bool vpgood = (vp!=NULL) && (vp->m_descs[ kGLMGLSL ].m_valid);
+ bool fpgood = (fp!=NULL) && (fp->m_descs[ kGLMGLSL ].m_valid);
+
+ if (vpgood && fpgood)
+ {
+ return SetProgramPair( vp, fp );
+ }
+ else
+ {
+ Debugger();
+ return false;
+ }
+}
+
+
+//===============================================================================
+
+CGLMShaderPairCache::CGLMShaderPairCache( GLMContext *ctx )
+{
+ m_ctx = ctx;
+
+ m_mark = 1;
+
+ m_rowsLg2 = gl_shaderpair_cacherows_lg2/* .GetInt() */;
+ if (m_rowsLg2 < 10)
+ m_rowsLg2 = 10;
+ m_rows = 1<Purge();
+ Assert( !purgeResult );
+
+ if (m_entries)
+ {
+ free( m_entries );
+ m_entries = NULL;
+ }
+
+ if (m_evictions)
+ {
+ free( m_evictions );
+ m_evictions = NULL;
+ }
+
+ if (m_hits)
+ {
+ free( m_hits );
+ m_hits = NULL;
+ }
+}
+
+
+#if 0 //turning off all the shader pair caching stuff for simplicity
+
+// Set this convar internally to build or add to the shader pair cache file (link hints)
+// We really only expect this to work on POSIX
+static ConVar glm_cacheprograms( "glm_cacheprograms", "0", FCVAR_DEVELOPMENTONLY );
+
+#define PROGRAM_CACHE_FILE "program_cache.cfg"
+
+static void WriteToProgramCache( CGLMShaderPair *pair )
+{
+ KeyValues *pProgramCache = new KeyValues( "programcache" );
+ pProgramCache->LoadFromFile( g_pFullFileSystem, PROGRAM_CACHE_FILE, "MOD" );
+
+ if ( !pProgramCache )
+ {
+ Warning( "Could not write to program cache file!\n" );
+ return;
+ }
+
+ // extract values of interest which represent a pair of shaders
+
+ char vprogramName[128];
+ int vprogramStaticIndex = -1;
+ int vprogramDynamicIndex = -1;
+ pair->m_vertexProg->GetLabelIndexCombo( vprogramName, sizeof(vprogramName), &vprogramStaticIndex, &vprogramDynamicIndex );
+
+
+ char pprogramName[128];
+ int pprogramStaticIndex = -1;
+ int pprogramDynamicIndex = -1;
+ pair->m_fragmentProg->GetLabelIndexCombo( pprogramName, sizeof(pprogramName), &pprogramStaticIndex, &pprogramDynamicIndex );
+
+ // make up a key - this thing is really a list of tuples, so need not be keyed by anything particular
+ KeyValues *pProgramKey = pProgramCache->CreateNewKey();
+ Assert( pProgramKey );
+
+ pProgramKey->SetString ( "vs", vprogramName );
+ pProgramKey->SetString ( "ps", pprogramName );
+
+ pProgramKey->SetInt ( "vs_static", vprogramStaticIndex );
+ pProgramKey->SetInt ( "ps_static", pprogramStaticIndex );
+
+ pProgramKey->SetInt ( "vs_dynamic", vprogramDynamicIndex );
+ pProgramKey->SetInt ( "ps_dynamic", pprogramDynamicIndex );
+
+ pProgramCache->SaveToFile( g_pFullFileSystem, PROGRAM_CACHE_FILE, "MOD" );
+ pProgramCache->deleteThis();
+}
+#endif
+
+
+CGLMShaderPair *CGLMShaderPairCache::SelectShaderPair( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits )
+{
+ CGLMShaderPair *result = NULL;
+
+ int loglevel = gl_shaderpair_cachelog/* .GetInt() */;
+ char vtempname[128];
+ int vtempindex = -1;
+ int vtempcombo = -1;
+
+ char ptempname[128];
+ int ptempindex = -1;
+ int ptempcombo = -1;
+
+
+ // select row where pair would be found if it exists
+ uint rowIndex = HashRowIndex( vp, fp, extraKeyBits );
+
+ CGLMPairCacheEntry *row = HashRowPtr( rowIndex );
+
+ // probe row and see if we get a hit
+ int hitway = -1;int emptyway = -1; int oldestway = -1;
+
+ HashRowProbe( row, vp, fp, extraKeyBits, &hitway, &emptyway, &oldestway );
+
+ if (hitway >=0)
+ {
+ // found it. mark it and return
+ CGLMPairCacheEntry *hit = row + hitway;
+ hit->m_lastMark = m_mark;
+
+ m_mark = m_mark+1;
+ if (!m_mark) // somewhat unlikely this will ever be reached.. but we need to avoid zero as a mark value
+ {
+ m_mark = 1;
+ }
+
+ // count the hit
+ m_hits[ rowIndex ] ++;
+
+ if (loglevel >= 3) // hits logged at level 3 and higher
+ {
+ printf("\nSSP: hit - row %05d - pair $%p (%d'th hit on row)",rowIndex, hit->m_pair, m_hits[ rowIndex ] );
+ }
+
+ result = hit->m_pair;
+ }
+ else
+ {
+ // we missed. if there is no empty way, then somebody's getting evicted.
+ int destway = -1;
+
+ if (emptyway>=0)
+ {
+ destway = emptyway;
+
+ if (loglevel >= 2) // misses logged at level 3 and higher
+ {
+ printf("\nSSP: miss - row %05d - ", rowIndex );
+ }
+ }
+ else
+ {
+ // evict the oldest way
+ Assert( oldestway >= 0); // better not come back negative
+
+ CGLMPairCacheEntry *evict = row + oldestway;
+
+ Assert( evict->m_pair != NULL );
+ Assert( evict->m_pair != m_ctx->m_boundPair ); // just check
+
+ ///////////////////////FIXME may need to do a shoot-down if the pair being evicted is currently active in the context
+
+ m_evictions[ rowIndex ]++;
+
+ // log eviction if desired
+ if (loglevel >= 2) // misses logged at level 3 and higher
+ {
+ //evict->m_vertexProg->GetLabelIndexCombo( vtempname, sizeof(vtempname), &vtempindex, &vtempcombo );
+ //evict->m_fragmentProg->GetLabelIndexCombo( ptempname, sizeof(ptempname), &ptempindex, &ptempcombo );
+ //printf("\nSSP: miss - row %05d - [ %s/%d/%d %s/%d/%d ]'s %d'th eviction - ", rowIndex, vtempname, vtempindex, vtempcombo, ptempname, ptempindex, ptempcombo, m_evictions[ rowIndex ] );
+
+ evict->m_vertexProg->GetComboIndexNameString( vtempname, sizeof(vtempname) );
+ evict->m_fragmentProg->GetComboIndexNameString( ptempname, sizeof(ptempname) );
+ printf("\nSSP: miss - row %05d - [ %s + %s ]'s %d'th eviction - ", rowIndex, vtempname, ptempname, m_evictions[ rowIndex ] );
+ }
+
+ delete evict->m_pair; evict->m_pair = NULL;
+ memset( evict, 0, sizeof(*evict) );
+
+ destway = oldestway;
+ }
+
+ // make the new entry
+ CGLMPairCacheEntry *newentry = row + destway;
+
+ newentry->m_lastMark = m_mark;
+ newentry->m_vertexProg = vp;
+ newentry->m_fragmentProg = fp;
+ newentry->m_extraKeyBits = extraKeyBits;
+ newentry->m_pair = new CGLMShaderPair( m_ctx );
+ newentry->m_pair->SetProgramPair( vp, fp );
+
+ if (loglevel >= 2) // say a little bit more
+ {
+ //newentry->m_vertexProg->GetLabelIndexCombo( vtempname, sizeof(vtempname), &vtempindex, &vtempcombo );
+ //newentry->m_fragmentProg->GetLabelIndexCombo( ptempname, sizeof(ptempname), &ptempindex, &ptempcombo );
+ //printf("new [ %s/%d/%d %s/%d/%d ]", vtempname, vtempindex, vtempcombo, ptempname, ptempindex, ptempcombo );
+
+ newentry->m_vertexProg->GetComboIndexNameString( vtempname, sizeof(vtempname) );
+ newentry->m_fragmentProg->GetComboIndexNameString( ptempname, sizeof(ptempname) );
+ printf("new [ %s + %s ]", vtempname, ptempname );
+ }
+
+ m_mark = m_mark+1;
+ if (!m_mark) // somewhat unlikely this will ever be reached.. but we need to avoid zero as a mark value
+ {
+ m_mark = 1;
+ }
+
+ result = newentry->m_pair;
+
+ /*
+ if (glm_cacheprograms.GetInt())
+ {
+ WriteToProgramCache( newentry->m_pair );
+ }
+ */
+ }
+
+ return result;
+}
+
+void CGLMShaderPairCache::QueryShaderPair( int index, GLMShaderPairInfo *infoOut )
+{
+ if ( (index<0) || ( index >= (m_rows*m_ways) ) )
+ {
+ // no such location
+ memset( infoOut, 0, sizeof(*infoOut) );
+
+ infoOut->m_status = -1;
+ }
+ else
+ {
+ // locate the entry, and see if an active pair is present.
+ // if so, extract info and return with m_status=1.
+ // if not, exit with m_status = 0.
+
+ CGLMPairCacheEntry *entry = &m_entries[index];
+
+ if (entry->m_pair)
+ {
+ // live
+ // extract values of interest for caller
+
+ entry->m_pair->m_vertexProg->GetLabelIndexCombo ( infoOut->m_vsName, sizeof(infoOut->m_vsName), &infoOut->m_vsStaticIndex, &infoOut->m_vsDynamicIndex );
+ entry->m_pair->m_fragmentProg->GetLabelIndexCombo ( infoOut->m_psName, sizeof(infoOut->m_psName), &infoOut->m_psStaticIndex, &infoOut->m_psDynamicIndex );
+
+ infoOut->m_status = 1;
+ }
+ else
+ {
+ // not
+ memset( infoOut, 0, sizeof(*infoOut) );
+ infoOut->m_status = 0;
+ }
+ }
+}
+
+bool CGLMShaderPairCache::PurgePairsWithShader( CGLMProgram *prog )
+{
+ bool result = false;
+
+ // walk all rows*ways
+ int limit = m_rows * m_ways;
+ for( int i=0; i < limit; i++)
+ {
+ CGLMPairCacheEntry *entry = &m_entries[i];
+
+ if (entry->m_pair)
+ {
+ //scrub it, if not currently bound, and if the supplied shader matches either stage
+ if ( (entry->m_vertexProg==prog) || (entry->m_fragmentProg==prog) )
+ {
+ // found it, but does it conflict with bound pair ?
+ if (entry->m_pair == m_ctx->m_boundPair)
+ {
+ m_ctx->m_boundPair = NULL;
+ }
+ delete entry->m_pair;
+ memset( entry, 0, sizeof(*entry) );
+ }
+ }
+ }
+ return result;
+}
+
+bool CGLMShaderPairCache::Purge( void )
+{
+ bool result = false;
+
+ // walk all rows*ways
+ int limit = m_rows * m_ways;
+ for( int i=0; i < limit; i++)
+ {
+ CGLMPairCacheEntry *entry = &m_entries[i];
+
+ if (entry->m_pair)
+ {
+ //scrub it, unless the pair is the currently bound pair in our parent glm context
+ if (entry->m_pair != m_ctx->m_boundPair)
+ {
+ delete entry->m_pair;
+ memset( entry, 0, sizeof(*entry) );
+ }
+ else
+ {
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+
+void CGLMShaderPairCache::DumpStats ( void )
+{
+ printf("\n------------------\npair cache stats");
+ int total = 0;
+ for( int row=0; row < m_rows; row++ )
+ {
+ if ( (m_evictions[row] != 0) || (m_hits[row] != 0) )
+ {
+ printf("\n row %d : %d evictions, %d hits",row,m_evictions[row], m_hits[row]);
+ total += m_evictions[row];
+ }
+ }
+ printf("\n\npair cache evictions: %d\n-----------------------\n",total );
+}
+
+ //===============================
+
+uint CGLMShaderPairCache::HashRowIndex ( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits )
+{
+ // calculate row index for this pair
+ uint vp_hash = vp->m_serial * 47;
+ uint fp_hash = fp->m_serial;
+
+ uint hash_row_index = ((vp_hash * fp_hash) + (vp_hash ^ fp_hash) + (extraKeyBits * 7) ) & (m_rows-1);
+
+ return hash_row_index;
+}
+
+CGLMPairCacheEntry* CGLMShaderPairCache::HashRowPtr ( uint hashRowIndex )
+{
+ return &m_entries[ hashRowIndex * m_ways ];
+}
+
+void CGLMShaderPairCache::HashRowProbe ( CGLMPairCacheEntry *row, CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits, int *hitwayOut, int *emptywayOut, int *oldestwayOut )
+{
+ // scan this row to see if the desired pair is present
+ CGLMPairCacheEntry *cursor = row;
+ int hitway = -1;
+ int emptyway = -1;
+ int oldestway = -1;
+ long long oldestmark = 0xFFFFFFFFFFFFFFFFLL;
+
+ for( int way = 0; (way < m_ways) && (hitway<0); way++)
+ {
+ if (cursor->m_lastMark != 0) // occupied slot
+ {
+ if ( (cursor->m_vertexProg == vp) && (cursor->m_fragmentProg == fp) && (cursor->m_extraKeyBits == extraKeyBits) ) // match?
+ {
+ // found it
+ hitway = way;
+ }
+
+ // check if this is the oldest one on the row - only occupied slots are checked
+ if (cursor->m_lastMark < oldestmark)
+ {
+ oldestway = way;
+ oldestmark = cursor->m_lastMark;
+ }
+ }
+ else
+ {
+ // empty way, log it if first one seen
+ if (emptyway<0)
+ {
+ emptyway = way;
+ }
+ }
+ cursor++;
+ }
+
+ if (hitwayOut) *hitwayOut = hitway;
+ if (emptywayOut) *emptywayOut = emptyway;
+ if (oldestwayOut) *oldestwayOut = oldestway;
+}
+
diff --git a/My project/sdk/glmgr/cglmprogram.h b/My project/sdk/glmgr/cglmprogram.h
new file mode 100644
index 000000000..cadd2208b
--- /dev/null
+++ b/My project/sdk/glmgr/cglmprogram.h
@@ -0,0 +1,291 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmprogram.h
+// GLMgr programs (ARBVP/ARBfp)
+//
+//===============================================================================
+
+#ifndef CGLMPROGRAM_H
+#define CGLMPROGRAM_H
+
+#include
+
+#pragma once
+
+// good ARB program references
+// http://petewarden.com/notes/archives/2005/05/fragment_progra_2.html
+// http://petewarden.com/notes/archives/2005/06/fragment_progra_3.html
+
+// ext links
+
+// http://www.opengl.org/registry/specs/ARB/vertex_program.txt
+// http://www.opengl.org/registry/specs/ARB/fragment_program.txt
+// http://www.opengl.org/registry/specs/EXT/gpu_program_parameters.txt
+
+
+//===============================================================================
+
+// tokens not in the SDK headers
+
+//#ifndef GL_DEPTH_STENCIL_ATTACHMENT_EXT
+// #define GL_DEPTH_STENCIL_ATTACHMENT_EXT 0x84F9
+//#endif
+
+//===============================================================================
+
+// forward declarations
+
+class GLMContext;
+class CGLMShaderPair;
+class CGLMShaderPairCache;
+
+// CGLMProgram can contain two flavors of the same program, one in assembler, one in GLSL.
+// these flavors are pretty different in terms of the API's that are used to activate them -
+// for example, assembler programs can just get bound to the context, whereas GLSL programs
+// have to be linked. To some extent we try to hide that detail inside GLM.
+
+// for now, make CGLMProgram a container, it does not set policy or hold a preference as to which
+// flavor you want to use. GLMContext has to handle that.
+
+enum EGLMProgramType
+{
+ kGLMVertexProgram,
+ kGLMFragmentProgram,
+
+ kGLMNumProgramTypes
+};
+
+enum EGLMProgramLang
+{
+ kGLMARB,
+ kGLMGLSL,
+
+ kGLMNumProgramLangs
+};
+
+struct GLMShaderDesc
+{
+ union
+ {
+ GLuint arb; // ARB program object name
+ GLhandleARB glsl; // GLSL shader object handle (void*)
+ } m_object;
+
+ // these can change if shader text is edited
+ bool m_textPresent; // is this flavor(lang) of text present in the buffer?
+ int m_textOffset; // where is it
+ int m_textLength; // how big
+
+ bool m_compiled; // has this text been through a compile attempt
+ bool m_valid; // and if so, was the compile successful
+
+ int m_slowMark; // has it been flagged during a non native draw batch before. increment every time it's slow.
+
+ int m_highWater; // vount of vec4's in the major uniform array ("vc" on vs, "pc" on ps)
+ // written by dxabstract.... gross!
+};
+
+GLenum GLMProgTypeToARBEnum( EGLMProgramType type ); // map vert/frag to ARB asm bind target
+GLenum GLMProgTypeToGLSLEnum( EGLMProgramType type ); // map vert/frag to ARB asm bind target
+
+class CGLMProgram
+{
+public:
+ friend class CGLMShaderPairCache;
+ friend class CGLMShaderPair;
+ friend class GLMContext; // only GLMContext can make CGLMProgram objects
+ friend class GLMTester;
+ friend struct IDirect3D9;
+ friend struct IDirect3DDevice9;
+
+ //===============================
+
+ // constructor is very light, it just makes one empty program object per flavor.
+ CGLMProgram( GLMContext *ctx, EGLMProgramType type );
+ ~CGLMProgram( );
+
+ void SetProgramText ( char *text ); // import text to GLM object - invalidate any prev compiled program
+
+ bool CompileActiveSources ( void ); // compile only the flavors that were provided.
+ bool Compile ( EGLMProgramLang lang );
+ bool CheckValidity ( EGLMProgramLang lang );
+
+ void LogSlow ( EGLMProgramLang lang ); // detailed spew when called for first time; one liner or perhaps silence after that
+
+ void GetLabelIndexCombo ( char *labelOut, int labelOutMaxChars, int *indexOut, int *comboOut );
+ void GetComboIndexNameString ( char *stringOut, int stringOutMaxChars ); // mmmmmmmm-nnnnnnnn-filename
+
+#if GLMDEBUG
+ bool PollForChanges( void ); // check mirror for changes.
+ void ReloadStringFromEditable( void ); // populate m_string from editable item (react to change)
+ bool SyncWithEditable( void );
+#endif
+
+ //===============================
+
+ // common stuff
+
+ GLMContext *m_ctx; // link back to parent context
+
+ EGLMProgramType m_type; // vertex or pixel
+
+ uint m_serial; // serial number for hashing
+
+ char *m_text; // copy of text passed into constructor. Can change if editable shaders is enabled.
+ // note - it can contain multiple flavors, so use CGLMTextSectioner to scan it and locate them
+#if GLMDEBUG
+ CGLMEditableTextItem *m_editable; // editable text item for debugging
+#endif
+
+ GLMShaderDesc m_descs[ kGLMNumProgramLangs ];
+
+ uint m_samplerMask; // (1<
+
+//===============================================================================
+
+extern int gl_errorcheckall;
+extern int gl_errorcheckqueries;
+extern int gl_errorchecknone;
+
+// how many microseconds to wait after a failed query-available test
+// presently on MTGL this doesn't happen, but it could change, keep this handy
+//ConVar gl_nullqueries( "gl_nullqueries", "0" );
+int gl_nullqueries = 0;
+
+GLenum GetQueryError( void )
+{
+ if ( ( GLMDEBUG || (gl_errorcheckall != 0) || (gl_errorcheckqueries != 0) ) && (gl_errorchecknone == 0) )
+ {
+ return glGetError();
+ }
+ else
+ {
+ return (GLenum) 0; // whistle past graveyard
+ }
+}
+
+//===============================================================================
+
+CGLMQuery::CGLMQuery( GLMContext *ctx, GLMQueryParams *params )
+{
+ // make sure context is current
+ // get the type of query requested
+ // generate name(s) needed
+ // set initial state appropriately
+ ctx->MakeCurrent();
+
+ m_ctx = ctx;
+ m_params = *params;
+
+ m_name = 0;
+
+ m_started = m_stopped = m_done = false;
+
+ m_nullQuery = false;
+ // assume value of convar at start time
+ // does not change during individual query lifetime
+ // started null = stays null
+ // started live = stays live
+
+ switch(m_params.m_type)
+ {
+ case EOcclusion:
+ {
+ //make an occlusion query (and a fence to go with it)
+ glGenQueriesARB( 1, &m_name );
+ GLMPRINTF(("-A- CGLMQuery(OQ) created name %d", m_name));
+
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::CGLMQuery (OQ) saw %s error (%d) from glGenQueriesARB", decodedStr, errorcode );
+ m_name = 0;
+ }
+ }
+ break;
+
+ case EFence:
+ {
+ //make a fence - no aux fence needed
+ glGenFencesAPPLE(1, &m_name );
+ GLMPRINTF(("-A- CGLMQuery(fence) created name %d", m_name));
+
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::CGLMQuery (fence) saw %s error (%d) from glGenFencesAPPLE", decodedStr, errorcode );
+ m_name = 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+CGLMQuery::~CGLMQuery()
+{
+ GLMPRINTF(("-A-> ~CGLMQuery"));
+
+ // make sure query has completed (might not be necessary)
+ // delete the name(s)
+
+ m_ctx->MakeCurrent();
+
+ switch(m_params.m_type)
+ {
+ case EOcclusion:
+ {
+ // do a finish occlusion query ?
+ GLMPRINTF(("-A- ~CGLMQuery(OQ) deleting name %d", m_name));
+ glDeleteQueries(1, &m_name );
+
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::~CGLMQuery (OQ) saw %s error (%d) from glDeleteQueries", decodedStr, errorcode );
+ }
+ }
+ break;
+
+ case EFence:
+ {
+ // do a finish fence ?
+ GLMPRINTF(("-A- ~CGLMQuery(fence) deleting name %d", m_name));
+ glDeleteFencesAPPLE(1, &m_name );
+
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::~CGLMQuery (fence) saw %s error (%d) from glDeleteFencesAPPLE", decodedStr, errorcode );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ m_name = 0;
+
+ GLMPRINTF(("-A-< ~CGLMQuery"));
+}
+
+
+
+
+void CGLMQuery::Start( void ) // "start counting"
+{
+ m_ctx->MakeCurrent();
+
+ // on occlusion query:
+ // glBeginQueryARB on the OQ name. counting starts.
+
+ // on fence: glSetFence on m_name.
+
+ // note, fences finish themselves via command progress - OQ's do not.
+
+ Assert(!m_started);
+ Assert(!m_stopped);
+ Assert(!m_done);
+
+ m_nullQuery = (gl_nullqueries != 0); // latch value for remainder of query life
+
+ switch(m_params.m_type)
+ {
+ case EOcclusion:
+ {
+ if (m_nullQuery)
+ {
+ // do nothing..
+ }
+ else
+ {
+ glBeginQueryARB( GL_SAMPLES_PASSED_ARB, m_name );
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::Start(OQ) saw %s error (%d) from glBeginQueryARB (GL_SAMPLES_PASSED_ARB) name=%d", decodedStr, errorcode, m_name );
+ }
+ }
+ }
+ break;
+
+ case EFence:
+ {
+ glSetFenceAPPLE( m_name );
+
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::Start(fence) saw %s error (%d) from glSetFenceAPPLE name=%d", decodedStr, errorcode, m_name );
+ }
+
+ m_stopped = true; // caller should not call Stop on a fence, it self-stops
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ m_started = true;
+}
+
+void CGLMQuery::Stop( void ) // "stop counting"
+{
+ m_ctx->MakeCurrent();
+
+ Assert(m_started);
+ Assert(!m_stopped); // this will assert if you try to call Stop on a fence that is started
+ Assert(!m_done);
+
+ switch(m_params.m_type)
+ {
+ case EOcclusion:
+ {
+ if (m_nullQuery)
+ {
+ // do nothing..
+ }
+ else
+ {
+ glEndQueryARB( GL_SAMPLES_PASSED_ARB ); // we are only putting the request-to-stop-counting into the cmd stream.
+
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::Stop(OQ) saw %s error (%d) from glEndQueryARB( GL_SAMPLES_PASSED_ARB ) name=%d", decodedStr, errorcode, m_name );
+ }
+ }
+ }
+ break;
+
+ case EFence:
+ {
+ // nop - you don't "end" a fence, you just test it and/or finish it out in Complete
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ m_stopped = true;
+}
+
+bool CGLMQuery::IsDone( void )
+{
+ m_ctx->MakeCurrent();
+
+ Assert(m_started);
+ Assert(m_stopped);
+
+ if(!m_done) // you can ask more than once, but we only check until it comes back as done.
+ {
+ // on occlusion: glGetQueryObjectivARB - large cost on pre SLGU, cheap after
+ // on fence: glTestFenceAPPLE on the fence
+ switch(m_params.m_type)
+ {
+ case EOcclusion: // just test the fence that was set after the query begin
+ {
+ if (m_nullQuery)
+ {
+ // do almost nothing.. but claim work is complete
+ m_done = true;
+ }
+ else
+ {
+ // prepare to pay a big price on drivers prior to 10.6.4+SLGU
+
+ GLint available = 0;
+ glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
+
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::IsDone saw %s error (%d) from glGetQueryObjectivARB(a2) name=%d", decodedStr, errorcode, m_name );
+ }
+
+ m_done = (available != 0);
+ }
+ }
+ break;
+
+ case EFence:
+ {
+ m_done = glTestFenceAPPLE( m_name );
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::IsDone saw %s error (%d) from glTestFenceAPPLE(b) name=%d", decodedStr, errorcode, m_name );
+ }
+
+ if (m_done)
+ {
+ glFinishFenceAPPLE( m_name ); // no set fence goes un-finished
+
+ errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::IsDone saw %s error (%d) from glFinishFenceAPPLE(b) name=%d", decodedStr, errorcode, m_name );
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return m_done;
+}
+
+void CGLMQuery::Complete( uint *result )
+{
+ m_ctx->MakeCurrent();
+
+ uint resultval = 0;
+ GLint available = 0;
+
+ // blocking call if not done
+ Assert(m_started);
+ Assert(m_stopped);
+
+ switch(m_params.m_type)
+ {
+ case EOcclusion:
+ {
+ if (m_nullQuery)
+ {
+ m_done = true;
+ resultval = 0; // we did say "null queries..."
+ }
+ else
+ {
+ // accept that the query is going to drain pipe in 10.6.4 and prior.
+ // check the error on the spot.
+ glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
+ GLenum errorcode = GetQueryError();
+
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::Complete saw %s error (%d) from glGetQueryObjectivARB GL_QUERY_RESULT_AVAILABLE_ARB name=%d", decodedStr, errorcode, m_name );
+
+ resultval=0;
+ }
+ else
+ {
+ if (!available)
+ {
+ // this does happen with some very modest frequency.
+ if (!m_ctx->Caps().m_hasPerfPackage1)
+ {
+ glFlush(); // ISTR some deadlock cases on pre-SLGU drivers if you didn't do this to kick the queue along..
+ }
+ }
+
+ glGetQueryObjectuivARB( m_name, GL_QUERY_RESULT_ARB, &resultval);
+
+ errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::Complete saw %s error (%d) from glGetQueryObjectivARB GL_QUERY_RESULT_ARB name=%d", decodedStr, errorcode, m_name );
+
+ resultval=0;
+ }
+ else
+ {
+ // resultval is legit
+ }
+ }
+ m_done = true;
+ }
+ }
+ break;
+
+ case EFence:
+ {
+ if(!m_done)
+ {
+ glFinishFenceAPPLE( m_name );
+
+ GLenum errorcode = GetQueryError();
+ if (errorcode)
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ printf( "\nCGLMQuery::Complete saw %s error (%d) from glFinishFenceAPPLE (EFence) name=%d", decodedStr, errorcode, m_name );
+ }
+
+ m_done = true; // for clarity or if they try to Complete twice
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ Assert( m_done );
+
+ // reset state for re-use - i.e. you have to call Complete if you want to re-use the object
+ m_started = m_stopped = m_done = false;
+
+ if (result) // caller may pass NULL if not interested in result, for example to clear a fence
+ {
+ *result = resultval;
+ }
+}
+
+
+
+ // accessors for the started/stopped state
+bool CGLMQuery::IsStarted ( void )
+{
+ return m_started;
+}
+
+bool CGLMQuery::IsStopped ( void )
+{
+ return m_stopped;
+}
+
diff --git a/My project/sdk/glmgr/cglmquery.h b/My project/sdk/glmgr/cglmquery.h
new file mode 100644
index 000000000..67c173273
--- /dev/null
+++ b/My project/sdk/glmgr/cglmquery.h
@@ -0,0 +1,84 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmquery.h
+// GLMgr queries
+//
+//===============================================================================
+
+#ifndef CGLMQUERY_H
+#define CGLMQUERY_H
+
+#pragma once
+
+#ifdef OSX
+#include "glmgrbasics.h"
+#endif
+
+//===============================================================================
+
+// forward declarations
+
+class GLMContext;
+class CGLMQuery;
+
+//===============================================================================
+
+enum EGLMQueryType
+{
+ EOcclusion,
+ EFence,
+ EGLMQueryCount
+};
+
+struct GLMQueryParams
+{
+ EGLMQueryType m_type;
+};
+
+class CGLMQuery
+{
+ // leave everything public til it's running
+public:
+ friend class GLMContext; // only GLMContext can make CGLMTex objects
+ friend struct IDirect3DDevice9;
+ friend struct IDirect3DQuery9;
+
+ GLMContext *m_ctx; // link back to parent context
+ GLMQueryParams m_params; // params created with
+
+ GLuint m_name; // name of the query object per se - could be fence, could be query object
+
+ bool m_started;
+ bool m_stopped;
+ bool m_done;
+
+ bool m_nullQuery; // was gl_nullqueries true at Start time - if so, continue to act like a null query through Stop/IsDone/Complete time
+ // restated - only Start should examine the convar.
+
+ CGLMQuery( GLMContext *ctx, GLMQueryParams *params );
+ ~CGLMQuery( );
+
+ // for an occlusion query:
+ // Start = BeginQuery query-start goes into stream
+ // Stop = EndQuery query-end goes into stream - a fence is also set so we can probe for completion
+ // IsDone = TestFence use the added fence to ask if query-end has passed (i.e. will Complete block?)
+ // Complete = GetQueryObjectuivARB(uint id, enum pname, uint *params) - extract the sample count
+
+ // for a fence query:
+ // Start = SetFence fence goes into command stream
+ // Stop = NOP fences are self finishing - no need to call Stop on a fence
+ // IsDone = TestFence ask if fence passed
+ // Complete = FinishFence
+
+ void Start ( void );
+ void Stop ( void );
+ bool IsDone ( void );
+ void Complete ( uint *result );
+
+ // accessors for the started/stopped state
+ bool IsStarted ( void );
+ bool IsStopped ( void );
+};
+
+
+#endif
diff --git a/My project/sdk/glmgr/cglmtex.cpp b/My project/sdk/glmgr/cglmtex.cpp
new file mode 100644
index 000000000..e74ee3372
--- /dev/null
+++ b/My project/sdk/glmgr/cglmtex.cpp
@@ -0,0 +1,1816 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmtex.cpp
+//
+//===============================================================================
+
+#include "glmgr.h"
+#include "cglmtex.h"
+#include "dxabstract.h"
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wunused-variable"
+#endif
+
+#ifdef OSX
+// Debugger - 10.8
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+//===============================================================================
+
+#define TEXSPACE_LOGGING 0
+
+// encoding layout to an index where the bits read
+// 4 : 1 if compressed
+// 2 : 1 if not power of two
+// 1 : 1 if mipmapped
+
+bool pwroftwo (int val )
+{
+ return (val & (val-1)) == 0;
+}
+
+int sEncodeLayoutAsIndex( GLMTexLayoutKey *key )
+{
+ int index = 0;
+
+ if (key->m_texFlags & kGLMTexMipped)
+ {
+ index |= 1;
+ }
+
+ if ( ! ( pwroftwo(key->m_xSize) && pwroftwo(key->m_ySize) && pwroftwo(key->m_zSize) ) )
+ {
+ // if not all power of two
+ index |= 2;
+ }
+
+ if (GetFormatDesc( key->m_texFormat )->m_chunkSize >1 )
+ {
+ index |= 4;
+ }
+
+ return index;
+}
+
+static unsigned long g_texGlobalBytes[8];
+
+//===============================================================================
+
+const GLMTexFormatDesc g_formatDescTable[] =
+{
+ // not yet handled by this table:
+ // D3DFMT_INDEX16, D3DFMT_VERTEXDATA // D3DFMT_INDEX32,
+ // WTF { D3DFMT_R5G6R5 ???, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 1, 2 },
+ // WTF { D3DFMT_A ???, GL_ALPHA8, GL_ALPHA, GL_UNSIGNED_BYTE, 1, 1 },
+ // ??? D3DFMT_V8U8,
+ // ??? D3DFMT_Q8W8V8U8,
+ // ??? D3DFMT_X8L8V8U8,
+ // ??? D3DFMT_R32F,
+ // ??? D3DFMT_D24X4S4 unsure how to handle or if it is ever used..
+ // ??? D3DFMT_D15S1 ever used ?
+ // ??? D3DFMT_D24X8 ever used?
+
+ // summ-name d3d-format gl-int-format gl-int-format-srgb gl-data-format gl-data-type chunksize, bytes-per-sqchunk
+ { "_D16", D3DFMT_D16, GL_DEPTH_COMPONENT16, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 1, 2 },
+ { "_D24X8", D3DFMT_D24X8, GL_DEPTH_COMPONENT24, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 1, 4 }, // ??? unsure on this one
+ { "_D24S8", D3DFMT_D24S8, GL_DEPTH24_STENCIL8_EXT, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 1, 4 },
+
+ { "_A8R8G8B8", D3DFMT_A8R8G8B8, GL_RGBA8, GL_SRGB8_ALPHA8_EXT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 1, 4 },
+ { "_A4R4G4B4", D3DFMT_A4R4G4B4, GL_RGBA4, 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, 1, 2 },
+ { "_X8R8G8B8", D3DFMT_X8R8G8B8, GL_RGB8, GL_SRGB8_EXT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 1, 4 },
+
+ { "_X1R5G5B5", D3DFMT_X1R5G5B5, GL_RGB5, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 1, 2 },
+ { "_A1R5G5B5", D3DFMT_A1R5G5B5, GL_RGB5_A1, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 1, 2 },
+
+ { "_L8", D3DFMT_L8, GL_LUMINANCE8, GL_SLUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, 1 },
+ { "_A8L8", D3DFMT_A8L8, GL_LUMINANCE8_ALPHA8, GL_SLUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, 2 },
+
+ { "_DXT1", D3DFMT_DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE, 4, 8 },
+ { "_DXT3", D3DFMT_DXT3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, 4, 16 },
+ { "_DXT5", D3DFMT_DXT5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, 4, 16 },
+
+ { "_A16B16G16R16F", D3DFMT_A16B16G16R16F, GL_RGBA16F_ARB, 0, GL_RGBA, GL_HALF_FLOAT_ARB, 1, 8 },
+ { "_A16B16G16R16", D3DFMT_A16B16G16R16, GL_RGBA16, 0, GL_RGBA, GL_UNSIGNED_SHORT, 1, 8 }, // 16bpc integer tex
+
+ { "_A32B32G32R32F", D3DFMT_A32B32G32R32F, GL_RGBA32F_ARB, 0, GL_RGBA, GL_FLOAT, 1, 16 },
+
+ { "_R8G8B8", D3DFMT_R8G8B8, GL_RGB8, GL_SRGB8_EXT, GL_BGR, GL_UNSIGNED_BYTE, 1, 3 },
+
+ { "_A8", D3DFMT_A8, GL_ALPHA8, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 1, 1 },
+ { "_R5G6B5", D3DFMT_R5G6B5, GL_RGB, GL_SRGB_EXT, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 1, 2 },
+
+ // fakey tex formats: the stated GL format and the memory layout may not agree (U8V8 for example)
+
+ // _Q8W8V8U8 we just pass through as RGBA bytes. Shader does scale/bias fix
+ { "_Q8W8V8U8", D3DFMT_Q8W8V8U8, GL_RGBA8, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 1, 4 }, // straight ripoff of D3DFMT_A8R8G8B8
+
+ // U8V8 is exposed to the client as 2-bytes per texel, but we download it as 3-byte RGB.
+ // WriteTexels needs to do that conversion from rg8 to rgb8 in order to be able to download it correctly
+ { "_V8U8", D3DFMT_V8U8, GL_RGB8, 0, GL_RG, GL_BYTE, 1, 2 },
+
+ /*
+ // NV shadow depth tex
+ D3DFMT_NV_INTZ = 0x5a544e49, // MAKEFOURCC('I','N','T','Z')
+ D3DFMT_NV_RAWZ = 0x5a574152, // MAKEFOURCC('R','A','W','Z')
+
+ // NV null tex
+ D3DFMT_NV_NULL = 0x4c4c554e, // MAKEFOURCC('N','U','L','L')
+
+ // ATI shadow depth tex
+ D3DFMT_ATI_D16 = 0x36314644, // MAKEFOURCC('D','F','1','6')
+ D3DFMT_ATI_D24S8 = 0x34324644, // MAKEFOURCC('D','F','2','4')
+
+ // ATI 1N and 2N compressed tex
+ D3DFMT_ATI_2N = 0x32495441, // MAKEFOURCC('A', 'T', 'I', '2')
+ D3DFMT_ATI_1N = 0x31495441, // MAKEFOURCC('A', 'T', 'I', '1')
+ */
+};
+
+int g_formatDescTableCount = sizeof(g_formatDescTable) / sizeof( g_formatDescTable[0] );
+
+const GLMTexFormatDesc *GetFormatDesc( D3DFORMAT format )
+{
+ for( int i=0; i= range) Debugger();
+
+ *valuebuf = (*valuebuf << width) | scaled;
+}
+
+// return true if successful
+bool GLMGenTexels( GLMGenTexelParams *params )
+{
+ unsigned char chunkbuf[256]; // can't think of any chunk this big..
+
+ const GLMTexFormatDesc *format = GetFormatDesc( params->m_format );
+
+ if (!format)
+ {
+ return FALSE; // fail
+ }
+
+ // this section just generates one square chunk in the desired format
+ unsigned long *temp32 = (unsigned long*)chunkbuf;
+ unsigned int chunksize = 0; // we can sanity check against the format table with this
+
+ switch( params->m_format )
+ {
+ // comment shows byte order in RAM
+ // lowercase is bit arrangement in a byte
+
+ case D3DFMT_A8R8G8B8: // B G R A
+ InsertTexelComponentFixed( params->a, 8, temp32 ); // A is inserted first and winds up at most significant bits after insertions follow
+ InsertTexelComponentFixed( params->r, 8, temp32 );
+ InsertTexelComponentFixed( params->g, 8, temp32 );
+ InsertTexelComponentFixed( params->b, 8, temp32 );
+ chunksize = 4;
+ break;
+
+ case D3DFMT_A4R4G4B4: // [ggggbbbb] [aaaarrrr] RA (nibbles)
+ InsertTexelComponentFixed( params->a, 4, temp32 );
+ InsertTexelComponentFixed( params->r, 4, temp32 );
+ InsertTexelComponentFixed( params->g, 4, temp32 );
+ InsertTexelComponentFixed( params->b, 4, temp32 );
+ chunksize = 2;
+ break;
+
+ case D3DFMT_X8R8G8B8: // B G R X
+ InsertTexelComponentFixed( 0.0, 8, temp32 );
+ InsertTexelComponentFixed( params->r, 8, temp32 );
+ InsertTexelComponentFixed( params->g, 8, temp32 );
+ InsertTexelComponentFixed( params->b, 8, temp32 );
+ chunksize = 4;
+ break;
+
+ case D3DFMT_X1R5G5B5: // [gggbbbbb] [xrrrrrgg]
+ InsertTexelComponentFixed( 0.0, 1, temp32 );
+ InsertTexelComponentFixed( params->r, 5, temp32 );
+ InsertTexelComponentFixed( params->g, 5, temp32 );
+ InsertTexelComponentFixed( params->b, 5, temp32 );
+ chunksize = 2;
+ break;
+
+ case D3DFMT_A1R5G5B5: // [gggbbbbb] [arrrrrgg]
+ InsertTexelComponentFixed( params->a, 1, temp32 );
+ InsertTexelComponentFixed( params->r, 5, temp32 );
+ InsertTexelComponentFixed( params->g, 5, temp32 );
+ InsertTexelComponentFixed( params->b, 5, temp32 );
+ chunksize = 2;
+ break;
+
+ case D3DFMT_L8: // L // caller, use R for L
+ InsertTexelComponentFixed( params->r, 8, temp32 );
+ chunksize = 1;
+ break;
+
+ case D3DFMT_A8L8: // L A // caller, use R for L and A for A
+ InsertTexelComponentFixed( params->a, 8, temp32 );
+ InsertTexelComponentFixed( params->r, 8, temp32 );
+ chunksize = 2;
+ break;
+
+ case D3DFMT_R8G8B8: // B G R
+ InsertTexelComponentFixed( params->r, 8, temp32 );
+ InsertTexelComponentFixed( params->g, 8, temp32 );
+ InsertTexelComponentFixed( params->b, 8, temp32 );
+ chunksize = 3;
+ break;
+
+ case D3DFMT_A8: // A
+ InsertTexelComponentFixed( params->a, 8, temp32 );
+ chunksize = 1;
+ break;
+
+ case D3DFMT_R5G6B5: // [gggbbbbb] [rrrrrggg]
+ InsertTexelComponentFixed( params->r, 5, temp32 );
+ InsertTexelComponentFixed( params->g, 6, temp32 );
+ InsertTexelComponentFixed( params->b, 5, temp32 );
+ chunksize = 2;
+ break;
+
+ case D3DFMT_DXT1:
+ {
+ memset( temp32, 0, 8 ); // zap 8 bytes
+
+ // two 565 RGB words followed by 32 bits of 2-bit interp values for a 4x4 block
+ // we write the same color to both slots and all zeroes for the mask (one color total)
+
+ unsigned long dxt1_color = 0;
+
+ // generate one such word and clone it
+ InsertTexelComponentFixed( params->r, 5, &dxt1_color );
+ InsertTexelComponentFixed( params->g, 6, &dxt1_color );
+ InsertTexelComponentFixed( params->b, 5, &dxt1_color );
+
+ // dupe
+ dxt1_color = dxt1_color | (dxt1_color<<16);
+
+ // write into chunkbuf
+ *(unsigned long*)&chunkbuf[0] = dxt1_color;
+
+ // color mask bits after that are already set to all zeroes. chunk is done.
+ chunksize = 8;
+ }
+ break;
+
+ case D3DFMT_DXT3:
+ {
+ memset( temp32, 0, 16 ); // zap 16 bytes
+
+ // eight bytes of alpha (16 4-bit alpha nibbles)
+ // followed by a DXT1 block
+
+ unsigned long dxt3_alpha = 0;
+ for( int i=0; i<8; i++)
+ {
+ // splat same alpha through block
+ InsertTexelComponentFixed( params->a, 4, &dxt3_alpha );
+ }
+
+ unsigned long dxt3_color = 0;
+
+ // generate one such word and clone it
+ InsertTexelComponentFixed( params->r, 5, &dxt3_color );
+ InsertTexelComponentFixed( params->g, 6, &dxt3_color );
+ InsertTexelComponentFixed( params->b, 5, &dxt3_color );
+
+ // dupe
+ dxt3_color = dxt3_color | (dxt3_color<<16);
+
+ // write into chunkbuf
+ *(unsigned long*)&chunkbuf[0] = dxt3_alpha;
+ *(unsigned long*)&chunkbuf[4] = dxt3_alpha;
+ *(unsigned long*)&chunkbuf[8] = dxt3_color;
+ *(unsigned long*)&chunkbuf[12] = dxt3_color;
+
+ chunksize = 16;
+ }
+ break;
+
+ case D3DFMT_DXT5:
+ {
+ memset( temp32, 0, 16 ); // zap 16 bytes
+
+ // DXT5 has 8 bytes of compressed alpha, then 8 bytes of compressed RGB like DXT1.
+
+ // the 8 alpha bytes are 2 bytes of endpoint alpha values, then 16x3 bits of interpolants.
+ // so to write a single alpha value, just figure out the value, store it in both the first two bytes then store zeroes.
+
+ InsertTexelComponentFixed( params->a, 8, (unsigned long*)&chunkbuf[0] );
+ InsertTexelComponentFixed( params->a, 8, (unsigned long*)&chunkbuf[0] );
+ // rest of the alpha mask was already zeroed.
+
+ // now do colors
+ unsigned long dxt5_color = 0;
+
+ // generate one such word and clone it
+ InsertTexelComponentFixed( params->r, 5, &dxt5_color );
+ InsertTexelComponentFixed( params->g, 6, &dxt5_color );
+ InsertTexelComponentFixed( params->b, 5, &dxt5_color );
+
+ // dupe
+ dxt5_color = dxt5_color | (dxt5_color<<16);
+
+ // write into chunkbuf
+ *(unsigned long*)&chunkbuf[8] = dxt5_color;
+ *(unsigned long*)&chunkbuf[12] = dxt5_color;
+
+ chunksize = 16;
+ }
+ break;
+
+
+ case D3DFMT_A32B32G32R32F:
+ {
+ *(float*)&chunkbuf[0] = params->r;
+ *(float*)&chunkbuf[4] = params->g;
+ *(float*)&chunkbuf[8] = params->b;
+ *(float*)&chunkbuf[12] = params->a;
+
+ chunksize = 16;
+ }
+ break;
+
+ case D3DFMT_A16B16G16R16:
+ memset( chunkbuf, 0, 8 );
+ // R and G wind up in the first 32 bits
+ // B and A wind up in the second 32 bits
+
+ InsertTexelComponentFixed( params->a, 16, (unsigned long*)&chunkbuf[4] ); // winds up as MSW of second word (note [4]) - thus last in RAM
+ InsertTexelComponentFixed( params->b, 16, (unsigned long*)&chunkbuf[4] );
+
+ InsertTexelComponentFixed( params->g, 16, (unsigned long*)&chunkbuf[0] );
+ InsertTexelComponentFixed( params->r, 16, (unsigned long*)&chunkbuf[0] ); // winds up as LSW of first word, thus first in RAM
+
+ chunksize = 8;
+ break;
+
+ // not done yet
+
+
+ //case D3DFMT_D16:
+ //case D3DFMT_D24X8:
+ //case D3DFMT_D24S8:
+
+ //case D3DFMT_A16B16G16R16F:
+
+ default:
+ return FALSE; // fail
+ break;
+ }
+
+ // once the chunk buffer is filled..
+
+ // sanity check the reported chunk size.
+ if (chunksize != format->m_bytesPerSquareChunk)
+ {
+ Debugger();
+ return FALSE;
+ }
+
+ // verify that the amount you want to write will not exceed the limit byte count
+ unsigned long destByteCount = chunksize * params->m_chunkCount;
+
+ if (destByteCount > params->m_byteCountLimit)
+ {
+ Debugger();
+ return FALSE;
+ }
+
+ // write the bytes.
+ unsigned char *destP = (unsigned char*)params->m_dest;
+ for( int chunk=0; chunk < params->m_chunkCount; chunk++)
+ {
+ for( int byteindex = 0; byteindex < chunksize; byteindex++)
+ {
+ *destP++ = chunkbuf[byteindex];
+ }
+ }
+ params->m_bytesWritten = destP - (unsigned char*)params->m_dest;
+
+ return TRUE;
+}
+
+
+//===============================================================================
+
+CGLMTexLayoutTable::CGLMTexLayoutTable()
+{
+}
+
+GLMTexLayout *CGLMTexLayoutTable::NewLayoutRef( GLMTexLayoutKey *key )
+{
+ // look up 'key' in the map and see if it's a hit, if so, bump the refcount and return
+ // if not, generate a completed layout based on the key, add to map, set refcount to 1, return that
+
+ const GLMTexFormatDesc *formatDesc = GetFormatDesc( key->m_texFormat );
+ if (!formatDesc)
+ {
+ GLMStop(); // bad news
+ }
+ bool compression = (formatDesc->m_chunkSize > 1);
+
+ GLMTexLayoutKeyMap::iterator p = m_layoutMap.find( *key );
+ if (p != m_layoutMap.end())
+ {
+ // found it
+ //printf(" -hit- ");
+ GLMTexLayout *ptr = (*p).second;
+
+ // bump ref count
+ ptr->m_refCount++;
+
+ return ptr;
+ }
+ else
+ {
+ //printf(" -miss- ");
+ // need to make a new one
+ // to allocate it, we need to know how big to make it (slice count)
+
+ // figure out how many mip levels are in play
+ int mipCount = 1;
+ if (key->m_texFlags & kGLMTexMipped)
+ {
+ int largestAxis = key->m_xSize;
+
+ if (key->m_ySize > largestAxis)
+ largestAxis = key->m_ySize;
+
+ if (key->m_zSize > largestAxis)
+ largestAxis = key->m_zSize;
+
+ mipCount = 0;
+ while( largestAxis > 0 )
+ {
+ mipCount ++;
+ largestAxis >>= 1;
+ }
+ }
+
+ int faceCount = 1;
+ if (key->m_texGLTarget == GL_TEXTURE_CUBE_MAP)
+ {
+ faceCount = 6;
+ }
+
+ int sliceCount = mipCount * faceCount;
+
+ if (key->m_texFlags & kGLMTexMultisampled)
+ {
+ Assert( (key->m_texGLTarget == GL_TEXTURE_2D) );
+ Assert( sliceCount == 1 );
+
+ // assume non mipped
+ Assert( (key->m_texFlags & kGLMTexMipped) == 0 );
+ Assert( (key->m_texFlags & kGLMTexMippedAuto) == 0 );
+
+ // assume renderable and srgb
+ Assert( (key->m_texFlags & kGLMTexRenderable) !=0 );
+ //Assert( (key->m_texFlags & kGLMTexSRGB) !=0 ); //FIXME don't assert on making depthstencil surfaces which are non srgb
+
+ // double check sample count (FIXME need real limit check here against device/driver)
+ Assert( (key->m_texSamples==2) || (key->m_texSamples==4) || (key->m_texSamples==6) || (key->m_texSamples==8) );
+ }
+
+ // now we know enough to allocate and populate the new tex layout.
+
+ // malloc the new layout
+ int layoutSize = sizeof( GLMTexLayout ) + (sliceCount * sizeof( GLMTexLayoutSlice ));
+ GLMTexLayout *layout = (GLMTexLayout *)malloc( layoutSize );
+ memset( layout, 0, layoutSize );
+
+ // clone the key in there
+ memset( &layout->m_key, 0x00, sizeof(layout->m_key) );
+ layout->m_key = *key;
+
+ // set refcount
+ layout->m_refCount = 1;
+
+ // save the format desc
+ layout->m_format = (GLMTexFormatDesc *)formatDesc;
+
+ // we know the mipcount from before
+ layout->m_mipCount = mipCount;
+
+ // we know the face count too
+ layout->m_faceCount = faceCount;
+
+ // slice count is the product
+ layout->m_sliceCount = mipCount * faceCount;
+
+ // we can now fill in the slices.
+ GLMTexLayoutSlice *slicePtr = &layout->m_slices[0];
+ int storageOffset = 0;
+
+ bool compressed = (formatDesc->m_chunkSize > 1); // true if DXT
+
+ for( int mip = 0; mip < mipCount; mip ++ )
+ {
+ for( int face = 0; face < faceCount; face++ )
+ {
+ // note application of chunk size which is 1 for uncompressed, and 4 for compressed tex (DXT)
+ // note also that the *dimensions* must scale down to 1
+ // but that the *storage* cannot go below 4x4.
+ // we introduce the "storage sizes" which are clamped, to compute the storage footprint.
+
+ int storage_x,storage_y,storage_z;
+
+ slicePtr->m_xSize = layout->m_key.m_xSize >> mip;
+ slicePtr->m_xSize = std::max( slicePtr->m_xSize, 1 ); // dimension can't go to zero
+ storage_x = std::max( slicePtr->m_xSize, formatDesc->m_chunkSize ); // storage extent can't go below chunk size
+
+ slicePtr->m_ySize = layout->m_key.m_ySize >> mip;
+ slicePtr->m_ySize = std::max( slicePtr->m_ySize, 1 ); // dimension can't go to zero
+ storage_y = std::max( slicePtr->m_ySize, formatDesc->m_chunkSize ); // storage extent can't go below chunk size
+
+ slicePtr->m_zSize = layout->m_key.m_zSize >> mip;
+ slicePtr->m_zSize = std::max( slicePtr->m_zSize, 1 ); // dimension can't go to zero
+ storage_z = std::max( slicePtr->m_zSize, 1); // storage extent for Z cannot go below '1'.
+
+ //if (compressed) NO NO NO do not lie about the dimensionality, just fudge the storage.
+ //{
+ // // round up to multiple of 4 in X and Y axes
+ // slicePtr->m_xSize = (slicePtr->m_xSize+3) & (~3);
+ // slicePtr->m_ySize = (slicePtr->m_ySize+3) & (~3);
+ //}
+
+ int xchunks = (storage_x / formatDesc->m_chunkSize );
+ int ychunks = (storage_y / formatDesc->m_chunkSize );
+
+ slicePtr->m_storageSize = (xchunks * ychunks * formatDesc->m_bytesPerSquareChunk) * storage_z;
+ slicePtr->m_storageOffset = storageOffset;
+
+ storageOffset += slicePtr->m_storageSize;
+ storageOffset = ( (storageOffset+0x0F) & (~0x0F)); // keep each MIP starting on a 16 byte boundary.
+
+ slicePtr++;
+ }
+ }
+
+ layout->m_storageTotalSize = storageOffset;
+ //printf("\n size %08x for key (x=%d y=%d z=%d, fmt=%08x, bpsc=%d)", layout->m_storageTotalSize, key->m_xSize, key->m_ySize, key->m_zSize, key->m_texFormat, formatDesc->m_bytesPerSquareChunk );
+
+ // generate summary
+ // "target, format, +/- mips, base size"
+ char scratch[1024];
+
+ const char *targetname;
+ switch( key->m_texGLTarget )
+ {
+ case GL_TEXTURE_2D: targetname = "2D "; break;
+ case GL_TEXTURE_3D: targetname = "3D "; break;
+ case GL_TEXTURE_CUBE_MAP: targetname = "CUBE"; break;
+ }
+
+ sprintf( scratch, "[%s %s %dx%dx%d mips=%d slices=%d flags=%02lX%s]",
+ targetname,
+ formatDesc->m_formatSummary,
+ layout->m_key.m_xSize, layout->m_key.m_ySize, layout->m_key.m_zSize,
+ mipCount,
+ sliceCount,
+ layout->m_key.m_texFlags,
+ (layout->m_key.m_texFlags & kGLMTexSRGB) ? " SRGB" : ""
+ );
+ layout->m_layoutSummary = strdup( scratch );
+ //GLMPRINTF(("-D- new tex layout [ %s ]", scratch ));
+
+ // then insert into map. disregard returned index.
+ m_layoutMap[ layout->m_key ] = layout;
+
+ return layout;
+ }
+}
+
+void CGLMTexLayoutTable::DelLayoutRef( GLMTexLayout *layout )
+{
+ // locate layout in hash, drop refcount
+
+ GLMTexLayoutKeyMap::iterator p = m_layoutMap.find( layout->m_key );
+ if (p != m_layoutMap.end())
+ {
+ // found it
+ GLMTexLayout *ptr = (*p).second;
+
+ // drop ref count
+ ptr->m_refCount--;
+ }
+}
+
+void CGLMTexLayoutTable::DumpStats( )
+{
+ for( GLMTexLayoutKeyMap::iterator p = m_layoutMap.begin(); p != m_layoutMap.end(); p++ )
+ {
+ GLMTexLayout *layout = (*p).second;
+
+ // print it out
+ printf("\n%05d instances %08d bytes %08d totbytes %s", layout->m_refCount, layout->m_storageTotalSize, (layout->m_refCount*layout->m_storageTotalSize), layout->m_layoutSummary );
+ }
+}
+
+#if 0
+ ConVar gl_texclientstorage( "gl_texclientstorage", "1" ); // default 1 for L4D2
+ ConVar gl_texmsaalog ( "gl_texmsaalog", "0");
+ ConVar gl_rt_forcergba ( "gl_rt_forcergba", "1" ); // on teximage of a renderable tex, pass GL_RGBA in place of GL_BGRA
+ ConVar gl_minimize_rt_tex ( "gl_minimize_rt_tex", "0" ); // if 1, set the GL_TEXTURE_MINIMIZE_STORAGE_APPLE texture parameter to cut off mipmaps for RT's
+ ConVar gl_minimize_all_tex ( "gl_minimize_all_tex", "1" ); // if 1, set the GL_TEXTURE_MINIMIZE_STORAGE_APPLE texture parameter to cut off mipmaps for textures which are unmipped
+ ConVar gl_minimize_tex_log ( "gl_minimize_tex_log", "0" ); // if 1, printf the names of the tex that got minimized
+#else
+ int gl_texclientstorage = 1;
+ int gl_texmsaalog = 0;
+ int gl_rt_forcergba = 1;
+ int gl_minimize_rt_tex = 0;
+ int gl_minimize_all_tex =1;
+ int gl_minimize_tex_log =0;
+#endif
+
+
+CGLMTex::CGLMTex( GLMContext *ctx, GLMTexLayout *layout, GLMTexSamplingParams *sampling, const char *debugLabel )
+{
+ // caller has responsibility to make 'ctx' current, but we check to be sure.
+ ctx->CheckCurrent();
+
+ // note layout requested
+ m_layout = layout;
+ m_maxActiveMip = -1; //index of highest mip that has been written - increase as each mip arrives
+ m_minActiveMip = 999; //index of lowest mip that has been written - lower it as each mip arrives
+
+ // note sampling (copy values)
+ m_sampling = *sampling;
+
+ // note context owner
+ m_ctx = ctx;
+
+ // clear the bind point flags
+ m_bindPoints = 0; // was ClearAll() with bitvec
+
+ // clear the RT attach count
+ m_rtAttachCount = 0;
+
+ // come up with a GL name for this texture.
+ // for MTGL friendliness, we should generate our own names at some point..
+ glGenTextures( 1, &m_texName );
+
+ //sense whether to try and apply client storage upon teximage/subimage
+ m_texClientStorage = (gl_texclientstorage/* .GetInt() */ != 0);
+
+ // flag that we have not yet been explicitly kicked into VRAM..
+ m_texPreloaded = false;
+
+ // clone the debug label if there is one.
+ m_debugLabel = debugLabel ? strdup(debugLabel) : NULL;
+
+ // if tex is MSAA renderable, make an RBO, else zero the RBO name and dirty bit
+ if (layout->m_key.m_texFlags & kGLMTexMultisampled)
+ {
+ glGenRenderbuffersEXT( 1, &m_rboName );
+ m_rboDirty = false;
+
+ // so we have enough info to go ahead and bind the RBO and put storage on it?
+ // try it.
+ glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, m_rboName );
+ GLMCheckError();
+
+ // quietly clamp if sample count exceeds known limit for the device
+ int sampleCount = layout->m_key.m_texSamples;
+
+ if (sampleCount > ctx->Caps().m_maxSamples)
+ {
+ sampleCount = ctx->Caps().m_maxSamples; // clamp
+ }
+
+ GLenum msaaFormat = (layout->m_key.m_texFlags & kGLMTexSRGB) ? layout->m_format->m_glIntFormatSRGB : layout->m_format->m_glIntFormat;
+ glRenderbufferStorageMultisampleEXT( GL_RENDERBUFFER_EXT,
+ sampleCount, // not "layout->m_key.m_texSamples"
+ msaaFormat,
+ layout->m_key.m_xSize,
+ layout->m_key.m_ySize );
+ GLMCheckError();
+
+ if (gl_texmsaalog/* .GetInt() */)
+ {
+ printf( "\n == MSAA Tex %p %s : MSAA RBO is intformat %s (%x)", this, m_debugLabel?m_debugLabel:"", GLMDecode( eGL_ENUM, msaaFormat ), msaaFormat );
+ }
+
+ glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ GLMCheckError();
+ }
+ else
+ {
+ m_rboName = 0;
+ m_rboDirty = false;
+ }
+
+
+ // at this point we have the complete description of the texture, and a name for it, but no data and no actual GL object.
+ // we know this name has bever seen duty before, so we're going to hard-bind it to TMU 0, displacing any other tex that might have been bound there.
+ // any previously bound tex will be unbound and appropriately marked as a result.
+ // the active TMU will be set as a side effect.
+ ctx->BindTexToTMU( this, 0 );
+
+ // OK, our texture now exists and is bound on the active TMU. Not drawable yet though.
+
+ // impose the sampling params we were given, unconditionally
+ ApplySamplingParams( sampling, true );
+
+ // if not an RT, create backing storage and fill it
+ if ( !(layout->m_key.m_texFlags & kGLMTexRenderable) )
+ {
+ m_backing = (char *)malloc( m_layout->m_storageTotalSize );
+ memset( m_backing, 0, m_layout->m_storageTotalSize );
+
+ // track bytes allocated for non-RT's
+ int formindex = sEncodeLayoutAsIndex( &layout->m_key );
+
+ g_texGlobalBytes[ formindex ] += m_layout->m_storageTotalSize;
+
+ #if TEXSPACE_LOGGING
+ printf( "\n Tex %s added %d bytes in form %d which is now %d bytes", m_debugLabel ? m_debugLabel : "-", m_layout->m_storageTotalSize, formindex, g_texGlobalBytes[ formindex ] );
+ printf( "\n\t\t[ %d %d %d %d %d %d %d %d ]",
+ g_texGlobalBytes[ 0 ],g_texGlobalBytes[ 1 ],g_texGlobalBytes[ 2 ],g_texGlobalBytes[ 3 ],
+ g_texGlobalBytes[ 4 ],g_texGlobalBytes[ 5 ],g_texGlobalBytes[ 6 ],g_texGlobalBytes[ 7 ]
+ );
+ #endif
+ }
+ else
+ {
+ m_backing = NULL;
+
+ m_texClientStorage = false;
+ }
+
+ // init lock count
+ // lock reqs are tracked by the owning context
+ m_lockCount = 0;
+
+ m_sliceFlags.resize( m_layout->m_sliceCount );
+ for( int i=0; i< m_layout->m_sliceCount; i++)
+ {
+ m_sliceFlags[i] = 0;
+ // kSliceValid = false (we have not teximaged each slice yet)
+ // kSliceStorageValid = false (the storage allocated does not reflect what is in the tex)
+ // kSliceLocked = false (the slices are not locked)
+ // kSliceFullyDirty = false (this does not come true til first lock)
+ }
+
+ // texture minimize parameter keeps driver from allocing mips when it should not, by being explicit about the ones that have no mips.
+
+ bool setMinimizeParameter = false;
+ bool minimize_rt = (gl_minimize_rt_tex/* .GetInt() */!=0);
+ bool minimize_all = (gl_minimize_all_tex/* .GetInt() */!=0);
+
+ if (layout->m_key.m_texFlags & kGLMTexRenderable)
+ {
+ // it's an RT. if mips were not explicitly requested, and "gl_minimize_rt_tex" is true, set the minimize parameter.
+ if ( (minimize_rt || minimize_all) && ( !(layout->m_key.m_texFlags & kGLMTexMipped) ) )
+ {
+ setMinimizeParameter = true;
+ }
+ }
+ else
+ {
+ // not an RT. if mips were not requested, and "gl_minimize_all_tex" is true, set the minimize parameter.
+ if ( minimize_all && ( !(layout->m_key.m_texFlags & kGLMTexMipped) ) )
+ {
+ setMinimizeParameter = true;
+ }
+ }
+
+ if (setMinimizeParameter)
+ {
+ if (gl_minimize_tex_log/* .GetInt() */)
+ {
+ printf("\n minimizing storage for tex '%s' [%s] ", m_debugLabel?m_debugLabel:"-", m_layout->m_layoutSummary );
+ }
+ glTexParameteri( m_layout->m_key.m_texGLTarget, GL_TEXTURE_MINIMIZE_STORAGE_APPLE, 1 );
+ }
+
+ // after a lot of pain with texture completeness...
+ // always push black into all slices of all newly created textures.
+
+ #if 0
+ bool pushRenderableSlices = (m_layout->m_key.m_texFlags & kGLMTexRenderable) != 0;
+ bool pushTexSlices = true; // just do it everywhere (m_layout->m_mipCount>1) && (m_layout->m_format->m_chunkSize !=1) ;
+ if (pushTexSlices)
+ {
+ // fill storage with mostly-opaque purple
+
+ GLMGenTexelParams genp;
+ memset( &genp, 0, sizeof(genp) );
+
+ genp.m_format = m_layout->m_format->m_d3dFormat;
+ const GLMTexFormatDesc *format = GetFormatDesc( genp.m_format );
+
+ genp.m_dest = m_backing; // dest addr
+ genp.m_chunkCount = m_layout->m_storageTotalSize / format->m_bytesPerSquareChunk; // fill the whole slab
+ genp.m_byteCountLimit = m_layout->m_storageTotalSize; // limit writes to this amount
+
+ genp.r = 1.0;
+ genp.g = 0.0;
+ genp.b = 1.0;
+ genp.a = 0.75;
+
+ GLMGenTexels( &genp );
+ }
+ #endif
+
+ //if (pushRenderableSlices || pushTexSlices)
+ if (1)
+ {
+ for( int face=0; face m_faceCount; face++)
+ {
+ for( int mip=0; mip m_mipCount; mip++)
+ {
+ // we're not really going to lock, we're just going to write the blank data from the backing store we just made
+ GLMTexLockDesc desc;
+
+ desc.m_req.m_tex = this;
+ desc.m_req.m_face = face;
+ desc.m_req.m_mip = mip;
+
+ desc.m_sliceIndex = CalcSliceIndex( face, mip );
+
+ GLMTexLayoutSlice *slice = &m_layout->m_slices[ desc.m_sliceIndex ];
+
+ desc.m_req.m_region.xmin = desc.m_req.m_region.ymin = desc.m_req.m_region.zmin = 0;
+ desc.m_req.m_region.xmax = slice->m_xSize;
+ desc.m_req.m_region.ymax = slice->m_ySize;
+ desc.m_req.m_region.zmax = slice->m_zSize;
+
+ desc.m_sliceBaseOffset = slice->m_storageOffset; // doesn't really matter... we're just pushing zeroes..
+ desc.m_sliceRegionOffset = 0;
+
+ this->WriteTexels( &desc, true, (layout->m_key.m_texFlags & kGLMTexRenderable)!=0 ); // write whole slice - but disable data source if it's an RT, as there's no backing
+ }
+ }
+ }
+ GLMPRINTF(("-A- -**TEXNEW '%-60s' name=%06d size=%09d storage=%08x label=%s ", m_layout->m_layoutSummary, m_texName, m_layout->m_storageTotalSize, m_backing, m_debugLabel ? m_debugLabel : "-" ));
+}
+
+CGLMTex::~CGLMTex( )
+{
+ if ( !(m_layout->m_key.m_texFlags & kGLMTexRenderable) )
+ {
+ int formindex = sEncodeLayoutAsIndex( &m_layout->m_key );
+
+ g_texGlobalBytes[ formindex ] -= m_layout->m_storageTotalSize;
+
+ #if TEXSPACE_LOGGING
+ printf( "\n Tex %s freed %d bytes in form %d which is now %d bytes", m_debugLabel ? m_debugLabel : "-", m_layout->m_storageTotalSize, formindex, g_texGlobalBytes[ formindex ] );
+ printf( "\n\t\t[ %d %d %d %d %d %d %d %d ]",
+ g_texGlobalBytes[ 0 ],g_texGlobalBytes[ 1 ],g_texGlobalBytes[ 2 ],g_texGlobalBytes[ 3 ],
+ g_texGlobalBytes[ 4 ],g_texGlobalBytes[ 5 ],g_texGlobalBytes[ 6 ],g_texGlobalBytes[ 7 ]
+ );
+ #endif
+ }
+
+ GLMPRINTF(("-A- -**TEXDEL '%-60s' name=%06d size=%09d storage=%08x label=%s ", m_layout->m_layoutSummary, m_texName, m_layout->m_storageTotalSize, m_backing, m_debugLabel ? m_debugLabel : "-" ));
+ // check first to see if we were still bound anywhere or locked... these should be failures.
+
+ // if all that is OK, then delete the underlying tex
+ glDeleteTextures( 1, &m_texName );
+ GLMCheckError();
+ m_texName = 0;
+
+ if(m_rboName)
+ {
+ glDeleteRenderbuffersEXT( 1, &m_rboName );
+ GLMCheckError();
+ m_rboName = 0;
+ m_rboDirty = false;
+ }
+
+
+ // release our usage of the layout
+ m_ctx->m_texLayoutTable->DelLayoutRef( m_layout );
+ m_layout = NULL;
+
+ if (m_backing)
+ {
+ free( m_backing );
+ m_backing = NULL;
+ }
+
+ if (m_debugLabel)
+ {
+ free( m_debugLabel );
+ m_debugLabel = NULL;
+ }
+
+ m_ctx = NULL;
+}
+
+int CGLMTex::CalcSliceIndex( int face, int mip )
+{
+ // faces of the same mip level are adjacent. "face major" storage
+ int index = (mip * m_layout->m_faceCount) + face;
+
+ return index;
+}
+
+void CGLMTex::CalcTexelDataOffsetAndStrides( int sliceIndex, int x, int y, int z, int *offsetOut, int *yStrideOut, int *zStrideOut )
+{
+ int offset = 0;
+ int yStride = 0;
+ int zStride = 0;
+
+ GLMTexFormatDesc *format = m_layout->m_format;
+ if (format->m_chunkSize==1)
+ {
+ // figure out row stride and layer stride
+ yStride = format->m_bytesPerSquareChunk * m_layout->m_slices[sliceIndex].m_xSize; // bytes per texel row (y stride)
+ zStride = yStride * m_layout->m_slices[sliceIndex].m_ySize; // bytes per texel layer (if 3D tex)
+
+ offset = x * format->m_bytesPerSquareChunk; // lateral offset
+ offset += (y * yStride); // scanline offset
+ offset += (z * zStride); // should be zero for 2D tex
+ }
+ else
+ {
+ yStride = format->m_bytesPerSquareChunk * (m_layout->m_slices[sliceIndex].m_xSize / format->m_chunkSize);
+ zStride = yStride * (m_layout->m_slices[sliceIndex].m_ySize / format->m_chunkSize);
+
+ // compressed format. scale the x,y,z values into chunks.
+ // assert if any of them are not multiples of a chunk.
+ int chunkx = x / format->m_chunkSize;
+ int chunky = y / format->m_chunkSize;
+ int chunkz = z / format->m_chunkSize;
+
+ if ( (chunkx * format->m_chunkSize) != x)
+ {
+ GLMStop();
+ }
+
+ if ( (chunky * format->m_chunkSize) != y)
+ {
+ GLMStop();
+ }
+
+ if ( (chunkz * format->m_chunkSize) != z)
+ {
+ GLMStop();
+ }
+
+ offset = chunkx * format->m_bytesPerSquareChunk; // lateral offset
+ offset += (chunky * yStride); // chunk row offset
+ offset += (chunkz * zStride); // should be zero for 2D tex
+ }
+
+ *offsetOut = offset;
+ *yStrideOut = yStride;
+ *zStrideOut = zStride;
+}
+
+void CGLMTex::ApplySamplingParams( GLMTexSamplingParams *params, bool noCheck )
+{
+ #define DIFF(fff) (noCheck || (params->fff != m_sampling.fff))
+
+ GLenum target = m_layout->m_key.m_texGLTarget;
+
+ // if the texture is compressed, and has a maxActiveMip that is >=0 but less than the mip count,
+ // (i.e. they supplied *some* but not *all* mips needed)...
+ // generate them, and fix the max mip count.
+
+
+ //if ( /*(m_layout->m_format->m_chunkSize !=1) &&*/ (m_layout->m_mipCount>3) )
+ //{
+ // m_maxActiveMip = m_layout->m_mipCount-3; // pull back three levels
+ // glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, m_maxActiveMip);
+ // GLMCheckError();
+ //}
+
+ if (DIFF(m_addressModes[0]))
+ {
+ m_sampling.m_addressModes[0] = params->m_addressModes[0];
+ glTexParameteri( target, GL_TEXTURE_WRAP_S, m_sampling.m_addressModes[0]);
+ GLMCheckError();
+ }
+
+ if (DIFF(m_addressModes[1]))
+ {
+ m_sampling.m_addressModes[1] = params->m_addressModes[1];
+ glTexParameteri( target, GL_TEXTURE_WRAP_T, m_sampling.m_addressModes[1]);
+ GLMCheckError();
+ }
+
+ if (DIFF(m_addressModes[2]))
+ {
+ m_sampling.m_addressModes[2] = params->m_addressModes[2];
+ glTexParameteri( target, GL_TEXTURE_WRAP_R, m_sampling.m_addressModes[2]);
+ GLMCheckError();
+ }
+
+ if ( noCheck || memcmp( params->m_borderColor, m_sampling.m_borderColor, sizeof(m_sampling.m_borderColor) ) )
+ {
+ memcpy( m_sampling.m_borderColor, params->m_borderColor, sizeof(params->m_borderColor) );
+ glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, params->m_borderColor );
+ GLMCheckError();
+ }
+
+ if (DIFF(m_magFilter))
+ {
+ m_sampling.m_magFilter = params->m_magFilter;
+ glTexParameteri( target, GL_TEXTURE_MAG_FILTER, params->m_magFilter);
+ GLMCheckError();
+ }
+
+ if (DIFF(m_minFilter))
+ {
+ m_sampling.m_minFilter = params->m_minFilter;
+ glTexParameteri( target, GL_TEXTURE_MIN_FILTER, params->m_minFilter);
+ GLMCheckError();
+ }
+
+ if (DIFF(m_mipmapBias))
+ {
+ m_sampling.m_mipmapBias = params->m_mipmapBias;
+ //glTexParameterf( target, GL_TEXTURE_LOD_BIAS, params->m_mipmapBias );
+ GLMCheckError();
+ }
+
+ if (DIFF(m_minMipLevel))
+ {
+ // don't let minmiplevel go below min active mip level
+ m_sampling.m_minMipLevel = std::max( m_minActiveMip, params->m_minMipLevel );
+ glTexParameteri( target, GL_TEXTURE_MIN_LOD, m_sampling.m_minMipLevel);
+ GLMCheckError();
+ }
+
+ if (DIFF(m_maxMipLevel))
+ {
+ // do not let max selectable LOD exceed the max submitted mip
+
+ m_sampling.m_maxMipLevel = std::min( m_maxActiveMip, params->m_maxMipLevel);
+ glTexParameteri( target, GL_TEXTURE_MAX_LOD, m_sampling.m_maxMipLevel);
+ GLMCheckError();
+ }
+
+ if (m_layout->m_mipCount > 1) // only apply aniso setting to mipped tex
+ {
+ if (DIFF(m_maxAniso))
+ {
+ m_sampling.m_maxAniso = params->m_maxAniso >= 1.0f ? params->m_maxAniso : 1.0f;
+ glTexParameteri( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, params->m_maxAniso );
+ GLMCheckError();
+ }
+ }
+
+ if (DIFF(m_compareMode))
+ {
+ m_sampling.m_compareMode = params->m_compareMode;
+ glTexParameteri( target, GL_TEXTURE_COMPARE_MODE_ARB, params->m_compareMode );
+ GLMCheckError();
+
+ if (params->m_compareMode == GL_COMPARE_R_TO_TEXTURE_ARB)
+ {
+ glTexParameteri( target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
+ GLMCheckError();
+ }
+ }
+
+ if (DIFF(m_srgb))
+ {
+ m_sampling.m_srgb = params->m_srgb; // we might have to re-DL the tex if the SRGB read status changes..
+ }
+
+ #undef DIFF
+}
+
+void CGLMTex::ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice )
+{
+ GLMRegion readBox;
+
+ if (readWholeSlice)
+ {
+ readBox.xmin = readBox.ymin = readBox.zmin = 0;
+
+ readBox.xmax = m_layout->m_slices[ desc->m_sliceIndex ].m_xSize;
+ readBox.ymax = m_layout->m_slices[ desc->m_sliceIndex ].m_ySize;
+ readBox.zmax = m_layout->m_slices[ desc->m_sliceIndex ].m_zSize;
+ }
+ else
+ {
+ readBox = desc->m_req.m_region;
+ }
+
+ m_ctx->BindTexToTMU( this, 0, false ); // SelectTMU(n) is a side effect
+
+ if (readWholeSlice)
+ {
+ // make this work first.... then write the partial path
+ // (Hmmmm, I don't think we will ever actually need a partial path -
+ // since we have no notion of a partially valid slice of storage
+
+ GLMTexFormatDesc *format = m_layout->m_format;
+ GLenum target = m_layout->m_key.m_texGLTarget;
+
+ void *sliceAddress = m_backing + m_layout->m_slices[ desc->m_sliceIndex ].m_storageOffset; // this would change for PBO
+ int sliceSize = m_layout->m_slices[ desc->m_sliceIndex ].m_storageSize;
+
+ // interestingly enough, we can use the same path for both 2D and 3D fetch
+
+ switch( target )
+ {
+ case GL_TEXTURE_CUBE_MAP:
+
+ // adjust target to steer to the proper face, then fall through to the 2D texture path.
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + desc->m_req.m_face;
+
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_3D:
+ {
+ // check compressed or not
+ if (format->m_chunkSize != 1)
+ {
+ // compressed path
+ // http://www.opengl.org/sdk/docs/man/xhtml/glGetCompressedTexImage.xml
+
+ glGetCompressedTexImage( target, // target
+ desc->m_req.m_mip, // level
+ sliceAddress ); // destination
+ GLMCheckError();
+ }
+ else
+ {
+ // uncompressed path
+ // http://www.opengl.org/sdk/docs/man/xhtml/glGetTexImage.xml
+
+ glGetTexImage( target, // target
+ desc->m_req.m_mip, // level
+ format->m_glDataFormat, // dataformat
+ format->m_glDataType, // datatype
+ sliceAddress ); // destination
+ GLMCheckError();
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ GLMStop();
+ }
+}
+
+// defaulting the subimage support off, since it's breaking Ep2 at startup on some NV 9400 and friends
+// defaulting it back to "1" for L4D2 and see if it flies
+int gl_enabletexsubimage = 1;
+//ConVar gl_enabletexsubimage( "gl_enabletexsubimage", "1" );
+
+void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDataWrite )
+{
+ GLMRegion writeBox;
+
+ bool needsExpand = false;
+ char *expandTemp = NULL;
+
+ switch( m_layout->m_format->m_d3dFormat)
+ {
+ case D3DFMT_V8U8:
+ {
+ needsExpand = true;
+ writeWholeSlice = true;
+
+ // shoot down client storage if we have to generate a new flavor of the data
+ m_texClientStorage = false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (writeWholeSlice)
+ {
+ writeBox.xmin = writeBox.ymin = writeBox.zmin = 0;
+
+ writeBox.xmax = m_layout->m_slices[ desc->m_sliceIndex ].m_xSize;
+ writeBox.ymax = m_layout->m_slices[ desc->m_sliceIndex ].m_ySize;
+ writeBox.zmax = m_layout->m_slices[ desc->m_sliceIndex ].m_zSize;
+ }
+ else
+ {
+ writeBox = desc->m_req.m_region;
+ }
+
+ // first thing is to get the GL texture bound to a TMU, or just select one if already bound
+ // to get this running we will just always slam TMU 0 and let the draw time code fix it back
+ // a later optimization would be to hoist the bind call to the caller, do it exactly once
+
+ m_ctx->BindTexToTMU( this, 0, false ); // SelectTMU(n) is a side effect
+
+ GLMTexFormatDesc *format = m_layout->m_format;
+
+ GLenum target = m_layout->m_key.m_texGLTarget;
+ GLenum glDataFormat = format->m_glDataFormat; // this could change if expansion kicks in
+ GLenum glDataType = format->m_glDataType;
+
+ GLMTexLayoutSlice *slice = &m_layout->m_slices[ desc->m_sliceIndex ];
+ void *sliceAddress = m_backing ? (m_backing + slice->m_storageOffset) : NULL; // this would change for PBO
+
+ // allow use of subimage if the target is texture2D and it has already been teximage'd
+ bool mayUseSubImage = false;
+ if ( (target==GL_TEXTURE_2D) && (m_sliceFlags[ desc->m_sliceIndex ] & kSliceValid) )
+ {
+ mayUseSubImage = gl_enabletexsubimage/* .GetInt() */;
+ }
+
+ // check flavor, 2D, 3D, or cube map
+ // we also have the choice to use subimage if this is a tex already created. (open question as to benefit)
+
+
+ // SRGB select. At this level (writetexels) we firmly obey the m_texFlags.
+ // (mechanism not policy)
+
+ GLenum intformat = (m_layout->m_key.m_texFlags & kGLMTexSRGB) ? format->m_glIntFormatSRGB : format->m_glIntFormat;
+ if (0 /* CommandLine()->FindParm("-disable_srgbtex") */)
+ {
+ // force non srgb flavor - experiment to make ATI r600 happy on 10.5.8 (maybe x1600 too!)
+ intformat = format->m_glIntFormat;
+ }
+
+ Assert( intformat != 0 );
+
+ if (m_layout->m_key.m_texFlags & kGLMTexSRGB)
+ {
+ Assert( m_layout->m_format->m_glDataFormat != GL_DEPTH_COMPONENT );
+ Assert( m_layout->m_format->m_glDataFormat != GL_DEPTH_STENCIL_EXT );
+ Assert( m_layout->m_format->m_glDataFormat != GL_ALPHA );
+ }
+
+ // adjust min and max mip written
+ if (desc->m_req.m_mip > m_maxActiveMip)
+ {
+ m_maxActiveMip = desc->m_req.m_mip;
+
+ glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, desc->m_req.m_mip);
+ GLMCheckError();
+ }
+
+ if (desc->m_req.m_mip < m_minActiveMip)
+ {
+ m_minActiveMip = desc->m_req.m_mip;
+
+ glTexParameteri( target, GL_TEXTURE_BASE_LEVEL, desc->m_req.m_mip);
+ GLMCheckError();
+ }
+
+ if (needsExpand)
+ {
+ int expandSize = 0;
+
+ switch( m_layout->m_format->m_d3dFormat)
+ {
+ case D3DFMT_V8U8:
+ {
+ // figure out new size based on 3byte RGB format
+ // easy, just take the two byte size and grow it by 50%
+ expandSize = (slice->m_storageSize * 3) / 2;
+ expandTemp = (char*)malloc( expandSize );
+
+ char *src = (char*)sliceAddress;
+ char *dst = expandTemp;
+
+ // transfer RG's to RGB's
+ while(expandSize>0)
+ {
+ *dst = *src++; // move first byte
+ *dst = *src++; // move second byte
+ *dst = 0xBB; // pad third byte
+
+ expandSize -= 3;
+ }
+
+ // move the slice pointer
+ sliceAddress = expandTemp;
+
+ // change the data format we tell GL about
+ glDataFormat = GL_RGB;
+ }
+ break;
+
+ default: Assert(!"Don't know how to expand that format..");
+ }
+
+ }
+
+ // set up the client storage now, one way or another
+ glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, m_texClientStorage );
+ GLMCheckError();
+
+ switch( target )
+ {
+ case GL_TEXTURE_CUBE_MAP:
+
+ // adjust target to steer to the proper face, then fall through to the 2D texture path.
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + desc->m_req.m_face;
+
+ case GL_TEXTURE_2D:
+ {
+ // check compressed or not
+ if (format->m_chunkSize != 1)
+ {
+ Assert( writeWholeSlice ); //subimage not implemented in this path yet
+
+ // compressed path
+ // http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage2D.xml
+ glCompressedTexImage2D( target, // target
+ desc->m_req.m_mip, // level
+ intformat, // internalformat - don't use format->m_glIntFormat because we have the SRGB select going on above
+ slice->m_xSize, // width
+ slice->m_ySize, // height
+ 0, // border
+ slice->m_storageSize, // imageSize
+ sliceAddress ); // data
+ GLMCheckError();
+
+
+ }
+ else
+ {
+ if (mayUseSubImage)
+ {
+ // go subimage2D if it's a replacement, not a creation
+
+
+ glPixelStorei( GL_UNPACK_ROW_LENGTH, slice->m_xSize ); // in pixels
+ glPixelStorei( GL_UNPACK_SKIP_PIXELS, writeBox.xmin ); // in pixels
+ glPixelStorei( GL_UNPACK_SKIP_ROWS, writeBox.ymin ); // in pixels
+ GLMCheckError();
+
+ glTexSubImage2D( target,
+ desc->m_req.m_mip, // level
+ writeBox.xmin, // xoffset into dest
+ writeBox.ymin, // yoffset into dest
+ writeBox.xmax - writeBox.xmin, // width (was slice->m_xSize)
+ writeBox.ymax - writeBox.ymin, // height (was slice->m_ySize)
+ glDataFormat, // format
+ glDataType, // type
+ sliceAddress // data (will be offsetted by the SKIP_PIXELS and SKIP_ROWS - let GL do the math to find the first source texel)
+ );
+ GLMCheckError();
+
+ glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+ glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ GLMCheckError();
+
+ /*
+ //http://www.opengl.org/sdk/docs/man/xhtml/glTexSubImage2D.xml
+ glTexSubImage2D( target,
+ desc->m_req.m_mip, // level
+ 0, // xoffset
+ 0, // yoffset
+ slice->m_xSize, // width
+ slice->m_ySize, // height
+ glDataFormat, // format
+ glDataType, // type
+ sliceAddress // data
+ );
+ GLMCheckError();
+ */
+ }
+ else
+ {
+ if (m_layout->m_key.m_texFlags & kGLMTexRenderable)
+ {
+ if (gl_rt_forcergba/* .GetInt() */)
+ {
+ if (glDataFormat == GL_BGRA)
+ {
+ // change it
+ glDataFormat = GL_RGBA;
+ }
+ }
+ }
+
+ // uncompressed path
+ // http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/teximage2d.html
+ glTexImage2D( target, // target
+ desc->m_req.m_mip, // level
+ intformat, // internalformat - don't use format->m_glIntFormat because we have the SRGB select going on above
+ slice->m_xSize, // width
+ slice->m_ySize, // height
+ 0, // border
+ glDataFormat, // dataformat
+ glDataType, // datatype
+ noDataWrite ? NULL : sliceAddress ); // data (optionally suppressed in case ResetSRGB desires)
+
+ if (m_layout->m_key.m_texFlags & kGLMTexMultisampled)
+ {
+ if (gl_texmsaalog/* .GetInt() */)
+ {
+ printf( "\n == MSAA Tex %p %s : glTexImage2D for flat tex using intformat %s (%x)", this, m_debugLabel?m_debugLabel:"", GLMDecode( eGL_ENUM, intformat ), intformat );
+ printf( "\n" );
+ }
+ }
+
+ m_sliceFlags[ desc->m_sliceIndex ] |= kSliceValid; // for next time, we can subimage..
+ }
+ }
+ }
+ break;
+
+ case GL_TEXTURE_3D:
+ {
+ // check compressed or not
+ if (format->m_chunkSize != 1)
+ {
+ // compressed path
+ // http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage3D.xml
+
+ glCompressedTexImage3D( target, // target
+ desc->m_req.m_mip, // level
+ format->m_glIntFormat, // internalformat
+ slice->m_xSize, // width
+ slice->m_ySize, // height
+ slice->m_zSize, // depth
+ 0, // border
+ slice->m_storageSize, // imageSize
+ sliceAddress ); // data
+ GLMCheckError();
+ }
+ else
+ {
+ // uncompressed path
+ // http://www.opengl.org/sdk/docs/man/xhtml/glTexImage3D.xml
+ glTexImage3D( target, // target
+ desc->m_req.m_mip, // level
+ format->m_glIntFormat, // internalformat
+ slice->m_xSize, // width
+ slice->m_ySize, // height
+ slice->m_zSize, // depth
+ 0, // border
+ glDataFormat, // dataformat
+ glDataType, // datatype
+ noDataWrite ? NULL : sliceAddress ); // data (optionally suppressed in case ResetSRGB desires)
+ GLMCheckError();
+ }
+ }
+ break;
+ }
+
+ glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE );
+ GLMCheckError();
+
+ if ( expandTemp )
+ {
+ free( expandTemp );
+ }
+}
+
+
+void CGLMTex::Lock( GLMTexLockParams *params, char** addressOut, int* yStrideOut, int *zStrideOut )
+{
+ // locate appropriate slice in layout record
+ int sliceIndex = CalcSliceIndex( params->m_face, params->m_mip );
+
+ GLMTexLayoutSlice *slice = &m_layout->m_slices[sliceIndex];
+
+ // obtain offset
+ int sliceBaseOffset = slice->m_storageOffset;
+
+ // cross check region req against slice bounds - figure out if it matches, exceeds, or is less than the whole slice.
+ char exceed = (params->m_region.xmin < 0) || (params->m_region.xmax > slice->m_xSize) ||
+ (params->m_region.ymin < 0) || (params->m_region.ymax > slice->m_ySize) ||
+ (params->m_region.zmin < 0) || (params->m_region.zmax > slice->m_zSize);
+
+ char partial = (params->m_region.xmin > 0) || (params->m_region.xmax < slice->m_xSize) ||
+ (params->m_region.ymin > 0) || (params->m_region.ymax < slice->m_ySize) ||
+ (params->m_region.zmin > 0) || (params->m_region.zmax < slice->m_zSize);
+
+ bool copyout = false; // set if a readback of the texture slice from GL is needed
+
+ if (exceed)
+ {
+ // illegal rect, out of bounds
+ GLMStop();
+ }
+
+ // on return, these things need to be true
+
+ // a - there needs to be storage allocated, which we will return an address within
+ // b - the region corresponding to the slice being locked, will have valid data there for the whole slice.
+ // c - the slice is marked as locked
+ // d - the params of the lock request have been saved in the lock table (in the context)
+
+ // so step 1 is unambiguous. If there's no backing storage, make some.
+ if (!m_backing)
+ {
+ m_backing = (char *)malloc( m_layout->m_storageTotalSize );
+ memset( m_backing, 0, m_layout->m_storageTotalSize );
+
+ // clear the kSliceStorageValid bit on all slices
+ for( int i=0; im_sliceCount; i++)
+ {
+ m_sliceFlags[i] &= ~kSliceStorageValid;
+ }
+ }
+
+ // work on this slice now
+
+ // storage is known to exist at this point, but we need to check if its contents are valid for this slice.
+ // this is tracked per-slice so we don't hoist all the texels back out of GL across all slices if caller only
+ // wanted to lock some of them.
+
+ // (i.e. if we just alloced it, it's blank)
+ // if storage is invalid, but the texture itself is valid, hoist the texels back to the storage and mark it valid.
+ // if storage is invalid, and texture itself is also invalid, go ahead and mark storage as valid and fully dirty... to force teximage.
+
+ // ???????????? we need to go over this more carefully re "slice valid" (it has been teximaged) vs "storage valid" (it has been copied out).
+
+ unsigned char *sliceFlags = &m_sliceFlags[ sliceIndex ];
+
+ if (params->m_readback)
+ {
+ // caller is letting us know that it wants to readback the real texels.
+ *sliceFlags |= kSliceStorageValid;
+ *sliceFlags |= kSliceValid;
+ *sliceFlags &= ~(kSliceFullyDirty);
+ copyout = true;
+ }
+ else
+ {
+ // caller is pushing texels.
+ if (! (*sliceFlags & kSliceStorageValid) )
+ {
+ // storage is invalid. check texture state
+ if ( *sliceFlags & kSliceValid )
+ {
+ // kSliceValid set: the texture itself has a valid slice, but we don't have it in our backing copy, so copy it out.
+ copyout = true;
+ }
+ else
+ {
+ // kSliceValid not set: the texture does not have a valid slice to copy out - it hasn't been teximage'd yet.
+ // set the "full dirty" bit to make sure we teximage the whole thing on unlock.
+ *sliceFlags |= kSliceFullyDirty;
+
+ // assert if they did not ask to lock the full slice size on this go-round
+ if (partial)
+ {
+ // choice here -
+ // 1 - stop cold, we don't know how to subimage yet.
+ // 2 - grin and bear it, mark whole slice dirty (ah, we already did... so, do nothing).
+ // choice 2: // GLMStop();
+ }
+ }
+
+ // one way or another, upon reaching here the slice storage is valid for read.
+ *sliceFlags |= kSliceStorageValid;
+ }
+ }
+
+
+ // when we arrive here, there is storage, and the content of the storage for this slice is valid
+ // (or zeroes if it's the first lock)
+
+ // log the lock request in the context.
+ GLMTexLockDesc newdesc;
+
+ newdesc.m_req = *params;
+ newdesc.m_active = true;
+ newdesc.m_sliceIndex = sliceIndex;
+ newdesc.m_sliceBaseOffset = m_layout->m_slices[sliceIndex].m_storageOffset;
+
+ // to calculate the additional offset we need to look at the rect's min corner
+ // combined with the per-texel size and Y/Z stride
+ // also cross check it for 4x multiple if there is compression in play
+
+ int offsetInSlice = 0;
+ int yStride = 0;
+ int zStride = 0;
+
+ CalcTexelDataOffsetAndStrides( sliceIndex, params->m_region.xmin, params->m_region.ymin, params->m_region.zmin, &offsetInSlice, &yStride, &zStride );
+
+ // for compressed case...
+ // since there is presently no way to texsubimage a DXT when the rect does not cover the whole width,
+ // we will probably need to inflate the dirty rect in the recorded lock req so that the entire span is
+ // pushed across at unlock time.
+
+ newdesc.m_sliceRegionOffset = offsetInSlice + newdesc.m_sliceBaseOffset;
+
+ if (copyout)
+ {
+ // read the whole slice
+ // (odds are we'll never request anything but a whole slice to be read..)
+ ReadTexels( &newdesc, true );
+ } // this would be a good place to fill with scrub value if in debug...
+
+ *addressOut = m_backing + newdesc.m_sliceRegionOffset;
+ *yStrideOut = yStride;
+ *zStrideOut = zStride;
+
+ m_ctx->m_texLocks.push_back( newdesc );
+
+ m_lockCount++;
+}
+
+void CGLMTex::Unlock( GLMTexLockParams *params )
+{
+ // look for an active lock request on this face and mip (doesn't necessarily matter which one, if more than one)
+ // and mark it inactive.
+ // --> if you can't find one, fail. first line of defense against mismatched locks/unlocks..
+
+ int i=0;
+ bool found = false;
+ while( !found && (im_texLocks.size()) )
+ {
+ GLMTexLockDesc *desc = &m_ctx->m_texLocks[i];
+
+ // is lock at index 'i' targeted at the texture/face/mip in question?
+ if ( (desc->m_req.m_tex == this) && (desc->m_req.m_face == params->m_face) & (desc->m_req.m_mip == params->m_mip) && (desc->m_active) )
+ {
+ // matched and active, so retire it
+ desc->m_active = false;
+
+ // stop searching
+ found = true;
+ }
+ i++;
+ }
+
+ if (!found)
+ {
+ GLMStop(); // bad news
+ }
+
+ // found - so drop lock count
+ m_lockCount--;
+
+ if (m_lockCount <0)
+ {
+ GLMStop(); // bad news
+ }
+
+ if (m_lockCount==0)
+ {
+ // there should not be any active locks remaining on this texture.
+
+ // motivation to defer all texel pushing til *all* open locks are closed out -
+ // if/when we back the texture with a PBO, we will need to unmap that PBO before teximaging from it;
+ // by waiting for all the locks to clear this gives us an unambiguous signal to act on.
+
+ // scan through all the retired locks for this texture and push the texels for each one.
+ // after each one is dispatched, remove it from the pile.
+
+ int j=0;
+ while( jm_texLocks.size() )
+ {
+ GLMTexLockDesc *desc = &m_ctx->m_texLocks[j];
+
+ if ( desc->m_req.m_tex == this )
+ {
+ // if it's active, something is wrong
+ if (desc->m_active)
+ {
+ GLMStop();
+ }
+
+ // write the texels
+ bool fullyDirty = false;
+
+ fullyDirty |= ((m_sliceFlags[ desc->m_sliceIndex ] & kSliceFullyDirty) != 0);
+
+ // this is not optimal and will result in full downloads on any dirty.
+ // we're papering over the fact that subimage isn't done yet.
+ // but this is safe if the slice of storage is all valid.
+
+ // at some point we'll need to actually compare the lock box against the slice bounds.
+
+ // fullyDirty |= (m_sliceFlags[ desc->m_sliceIndex ] & kSliceStorageValid);
+
+ WriteTexels( desc, fullyDirty );
+
+ // logical place to trigger preloading
+ // only do it for an RT tex, if it is not yet attached to any FBO.
+ // also, only do it if the slice number is the last slice in the tex.
+ if ( desc->m_sliceIndex == (m_layout->m_sliceCount-1) )
+ {
+ if ( !(m_layout->m_key.m_texFlags & kGLMTexRenderable) || (m_rtAttachCount==0) )
+ {
+ m_ctx->PreloadTex( this );
+ // printf("( slice %d of %d )", desc->m_sliceIndex, m_layout->m_sliceCount );
+ }
+ }
+
+ m_ctx->m_texLocks.erase( m_ctx->m_texLocks.begin() + j ); // remove from the pile, don't advance index
+ }
+ else
+ {
+ j++; // move on to next one
+ }
+ }
+
+ // clear the locked and full-dirty flags for all slices
+ for( int slice=0; slice < m_layout->m_sliceCount; slice++)
+ {
+ m_sliceFlags[slice] &= ~( kSliceLocked | kSliceFullyDirty );
+ }
+ }
+}
+
+
+void CGLMTex::ResetSRGB( bool srgb, bool noDataWrite )
+{
+ // see if requested SRGB state differs from the known one
+ bool wasSRGB = (m_layout->m_key.m_texFlags & kGLMTexSRGB);
+ GLMTexLayout *oldLayout = m_layout; // need to m_ctx->m_texLayoutTable->DelLayoutRef on this one if we flip
+
+ if (srgb != wasSRGB)
+ {
+ // we're going to need a new layout (though the storage size should be the same - check it)
+ GLMTexLayoutKey newKey = m_layout->m_key;
+
+ newKey.m_texFlags &= (~kGLMTexSRGB); // turn off that bit
+ newKey.m_texFlags |= srgb ? kGLMTexSRGB : 0; // turn on that bit if it should be so
+
+ // get new layout
+ GLMTexLayout *newLayout = m_ctx->m_texLayoutTable->NewLayoutRef( &newKey );
+
+
+ // if SRGB requested, verify that the layout we just got can do it.
+ // if it can't, delete the new layout ref and bail.
+ if (srgb && (newLayout->m_format->m_glIntFormatSRGB == 0))
+ {
+ Assert( !"Can't enable SRGB mode on this format" );
+ m_ctx->m_texLayoutTable->DelLayoutRef( newLayout );
+ return;
+ }
+
+ // check sizes and fail if no match
+ if( newLayout->m_storageTotalSize != oldLayout->m_storageTotalSize )
+ {
+ Assert( !"Bug: layout sizes don't match on SRGB change" );
+ m_ctx->m_texLayoutTable->DelLayoutRef( newLayout );
+ return;
+ }
+
+ // commit to new layout
+ m_layout = newLayout;
+
+ // check same size
+ Assert( m_layout->m_storageTotalSize == oldLayout->m_storageTotalSize );
+
+ // release old
+ m_ctx->m_texLayoutTable->DelLayoutRef( oldLayout );
+ oldLayout = NULL;
+
+ // force texel re-DL
+
+ // note this messes with TMU 0 as side effect of WriteTexels
+ // so we save and restore the TMU 0 binding first
+
+ // since we're likely to be called in dxabstract when it is syncing sampler state, we can't go trampling the bindings.
+ // a refinement would be to have each texture make a note of which TMU they're bound on, and just use that active TMU for DL instead of 0.
+ CGLMTex *tmu0save = m_ctx->m_samplers[0].m_drawTex;
+
+ for( int face=0; face m_faceCount; face++)
+ {
+ for( int mip=0; mip m_mipCount; mip++)
+ {
+ // we're not really going to lock, we're just going to rewrite the orig data
+ GLMTexLockDesc desc;
+
+ desc.m_req.m_tex = this;
+ desc.m_req.m_face = face;
+ desc.m_req.m_mip = mip;
+
+ desc.m_sliceIndex = CalcSliceIndex( face, mip );
+
+ GLMTexLayoutSlice *slice = &m_layout->m_slices[ desc.m_sliceIndex ];
+
+ desc.m_req.m_region.xmin = desc.m_req.m_region.ymin = desc.m_req.m_region.zmin = 0;
+ desc.m_req.m_region.xmax = slice->m_xSize;
+ desc.m_req.m_region.ymax = slice->m_ySize;
+ desc.m_req.m_region.zmax = slice->m_zSize;
+
+ desc.m_sliceBaseOffset = slice->m_storageOffset; // doesn't really matter... we're just pushing zeroes..
+ desc.m_sliceRegionOffset = 0;
+
+ this->WriteTexels( &desc, true, noDataWrite ); // write whole slice. and avoid pushing real bits if the caller requests (RT's)
+ }
+ }
+
+ // put it back
+ m_ctx->BindTexToTMU( tmu0save, 0, true );
+ }
+}
diff --git a/My project/sdk/glmgr/cglmtex.h b/My project/sdk/glmgr/cglmtex.h
new file mode 100644
index 000000000..241434b78
--- /dev/null
+++ b/My project/sdk/glmgr/cglmtex.h
@@ -0,0 +1,291 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// cglmtex.h
+// GLMgr textures
+//
+//===============================================================================
+
+#ifndef CGLMTEX_H
+#define CGLMTEX_H
+
+#pragma once
+
+#ifdef OSX
+#include "glmgrbasics.h"
+#endif
+
+//===============================================================================
+
+// forward declarations
+
+class GLMContext;
+class GLMTester;
+class CGLMTexLayoutTable;
+class CGLMTex;
+class CGLMFBO;
+
+struct IDirect3DSurface9;
+
+//===============================================================================
+
+struct GLMTexFormatDesc
+{
+ const char *m_formatSummary; // for debug visibility
+
+ D3DFORMAT m_d3dFormat; // what D3D knows it as; see public/bitmap/imageformat.h
+
+ GLenum m_glIntFormat; // GL internal format
+ GLenum m_glIntFormatSRGB; // internal format if SRGB flavor
+ GLenum m_glDataFormat; // GL data format
+ GLenum m_glDataType; // GL data type
+
+ int m_chunkSize; // 1 or 4 - 4 is used for compressed textures
+ int m_bytesPerSquareChunk; // how many bytes for the smallest quantum (m_chunkSize x m_chunkSize)
+ // this description lets us calculate size cleanly without conditional logic for compression
+};
+const GLMTexFormatDesc *GetFormatDesc( D3DFORMAT format );
+
+//===============================================================================
+
+// utility function for generating slabs of texels. mostly for test.
+typedef struct
+{
+ // in
+ D3DFORMAT m_format;
+ void *m_dest; // dest address
+ int m_chunkCount; // square chunk count (single texels or compressed blocks)
+ int m_byteCountLimit; // caller expectation of max number of bytes to write out
+ float r,g,b,a; // color desired
+
+ // out
+ int m_bytesWritten;
+} GLMGenTexelParams;
+
+// return true if successful
+bool GLMGenTexels( GLMGenTexelParams *params );
+
+
+//===============================================================================
+
+struct GLMTexLayoutSlice
+{
+ int m_xSize,m_ySize,m_zSize; //texel dimensions of this slice
+ int m_storageOffset; //where in the storage slab does this slice live
+ int m_storageSize; //how much storage does this slice occupy
+};
+
+enum EGLMTexFlags
+{
+ kGLMTexMipped = 0x01,
+ kGLMTexMippedAuto = 0x02,
+ kGLMTexRenderable = 0x04,
+ kGLMTexIsStencil = 0x08,
+ kGLMTexIsDepth = 0x10,
+ kGLMTexSRGB = 0x20,
+ kGLMTexMultisampled = 0x40, // has an RBO backing it. Cannot combine with Mipped, MippedAuto. One slice maximum, only targeting GL_TEXTURE_2D.
+ // actually not 100% positive on the mipmapping, the RBO itself can't be mipped, but the resulting texture could
+ // have mipmaps generated.
+};
+
+//===============================================================================
+
+struct GLMTexLayoutKey
+{
+ // input values: held const, these are the hash key for the form map
+ GLenum m_texGLTarget; // flavor of texture: GL_TEXTURE_2D, GL_TEXTURE_3D, GLTEXTURE_CUBE_MAP
+ D3DFORMAT m_texFormat; // D3D texel format
+ unsigned long m_texFlags; // mipped, autogen mips, render target, ... ?
+ unsigned long m_texSamples; // zero for a plain tex, 2/4/6/8 for "MSAA tex" (RBO backed)
+ int m_xSize,m_ySize,m_zSize; // size of base mip
+};
+
+struct LessThan_GLMTexLayoutKey
+{
+ bool operator()(const GLMTexLayoutKey &a, const GLMTexLayoutKey &b) const
+ {
+ #define DO_LESS(fff) if (a.fff != b.fff) { return (a.fff< b.fff); }
+
+ DO_LESS(m_texGLTarget);
+ DO_LESS(m_texFormat);
+ DO_LESS(m_texFlags);
+ DO_LESS(m_xSize);
+ DO_LESS(m_ySize)
+ DO_LESS(m_zSize);
+
+ #undef DO_LESS
+
+ return false; // they are equal
+ }
+};
+
+#define GLM_TEX_MAX_MIPS 14
+#define GLM_TEX_MAX_FACES 6
+#define GLM_TEX_MAX_SLICES (GLM_TEX_MAX_MIPS * GLM_TEX_MAX_FACES)
+
+struct GLMTexLayout
+{
+ char *m_layoutSummary; // for debug visibility
+
+ // const inputs used for hashing
+ GLMTexLayoutKey m_key;
+
+ // refcount
+ int m_refCount;
+
+ // derived values:
+ GLMTexFormatDesc *m_format; // format specific info
+ int m_mipCount; // derived by starying at base size and working down towards 1x1
+ int m_faceCount; // 1 for 2d/3d, 6 for cubemap
+ int m_sliceCount; // product of faces and mips
+ int m_storageTotalSize; // size of storage slab required
+
+ // slice array
+ GLMTexLayoutSlice m_slices[0]; // dynamically allocated 2-d array [faces][mips]
+};
+
+typedef std::map< GLMTexLayoutKey, GLMTexLayout*, LessThan_GLMTexLayoutKey > GLMTexLayoutKeyMap;
+class CGLMTexLayoutTable
+{
+public:
+ CGLMTexLayoutTable();
+
+ GLMTexLayout *NewLayoutRef( GLMTexLayoutKey *key ); // pass in a pointer to layout key - receive ptr to completed layout
+ void DelLayoutRef( GLMTexLayout *layout ); // pass in pointer to completed layout. refcount is dropped.
+
+ void DumpStats( void );
+protected:
+ GLMTexLayoutKeyMap m_layoutMap;
+};
+
+//===============================================================================
+
+// a sampler specifies desired state for drawing on a given sampler index
+// this is the combination of a texture choice and a set of sampler parameters
+// see http://msdn.microsoft.com/en-us/library/bb172602(VS.85).aspx
+
+
+struct GLMTexSamplingParams
+{
+ GLenum m_addressModes[3]; // S, T, R
+ GLfloat m_borderColor[4]; // R,G,B,A
+
+ GLenum m_magFilter;
+ GLenum m_minFilter;
+
+ GLfloat m_mipmapBias;
+ GLint m_minMipLevel;
+ GLint m_maxMipLevel;
+ GLint m_maxAniso;
+ GLenum m_compareMode; // only used for depth and stencil type textures
+ bool m_srgb; // srgb texture read...
+};
+
+struct GLMTexLockParams
+{
+ // input params which identify the slice of interest
+ CGLMTex *m_tex;
+ int m_face;
+ int m_mip;
+
+ // identifies the region of the slice
+ GLMRegion m_region;
+
+ // tells GLM to force re-read of the texels back from GL
+ // i.e. "I know I stepped on those texels with a draw or blit - the GLM copy is stale"
+ bool m_readback;
+};
+
+struct GLMTexLockDesc
+{
+ GLMTexLockParams m_req; // form of the lock request
+
+ bool m_active; // set true at lock time. cleared at unlock time.
+
+ int m_sliceIndex; // which slice in the layout
+ int m_sliceBaseOffset; // where is that in the texture data
+ int m_sliceRegionOffset; // offset to the start (lowest address corner) of the region requested
+};
+
+//===============================================================================
+
+#define GLM_SAMPLER_COUNT 16
+
+typedef unsigned short CTexBindMask; // 16 bits, who needs bitvec...
+
+enum EGLMTexSliceFlag
+{
+ kSliceValid = 0x01, // slice has been teximage'd in whole at least once - set to 0 initially
+ kSliceStorageValid = 0x02, // if backing store is available, this slice's data is a valid copy - set to 0 initially
+ kSliceLocked = 0x04, // are one or more locks outstanding on this slice
+ kSliceFullyDirty = 0x08, // does the slice need to be fully downloaded at unlock time (disregard dirty rects)
+};
+
+class CGLMTex
+{
+
+public:
+
+ void Lock( GLMTexLockParams *params, char** addressOut, int* yStrideOut, int *zStrideOut );
+ void Unlock( GLMTexLockParams *params );
+
+protected:
+ friend class GLMContext; // only GLMContext can make CGLMTex objects
+ friend class GLMTester;
+ friend class CGLMFBO;
+
+ friend struct IDirect3DDevice9;
+ friend struct IDirect3DBaseTexture9;
+ friend struct IDirect3DTexture9;
+ friend struct IDirect3DSurface9;
+ friend struct IDirect3DCubeTexture9;
+ friend struct IDirect3DVolumeTexture9;
+
+ CGLMTex( GLMContext *ctx, GLMTexLayout *layout, GLMTexSamplingParams *sampling, const char *debugLabel = NULL );
+ ~CGLMTex( );
+
+ int CalcSliceIndex( int face, int mip );
+ void CalcTexelDataOffsetAndStrides( int sliceIndex, int x, int y, int z, int *offsetOut, int *yStrideOut, int *zStrideOut );
+
+ void ApplySamplingParams( GLMTexSamplingParams *params, bool noCheck=FALSE );
+
+ void ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice=true );
+ void WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice=true, bool noDataWrite=false );
+ // last param lets us send NULL data ptr (only legal with uncompressed formats, beware)
+ // this helps out ResetSRGB.
+
+ void ResetSRGB( bool srgb, bool noDataWrite );
+ // re-specify texture format to match desired sRGB form
+ // noWrite means send NULL for texel source addresses instead of actual data - ideal for RT's
+
+ GLMTexLayout *m_layout; // layout of texture (shared across all tex with same layout)
+ int m_minActiveMip;//index of lowest mip that has been written. used to drive setting of GL_TEXTURE_MAX_LEVEL.
+ int m_maxActiveMip;//index of highest mip that has been written. used to drive setting of GL_TEXTURE_MAX_LEVEL.
+
+ GLMTexSamplingParams m_sampling; // mirror of sampling params currently embodied in the texture
+ // (consult this at draw time, in order to know if changes need to be made)
+
+ GLMContext *m_ctx; // link back to parent context
+
+ GLuint m_texName; // name of this texture in the context
+ bool m_texClientStorage; // was CS selecetd for texture
+ bool m_texPreloaded; // has it been kicked into VRAM with GLMContext::PreloadTex yet
+
+ GLuint m_rboName; // name of MSAA RBO backing the tex if MSAA enabled (or zero)
+ bool m_rboDirty; // has RBO been drawn on - i.e. needs to be blitted back to texture if texture is going to be sampled from
+
+ CTexBindMask m_bindPoints; // true for each place in the parent ctx where currently
+ // bound (indexed via EGLMTexCtxBindingIndex)
+
+ int m_rtAttachCount; // how many RT's have this texture attached somewhere
+
+ char *m_backing; // backing storage if available
+
+ int m_lockCount; // lock reqs are stored in the GLMContext for tracking
+
+ std::vector m_sliceFlags;
+
+ char *m_debugLabel; // strdup() of debugLabel passed in, or NULL
+};
+
+
+#endif
diff --git a/My project/sdk/glmgr/dx9asmtogl2.cpp b/My project/sdk/glmgr/dx9asmtogl2.cpp
new file mode 100644
index 000000000..dc89d033e
--- /dev/null
+++ b/My project/sdk/glmgr/dx9asmtogl2.cpp
@@ -0,0 +1,3524 @@
+//------------------------------------------------------------------------------
+// DX9AsmToGL2.cpp
+//------------------------------------------------------------------------------
+
+#include "dxabstract.h"
+#include "dx9asmtogl2.h"
+
+#ifdef OSX
+// Debugger - 10.8
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+
+void Error( const char *fmt, ... )
+{
+}
+
+#define DST_REGISTER 0
+#define SRC_REGISTER 1
+
+// Tracking and naming sampler dimensions
+#define SAMPLER_TYPE_2D 0
+#define SAMPLER_TYPE_CUBE 1
+#define SAMPLER_TYPE_3D 2
+#define SAMPLER_TYPE_UNUSED 3
+
+// Flags to PrintUsageAndIndexToString.
+#define SEMANTIC_OUTPUT 0x01
+#define SEMANTIC_INPUT 0x02
+
+#define UNDECLARED_OUTPUT 0xFFFFFFFF
+
+#ifndef POSIX
+#define Debugger() Assert(0)
+#endif
+
+static const char *g_szVecZeros[] = { NULL, "0.0", "vec2( 0.0, 0.0 )", "vec3( 0.0, 0.0, 0.0 )", "vec4( 0.0, 0.0, 0.0, 0.0 )" };
+static const char *g_szVecOnes[] = { NULL, "1.0", "vec2( 1.0, 1.0 )", "vec3( 1.0, 1.0, 1.0 )", "vec4( 1.0, 1.0, 1.0, 1.0 )" };
+static const char *g_szDefaultSwizzle = "xyzw";
+static const char *g_szSamplerStrings[] = { "2D", "CUBE", "3D" };
+
+static const char *g_pAtomicTempVarName = "atomic_temp_var";
+static const char *g_pTangentAttributeName = "g_tangent";
+
+int __cdecl SortInts( const int *a, const int *b )
+{
+ if ( *a < *b )
+ return -1;
+ else if ( *a > *b )
+ return 1;
+ else
+ return 0;
+}
+
+void StripExtraTrailingZeros( char *pStr )
+{
+ int len = (int)V_strlen( pStr );
+ while ( len >= 2 && pStr[len-1] == '0' && pStr[len-2] != '.' )
+ {
+ pStr[len-1] = 0;
+ --len;
+ }
+}
+
+void PrintToBuf( CUtlBuffer &buf, const char *pFormat, ... )
+{
+ va_list marker;
+ va_start( marker, pFormat );
+
+ char szTemp[1024];
+ V_vsnprintf( szTemp, sizeof( szTemp ), pFormat, marker );
+ va_end( marker );
+
+ strcat_s( (char*)buf.Base(), buf.Size(), szTemp );
+}
+
+void PrintToBuf( char *pOut, int nOutSize, const char *pFormat, ... )
+{
+ (void)nOutSize;
+
+ int nStrlen = V_strlen( pOut );
+ pOut += nStrlen;
+ nOutSize -= nStrlen;
+
+ va_list marker;
+ va_start( marker, pFormat );
+ V_vsnprintf( pOut, nOutSize, pFormat, marker );
+ va_end( marker );
+}
+
+// Return the number of letters following the dot.
+// Returns 4 if there is no dot.
+// (So "r0.xy" returns 2 and "r0" returns 4).
+int GetNumWriteMaskEntries( const char *pParam )
+{
+ const char *pDot = strchr( pParam, '.' );
+ if ( pDot )
+ return V_strlen( pDot + 1 );
+ else
+ return 4;
+}
+
+const char* GetSwizzleDot( const char *pParam )
+{
+ const char *pDot = strrchr( pParam, '.' );
+
+ // The test against ')' here is for stuff like vec4( gl_Normal, 0.0 ) - we want to treat that as a whole param name.
+ if ( pDot && strrchr( pParam, ')' ) < pDot && strrchr( pParam, ']' ) < pDot )
+ return pDot;
+ else
+ return NULL;
+}
+
+int GetNumSwizzleComponents( const char *pParam )
+{
+ // Special scalar output which won't accept a swizzle
+ if ( !V_stricmp( pParam, "gl_FogFragCoord" ) )
+ return 1;
+
+ // Special scalar output which won't accept a swizzle
+ if ( !V_stricmp( pParam, "gl_FragDepth" ) )
+ return 1;
+
+ // Special scalar output which won't accept a swizzle
+ if ( !V_stricmp( pParam, "a0" ) )
+ return 1;
+
+ const char *pDot = GetSwizzleDot( pParam );
+ if ( pDot )
+ return V_strlen( pDot + 1 );
+ else
+ return 0;
+}
+
+char GetSwizzleComponent( const char *pParam, int n )
+{
+ Assert( n < 4 );
+
+ const char *pDot = GetSwizzleDot( pParam );
+ if ( pDot )
+ {
+ ++pDot;
+ int nComponents = (int)V_strlen( pDot );
+ Assert( nComponents > 0 );
+
+ if ( n < nComponents )
+ return pDot[n];
+ else
+ return pDot[nComponents-1];
+ }
+
+ return g_szDefaultSwizzle[n];
+}
+
+// Replace the parameter name and leave the swizzle intact.
+// So "somevar.xyz" becomes "othervar.xyz".
+void ReplaceParamName( const char *pSrc, const char *pNewParamName, char *pOut, int nOutLen )
+{
+ // Start with the new parameter name.
+ V_strncpy( pOut, pNewParamName, nOutLen );
+
+ // Now add the swizzle if necessary.
+ const char *pDot = GetSwizzleDot( pSrc );
+ if ( pDot )
+ {
+ strncat( pOut, pDot, nOutLen - strlen( pOut ) - 1 );
+ }
+}
+
+void GetParamNameWithoutSwizzle( const char *pParam, char *pOut, int nOutLen )
+{
+ const char *pDot = GetSwizzleDot( pParam );
+
+ // The test against ')' here is for stuff like vec4( gl_Normal, 0.0 ) - we want to treat that as a whole param name.
+ if ( pDot )
+ {
+ int nToCopy = std::min( nOutLen-1, pDot - pParam );
+ memcpy( pOut, pParam, nToCopy );
+ pOut[nToCopy] = 0;
+ }
+ else
+ {
+ V_strncpy( pOut, pParam, nOutLen );
+ }
+}
+
+bool DoParamNamesMatch( const char *pParam1, const char *pParam2 )
+{
+ char szTemp[2][256];
+ GetParamNameWithoutSwizzle( pParam1, szTemp[0], sizeof( szTemp[0] ) );
+ GetParamNameWithoutSwizzle( pParam2, szTemp[1], sizeof( szTemp[1] ) );
+ return ( V_stricmp( szTemp[0], szTemp[1] ) == 0 );
+}
+
+
+
+// Extract the n'th component of the swizzle mask.
+// If n would exceed the length of the swizzle mask, then it looks up into "xyzw".
+void WriteParamWithSingleMaskEntry( const char *pParam, int n, char *pOut, int nOutLen )
+{
+ GetParamNameWithoutSwizzle( pParam, pOut, nOutLen );
+ PrintToBuf( pOut, nOutLen, "." );
+ PrintToBuf( pOut, nOutLen, "%c", GetSwizzleComponent( pParam, n ) );
+}
+
+
+float uint32ToFloat( uint32 dw )
+{
+ return *((float*)&dw);
+}
+
+CUtlString EnsureNumSwizzleComponents( const char *pStr, int nComponents )
+{
+ int nExisting = GetNumSwizzleComponents( pStr );
+ if ( nExisting == nComponents )
+ return pStr;
+
+ char szReg[256];
+ GetParamNameWithoutSwizzle( pStr, szReg, sizeof( szReg ) );
+ if ( nComponents == 0 )
+ return szReg;
+
+ PrintToBuf( szReg, sizeof( szReg ), "." );
+ if ( nExisting > nComponents )
+ {
+ // DX ASM will sometimes have statements like "NRM r0.xyz, r1.yzww", where it just doesn't use the last part of r1. So we won't either.
+ for ( int i=0; i < nComponents; i++ )
+ {
+ PrintToBuf( szReg, sizeof( szReg ), "%c", GetSwizzleComponent( pStr, i ) );
+ }
+ }
+ else
+ {
+ if ( nExisting == 0 )
+ {
+ // We've got something like r0 and need N more components, so add as much of "xyzw" is needed.
+ for ( int i=0; i < nComponents; i++ )
+ PrintToBuf( szReg, sizeof( szReg ), "%c", g_szDefaultSwizzle[i] );
+ }
+ else
+ {
+ // We've got something like r0.x and need N more components, so replicate the X so it looks like r0.xxx
+ V_strncpy( szReg, pStr, sizeof( szReg ) );
+ char cLast = pStr[ V_strlen( pStr ) - 1 ];
+ for ( int i=nExisting; i < nComponents; i++ )
+ {
+ PrintToBuf( szReg, sizeof( szReg ), "%c", cLast );
+ }
+ }
+ }
+
+ return szReg;
+}
+
+D3DToGL::D3DToGL()
+{
+}
+
+uint32 D3DToGL::GetNextToken( void )
+{
+ uint32 dwToken = *m_pdwNextToken;
+ m_pdwNextToken++;
+ return dwToken;
+}
+
+void D3DToGL::SkipTokens( uint32 numToSkip )
+{
+ m_pdwNextToken += numToSkip;
+}
+
+uint32 D3DToGL::Opcode( uint32 dwToken )
+{
+ return ( dwToken & D3DSI_OPCODE_MASK );
+}
+
+uint32 D3DToGL::OpcodeSpecificData (uint32 dwToken)
+{
+ return ( ( dwToken & D3DSP_OPCODESPECIFICCONTROL_MASK ) >> D3DSP_OPCODESPECIFICCONTROL_SHIFT );
+}
+
+uint32 D3DToGL::TextureType ( uint32 dwToken )
+{
+ return ( dwToken & D3DSP_TEXTURETYPE_MASK ); // Note this one doesn't shift due to weird D3DSAMPLER_TEXTURE_TYPE enum
+}
+
+
+
+// Print GLSL intrinsic corresponding to particular instruction
+bool D3DToGL::OpenIntrinsic( uint32 inst, char* buff, int nBufLen, uint32 destDimension, uint32 nArgumentDimension )
+{
+ // Some GLSL intrinsics need type conversion, which we do in this routine
+ // As a result, the caller must sometimes close both parentheses, not just one
+ bool bDoubleClose = false;
+
+ if ( nArgumentDimension == 0 )
+ {
+ nArgumentDimension = 4;
+ }
+
+ switch ( inst )
+ {
+ case D3DSIO_RSQ:
+ V_snprintf( buff, nBufLen, "inversesqrt( " );
+ break;
+ case D3DSIO_DP3:
+ case D3DSIO_DP4:
+ if ( destDimension == 1 )
+ {
+ V_snprintf( buff, nBufLen, "dot( " );
+ }
+ else
+ {
+ V_snprintf( buff, nBufLen, "vec%d( dot( ", destDimension );
+ bDoubleClose = true;
+ }
+ break;
+ case D3DSIO_MIN:
+ V_snprintf( buff, nBufLen, "min( " );
+ break;
+ case D3DSIO_MAX:
+ V_snprintf( buff, nBufLen, "max( " );
+ break;
+ case D3DSIO_SLT:
+ if ( nArgumentDimension == 1 )
+ {
+ V_snprintf( buff, nBufLen, "float( " ); // lessThan doesn't have a scalar version
+ }
+ else
+ {
+ V_snprintf( buff, nBufLen, "vec%d( lessThan( ", nArgumentDimension );
+ bDoubleClose = true;
+ }
+ break;
+ case D3DSIO_SGE:
+ if ( nArgumentDimension == 1 )
+ {
+ V_snprintf( buff, nBufLen, "float( " ); // greaterThanEqual doesn't have a scalar version
+ }
+ else
+ {
+ V_snprintf( buff, nBufLen, "vec%d( greaterThanEqual( ", nArgumentDimension );
+ bDoubleClose = true;
+ }
+ break;
+ case D3DSIO_EXP:
+ V_snprintf( buff, nBufLen, "exp( " ); // exp2 ?
+ break;
+ case D3DSIO_LOG:
+ V_snprintf( buff, nBufLen, "log( " ); // log2 ?
+ break;
+ case D3DSIO_LIT:
+ Assert(0);
+ V_snprintf( buff, nBufLen, "lit( " ); // gonna have to write this one
+ break;
+ case D3DSIO_DST:
+ Assert(0);
+ V_snprintf( buff, nBufLen, "dst( " ); // gonna have to write this one
+ break;
+ case D3DSIO_LRP:
+ Assert( !m_bVertexShader );
+ V_snprintf( buff, nBufLen, "mix( " );
+ break;
+ case D3DSIO_FRC:
+ V_snprintf( buff, nBufLen, "fract( " );
+ break;
+ case D3DSIO_M4x4:
+ Assert(0);
+ V_snprintf( buff, nBufLen, "m4x4" );
+ break;
+ case D3DSIO_M4x3:
+ case D3DSIO_M3x4:
+ case D3DSIO_M3x3:
+ case D3DSIO_M3x2:
+ case D3DSIO_CALL:
+ case D3DSIO_CALLNZ:
+ case D3DSIO_LOOP:
+ case D3DSIO_RET:
+ case D3DSIO_ENDLOOP:
+ case D3DSIO_LABEL:
+ case D3DSIO_DCL:
+ Assert(0);
+ break;
+ case D3DSIO_POW:
+ V_snprintf( buff, nBufLen, "pow( " );
+ break;
+ case D3DSIO_CRS:
+ V_snprintf( buff, nBufLen, "cross( " );
+ break;
+ case D3DSIO_SGN:
+ Assert(0);
+ V_snprintf( buff, nBufLen, "sign( " );
+ break;
+ case D3DSIO_ABS:
+ V_snprintf( buff, nBufLen, "abs( " );
+ break;
+ case D3DSIO_NRM:
+ Assert( 0 );
+ V_snprintf( buff, nBufLen, "normalize( " );
+ break;
+ case D3DSIO_SINCOS:
+ Assert( 0 );
+ V_snprintf( buff, nBufLen, "sincos( " ); // gonna have to write this one
+ break;
+ case D3DSIO_REP:
+ case D3DSIO_ENDREP:
+ case D3DSIO_IF:
+ case D3DSIO_IFC:
+ case D3DSIO_ELSE:
+ case D3DSIO_ENDIF:
+ case D3DSIO_BREAK:
+ case D3DSIO_BREAKC: // TODO: these are the reason we even need GLSL...gotta make these work
+ Assert(0);
+ break;
+ case D3DSIO_DEFB:
+ case D3DSIO_DEFI:
+ Assert(0);
+ break;
+ case D3DSIO_TEXCOORD:
+ V_snprintf( buff, nBufLen, "texcoord" );
+ break;
+ case D3DSIO_TEXKILL:
+ V_snprintf( buff, nBufLen, "kill( " ); // wrap the discard instruction?
+ break;
+ case D3DSIO_TEX:
+ Assert(0);
+ V_snprintf( buff, nBufLen, "TEX" ); // We shouldn't get here
+ break;
+ case D3DSIO_TEXBEM:
+ case D3DSIO_TEXBEML:
+ case D3DSIO_TEXREG2AR:
+ case D3DSIO_TEXREG2GB:
+ case D3DSIO_TEXM3x2PAD:
+ case D3DSIO_TEXM3x2TEX:
+ case D3DSIO_TEXM3x3PAD:
+ case D3DSIO_TEXM3x3TEX:
+ case D3DSIO_TEXM3x3SPEC:
+ case D3DSIO_TEXM3x3VSPEC:
+ Assert(0);
+ break;
+ case D3DSIO_EXPP:
+ V_snprintf( buff, nBufLen, "exp( " );
+ break;
+ case D3DSIO_LOGP:
+ V_snprintf( buff, nBufLen, "log( " );
+ break;
+ case D3DSIO_CND:
+ Assert(0);
+ break;
+ case D3DSIO_DEF:
+ Assert(0);
+ V_snprintf( buff, nBufLen, "DEF" );
+ break;
+ case D3DSIO_TEXREG2RGB:
+ case D3DSIO_TEXDP3TEX:
+ case D3DSIO_TEXM3x2DEPTH:
+ case D3DSIO_TEXDP3:
+ case D3DSIO_TEXM3x3:
+ Assert(0);
+ break;
+ case D3DSIO_TEXDEPTH:
+ V_snprintf( buff, nBufLen, "texdepth" );
+ break;
+ case D3DSIO_CMP:
+ Assert(0);
+ Assert( !m_bVertexShader );
+ V_snprintf( buff, nBufLen, "CMP" );
+ break;
+ case D3DSIO_BEM:
+ Assert(0);
+ break;
+ case D3DSIO_DP2ADD:
+ Assert(0);
+ break;
+ case D3DSIO_DSX:
+ case D3DSIO_DSY:
+ Assert(0);
+ break;
+ case D3DSIO_TEXLDD:
+ V_snprintf( buff, nBufLen, "texldd" );
+ break;
+ case D3DSIO_SETP:
+ Assert(0);
+ break;
+ case D3DSIO_TEXLDL:
+ V_snprintf( buff, nBufLen, "texldl" );
+ break;
+ case D3DSIO_BREAKP:
+ case D3DSIO_PHASE:
+ Assert(0);
+ break;
+ }
+
+ return bDoubleClose;
+}
+
+
+const char* D3DToGL::GetGLSLOperatorString( uint32 inst )
+{
+ if ( inst == D3DSIO_ADD )
+ return "+";
+ else if ( inst == D3DSIO_SUB )
+ return "-";
+ else if ( inst == D3DSIO_MUL )
+ return "*";
+
+ Error( "GetGLSLOperatorString: unknown operator" );
+ return "zzzz";
+}
+
+
+// Print ASM opcode
+void D3DToGL::PrintOpcode( uint32 inst, char* buff, int nBufLen )
+{
+ switch ( inst )
+ {
+ case D3DSIO_NOP:
+ V_snprintf( buff, nBufLen, "NOP" );
+ Assert(0);
+ break;
+ case D3DSIO_MOV:
+ V_snprintf( buff, nBufLen, "MOV" );
+ break;
+ case D3DSIO_ADD:
+ V_snprintf( buff, nBufLen, "ADD" );
+ break;
+ case D3DSIO_SUB:
+ V_snprintf( buff, nBufLen, "SUB" );
+ break;
+ case D3DSIO_MAD:
+ V_snprintf( buff, nBufLen, "MAD" );
+ break;
+ case D3DSIO_MUL:
+ V_snprintf( buff, nBufLen, "MUL" );
+ break;
+ case D3DSIO_RCP:
+ V_snprintf( buff, nBufLen, "RCP" );
+ break;
+ case D3DSIO_RSQ:
+ V_snprintf( buff, nBufLen, "RSQ" );
+ break;
+ case D3DSIO_DP3:
+ V_snprintf( buff, nBufLen, "DP3" );
+ break;
+ case D3DSIO_DP4:
+ V_snprintf( buff, nBufLen, "DP4" );
+ break;
+ case D3DSIO_MIN:
+ V_snprintf( buff, nBufLen, "MIN" );
+ break;
+ case D3DSIO_MAX:
+ V_snprintf( buff, nBufLen, "MAX" );
+ break;
+ case D3DSIO_SLT:
+ V_snprintf( buff, nBufLen, "SLT" );
+ break;
+ case D3DSIO_SGE:
+ V_snprintf( buff, nBufLen, "SGE" );
+ break;
+ case D3DSIO_EXP:
+ V_snprintf( buff, nBufLen, "EX2" );
+ break;
+ case D3DSIO_LOG:
+ V_snprintf( buff, nBufLen, "LG2" );
+ break;
+ case D3DSIO_LIT:
+ V_snprintf( buff, nBufLen, "LIT" );
+ break;
+ case D3DSIO_DST:
+ V_snprintf( buff, nBufLen, "DST" );
+ break;
+ case D3DSIO_LRP:
+ Assert( !m_bVertexShader );
+ V_snprintf( buff, nBufLen, "LRP" );
+ break;
+ case D3DSIO_FRC:
+ V_snprintf( buff, nBufLen, "FRC" );
+ break;
+ case D3DSIO_M4x4:
+ V_snprintf( buff, nBufLen, "m4x4" );
+ break;
+ case D3DSIO_M4x3:
+ case D3DSIO_M3x4:
+ case D3DSIO_M3x3:
+ case D3DSIO_M3x2:
+ case D3DSIO_CALL:
+ case D3DSIO_CALLNZ:
+ case D3DSIO_LOOP:
+ case D3DSIO_RET:
+ case D3DSIO_ENDLOOP:
+ case D3DSIO_LABEL:
+ Assert(0);
+ break;
+ case D3DSIO_DCL:
+ V_snprintf( buff, nBufLen, "DCL" );
+ break;
+ case D3DSIO_POW:
+ V_snprintf( buff, nBufLen, "POW" );
+ break;
+ case D3DSIO_CRS:
+ V_snprintf( buff, nBufLen, "XPD" );
+ break;
+ case D3DSIO_SGN:
+ Assert(0);
+ V_snprintf( buff, nBufLen, "SGN" );
+ break;
+ case D3DSIO_ABS:
+ V_snprintf( buff, nBufLen, "ABS" );
+ break;
+ case D3DSIO_NRM:
+ Assert( 0 );
+ V_snprintf( buff, nBufLen, "NRM" );
+ break;
+ case D3DSIO_SINCOS:
+ Assert( !m_bVertexShader );
+ V_snprintf( buff, nBufLen, "SCS" );
+ break;
+ case D3DSIO_REP:
+ case D3DSIO_ENDREP:
+ case D3DSIO_IF:
+ case D3DSIO_IFC:
+ case D3DSIO_ELSE:
+ case D3DSIO_ENDIF:
+ case D3DSIO_BREAK:
+ case D3DSIO_BREAKC:
+ Assert(0);
+ break;
+ case D3DSIO_MOVA:
+ Assert( m_bVertexShader );
+ V_snprintf( buff, nBufLen, "MOV" ); // We're always moving into a temp instead, so this is MOV instead of ARL
+ break;
+ case D3DSIO_DEFB:
+ case D3DSIO_DEFI:
+ Assert(0);
+ break;
+ case D3DSIO_TEXCOORD:
+ V_snprintf( buff, nBufLen, "texcoord" );
+ break;
+ case D3DSIO_TEXKILL:
+ V_snprintf( buff, nBufLen, "KIL" );
+ break;
+ case D3DSIO_TEX:
+ V_snprintf( buff, nBufLen, "TEX" );
+ break;
+ case D3DSIO_TEXBEM:
+ case D3DSIO_TEXBEML:
+ case D3DSIO_TEXREG2AR:
+ case D3DSIO_TEXREG2GB:
+ case D3DSIO_TEXM3x2PAD:
+ case D3DSIO_TEXM3x2TEX:
+ case D3DSIO_TEXM3x3PAD:
+ case D3DSIO_TEXM3x3TEX:
+ case D3DSIO_TEXM3x3SPEC:
+ case D3DSIO_TEXM3x3VSPEC:
+ Assert(0);
+ break;
+ case D3DSIO_EXPP:
+ V_snprintf( buff, nBufLen, "EXP" );
+ break;
+ case D3DSIO_LOGP:
+ V_snprintf( buff, nBufLen, "LOG" );
+ break;
+ case D3DSIO_CND:
+ Assert(0);
+ break;
+ case D3DSIO_DEF:
+ V_snprintf( buff, nBufLen, "DEF" );
+ break;
+ case D3DSIO_TEXREG2RGB:
+ case D3DSIO_TEXDP3TEX:
+ case D3DSIO_TEXM3x2DEPTH:
+ case D3DSIO_TEXDP3:
+ case D3DSIO_TEXM3x3:
+ Assert(0);
+ break;
+ case D3DSIO_TEXDEPTH:
+ V_snprintf( buff, nBufLen, "texdepth" );
+ break;
+ case D3DSIO_CMP:
+ Assert( !m_bVertexShader );
+ V_snprintf( buff, nBufLen, "CMP" );
+ break;
+ case D3DSIO_BEM:
+ Assert(0);
+ break;
+ case D3DSIO_DP2ADD:
+ Assert(0);
+ break;
+ case D3DSIO_DSX:
+ case D3DSIO_DSY:
+ Assert(0);
+ break;
+ case D3DSIO_TEXLDD:
+ V_snprintf( buff, nBufLen, "texldd" );
+ break;
+ case D3DSIO_SETP:
+ Assert(0);
+ break;
+ case D3DSIO_TEXLDL:
+ V_snprintf( buff, nBufLen, "texldl" );
+ break;
+ case D3DSIO_BREAKP:
+ case D3DSIO_PHASE:
+ Assert(0);
+ break;
+ }
+}
+
+CUtlString D3DToGL::GetUsageAndIndexString( uint32 dwToken, int fSemanticFlags )
+{
+ char szTemp[1024];
+ PrintUsageAndIndexToString( dwToken, szTemp, sizeof( szTemp ), fSemanticFlags );
+ return szTemp;
+}
+
+//------------------------------------------------------------------------------
+// Helper function which prints ASCII representation of usage-usageindex pair to string
+//
+// Strictly used by vertex shaders
+// not used any more now that we have attribmap metadata
+//------------------------------------------------------------------------------
+void D3DToGL::PrintUsageAndIndexToString( uint32 dwToken, char* strUsageUsageIndexName, int nBufLen, int fSemanticFlags )
+{
+ uint32 dwUsage = ( dwToken & D3DSP_DCL_USAGE_MASK );
+ uint32 dwUsageIndex = ( dwToken & D3DSP_DCL_USAGEINDEX_MASK ) >> D3DSP_DCL_USAGEINDEX_SHIFT;
+
+ switch ( dwUsage )
+ {
+ case D3DDECLUSAGE_POSITION:
+ if ( m_bGLSL )
+ {
+ if ( m_bVertexShader )
+ {
+ if ( fSemanticFlags & SEMANTIC_OUTPUT )
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vTempPos" ); // effectively gl_Position
+ else
+ V_snprintf( strUsageUsageIndexName, nBufLen, "gl_Vertex" );
+ }
+ else
+ {
+ // .xy = position in viewport coordinates
+ // .z = depth
+ V_snprintf( strUsageUsageIndexName, nBufLen, "gl_FragCoord" );
+ }
+ }
+ else
+ {
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[0]" ); //"vertex.position" ); // aka generic [0]
+ }
+ break;
+ case D3DDECLUSAGE_BLENDWEIGHT:
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[1]" ); // "vertex.attrib[12]" ); // or [1]
+ break;
+ case D3DDECLUSAGE_BLENDINDICES:
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[13]" ); // "vertex.attrib[13]" ); // or [ 7 ]
+ break;
+ case D3DDECLUSAGE_NORMAL:
+ V_snprintf( strUsageUsageIndexName, nBufLen, m_bGLSL ? "vec4( gl_Normal, 0.0 )" : "vertex.attrib[2]" );
+ break;
+ case D3DDECLUSAGE_PSIZE:
+ Assert(0);
+ V_snprintf( strUsageUsageIndexName, nBufLen, "_psize" ); // no analog
+ break;
+ case D3DDECLUSAGE_TEXCOORD:
+ if ( m_bGLSL )
+ {
+ // GLSL vs output and ps inputs reference gl_TexCoord[n], not gl_MultiTexCoord.
+ if ( !m_bVertexShader || (fSemanticFlags & SEMANTIC_OUTPUT) )
+ V_snprintf( strUsageUsageIndexName, nBufLen, "gl_TexCoord[%d]", dwUsageIndex );
+ else
+ V_snprintf( strUsageUsageIndexName, nBufLen, "gl_MultiTexCoord%d", dwUsageIndex );
+ }
+ else
+ {
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[%d]", 8+dwUsageIndex ); // "vertex.texcoord[%d]", dwUsageIndex ); // aka [8] - [15] ?
+ }
+ break;
+ case D3DDECLUSAGE_TANGENT:
+ if ( m_bGLSL )
+ {
+ NoteTangentInputUsed();
+ V_strncpy( strUsageUsageIndexName, g_pTangentAttributeName, nBufLen );
+ }
+ else
+ {
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[15]" ); // aka texc[7]
+ }
+ break;
+ case D3DDECLUSAGE_BINORMAL:
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[14]" ); // aka texc[6]
+ break;
+// case D3DDECLUSAGE_TESSFACTOR:
+// Assert(0);
+// V_snprintf( strUsageUsageIndexName, nBufLen, "_position" ); // no analog
+// break;
+// case D3DDECLUSAGE_POSITIONT:
+// Assert(0);
+// V_snprintf( strUsageUsageIndexName, nBufLen, "_positiont" ); // no analog
+// break;
+ case D3DDECLUSAGE_COLOR:
+ if ( m_bGLSL )
+ {
+// if ( fSemanticFlags & SEMANTIC_OUTPUT )
+// V_snprintf( strUsageUsageIndexName, nBufLen, dwUsageIndex != 0 ? "gl_BackColor" : "gl_FrontColor" );
+// else
+ V_snprintf( strUsageUsageIndexName, nBufLen, dwUsageIndex != 0 ? "gl_SecondaryColor" : "gl_Color" );
+ }
+ else
+ {
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[%d]", 3+dwUsageIndex ); //dwUsageIndex ); // != 0 ? "vertex.color.secondary" : "vertex.color" ); // aka [3] / [4] (second)
+ }
+ break;
+ case D3DDECLUSAGE_FOG:
+ Assert( !m_bGLSL );
+ V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[5]" ); //"vertex.position" /* "_fog" */ ); //FIXME, evil // aka [5] / vertex.fogcoord
+ break;
+ case D3DDECLUSAGE_DEPTH:
+ Assert(0);
+ V_snprintf( strUsageUsageIndexName, nBufLen, "_depth" ); // no analog
+ break;
+ case D3DDECLUSAGE_SAMPLE:
+ Assert(0);
+ V_snprintf( strUsageUsageIndexName, nBufLen, "_sample" ); // no analog
+ break;
+ default:
+ Debugger();
+ break;
+ }
+}
+
+uint32 D3DToGL::GetRegType( uint32 dwRegToken )
+{
+ return ( ( dwRegToken & D3DSP_REGTYPE_MASK2 ) >> D3DSP_REGTYPE_SHIFT2 ) | ( ( dwRegToken & D3DSP_REGTYPE_MASK ) >> D3DSP_REGTYPE_SHIFT );
+}
+
+void D3DToGL::PrintIndentation( char *pBuf, int nBufLen )
+{
+ for( int i=0; i 5 && V_strcmp( &pRegister[nLen-5], ".xyzw" ) == 0 )
+ pRegister[nLen-5] = 0;
+}
+
+
+// This returns 0 for x, 1 for y, 2 for z, and 3 for w.
+int GetSwizzleComponentVectorIndex( char chMask )
+{
+ if ( chMask == 'x' )
+ return 0;
+ else if ( chMask == 'y' )
+ return 1;
+ else if ( chMask == 'z' )
+ return 2;
+ else if ( chMask == 'w' )
+ return 3;
+
+ Error( "GetSwizzleComponentVectorIndex( '%c' ) - invalid parameter.\n", chMask );
+ return 0;
+}
+
+
+// GLSL needs the # of src masks to match the dest write mask.
+//
+// So this:
+// r0.xy = r1 + r2;
+// becomes:
+// r0.xy = r1.xy + r2.xy;
+//
+//
+// Also, and this is the trickier one: GLSL reads the source registers from their first component on
+// whereas D3D reads them as referenced in the dest register mask!
+//
+// So this code in D3D:
+// r0.yz = c0.x + c1.wxyz
+// Really means:
+// r0.y = c0.x + c1.x
+// r0.z = c0.x + c1.y
+// So we translate it to this in GLSL:
+// r0.yz = c0.xx + c1.wx
+// r0.yz = c0.xx + c1.xy
+//
+CUtlString D3DToGL::FixGLSLSwizzle( const char *pDestRegisterName, const char *pSrcRegisterName )
+{
+ if ( !m_bGLSL )
+ return pSrcRegisterName;
+
+ int nSwizzlesInDest = GetNumSwizzleComponents( pDestRegisterName );
+ if ( nSwizzlesInDest == 0 )
+ nSwizzlesInDest = 4;
+
+ char szFixedSrcRegister[128];
+ GetParamNameWithoutSwizzle( pSrcRegisterName, szFixedSrcRegister, sizeof( szFixedSrcRegister ) );
+ strncat( szFixedSrcRegister, ".", sizeof(szFixedSrcRegister) - strlen(szFixedSrcRegister) - 1 );
+ for ( int i=0; i < nSwizzlesInDest; i++ )
+ {
+ char chDestWriteMask = GetSwizzleComponent( pDestRegisterName, i );
+ int nVectorIndex = GetSwizzleComponentVectorIndex( chDestWriteMask );
+
+ char ch[2];
+ ch[0] = GetSwizzleComponent( pSrcRegisterName, nVectorIndex );
+ ch[1] = 0;
+ strncat( szFixedSrcRegister, ch, sizeof(szFixedSrcRegister) - strlen(szFixedSrcRegister) - 1 );
+ }
+
+ SimplifyFourParamRegister( szFixedSrcRegister );
+ return szFixedSrcRegister;
+}
+
+// Weird encoding...bits are split apart in the dwToken
+inline uint32 GetRegTypeFromToken( uint32 dwToken )
+{
+ return ( ( dwToken & D3DSP_REGTYPE_MASK2 ) >> D3DSP_REGTYPE_SHIFT2 ) | ( ( dwToken & D3DSP_REGTYPE_MASK ) >> D3DSP_REGTYPE_SHIFT );
+}
+
+void D3DToGL::FlagIndirectRegister( uint32 dwToken, int *pARLDestReg )
+{
+ if ( !pARLDestReg )
+ return;
+
+ switch ( dwToken & D3DVS_SWIZZLE_MASK & D3DVS_X_W )
+ {
+ case D3DVS_X_X:
+ *pARLDestReg = ARL_DEST_X;
+ break;
+ case D3DVS_X_Y:
+ *pARLDestReg = ARL_DEST_Y;
+ break;
+ case D3DVS_X_Z:
+ *pARLDestReg = ARL_DEST_Z;
+ break;
+ case D3DVS_X_W:
+ *pARLDestReg = ARL_DEST_W;
+ break;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// PrintParameterToString()
+//
+// Helper function which prints ASCII representation of passed Parameter dwToken
+// to string. Token defines parameter details. The dwSourceOrDest parameter says
+// whether or not this is a source or destination register
+//------------------------------------------------------------------------------
+void D3DToGL::PrintParameterToString ( uint32 dwToken, uint32 dwSourceOrDest, char *pRegisterName, int nBufLen, bool bForceScalarSource, int *pARLDestReg )
+{
+ char buff[32];
+ bool bAllowWriteMask = true;
+ bool bAllowSwizzle = true;
+
+ uint32 dwRegNum = dwToken & D3DSP_REGNUM_MASK;
+
+ uint32 dwRegType, dwSwizzle;
+ uint32 dwSrcModifier = D3DSPSM_NONE;
+
+ // Clear string to zero length
+ V_snprintf( pRegisterName, nBufLen, "" );
+
+ dwRegType = GetRegTypeFromToken( dwToken );
+
+ // If this is a dest register
+ if ( dwSourceOrDest == DST_REGISTER )
+ {
+ // Instruction modifiers
+ if ( dwToken & D3DSPDM_PARTIALPRECISION )
+ {
+// strcat_s( pRegisterName, nBufLen, "_pp" );
+ }
+
+ if ( dwToken & D3DSPDM_SATURATE && !m_bGLSL )
+ {
+ strcat_s( pRegisterName, nBufLen, "_SAT" );
+ }
+
+ if ( dwToken & D3DSPDM_MSAMPCENTROID)
+ {
+// strcat_s( pRegisterName, nBufLen, "_centroid" );
+ }
+
+ if ( !m_bGLSL )
+ {
+ strcat_s( pRegisterName, nBufLen, " " );
+ }
+ }
+
+ // If this is a source register
+ if ( dwSourceOrDest == SRC_REGISTER )
+ {
+ dwSrcModifier = dwToken & D3DSP_SRCMOD_MASK;
+
+ // If there are any source modifiers, check to see if they're at
+ // least partially "prefix" and prepend appropriately
+ if ( dwSrcModifier != D3DSPSM_NONE )
+ {
+ switch ( dwSrcModifier )
+ {
+ // These four start with just minus... (some may result in "postfix" notation as well later on)
+ case D3DSPSM_NEG: // negate
+ strcat_s( pRegisterName, nBufLen, "-" );
+ break;
+ case D3DSPSM_BIASNEG: // bias and negate
+ case D3DSPSM_SIGNNEG: // sign and negate
+ case D3DSPSM_X2NEG: // *2 and negate
+ Assert(0);
+ strcat_s( pRegisterName, nBufLen, "-" );
+ break;
+ case D3DSPSM_COMP: // complement
+ Assert(0);
+ strcat_s( pRegisterName, nBufLen, "1-" );
+ break;
+ case D3DSPSM_ABS: // abs()
+ if ( m_bGLSL )
+ {
+ strcat_s( pRegisterName, nBufLen, "abs(" );
+ }
+ else if ( !m_bGeneratingDebugText )
+ {
+ Assert( false );
+ }
+ break;
+ case D3DSPSM_ABSNEG: // -abs()
+ if ( m_bGLSL )
+ {
+ strcat_s( pRegisterName, nBufLen, "-abs(" );
+ }
+ else if ( !m_bGeneratingDebugText )
+ {
+ Assert( false );
+ }
+ break;
+ case D3DSPSM_NOT: // for predicate register: "!p0"
+ Assert(0);
+ strcat_s( pRegisterName, nBufLen, "!" );
+ break;
+ }
+ }
+ }
+
+ // Register name (from type and number)
+ switch ( dwRegType )
+ {
+ case D3DSPR_TEMP:
+ V_snprintf( buff, sizeof( buff ), "r%d", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ m_dwTempUsageMask |= 0x00000001 << dwRegNum; // Keep track of the use of this temp
+ break;
+ case D3DSPR_INPUT:
+ if ( !m_bVertexShader && ( dwSourceOrDest == SRC_REGISTER ) && m_bGLSL )
+ {
+ V_snprintf( buff, sizeof( buff ), dwRegNum == 0 ? "gl_Color" : "gl_SecondaryColor" );
+ strcat_s( pRegisterName, nBufLen, buff );
+ }
+ else if ( m_bVertexShader || ( dwSourceOrDest == SRC_REGISTER ) || m_bGLSL )
+ {
+ V_snprintf( buff, sizeof( buff ), "v%d", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ }
+ else // asm pixel shader declaration syntax:
+ {
+ V_snprintf( buff, sizeof( buff ), dwRegNum == 0 ? "v0 = fragment.color" : "v1 = fragment.color.secondary" );
+ strcat_s( pRegisterName, nBufLen, buff );
+ bAllowWriteMask = false;
+ }
+ break;
+ case D3DSPR_CONST:
+ if ( m_bConstantRegisterDefined[dwRegNum] )
+ {
+ char szConstantRegName[3];
+ if ( m_bVertexShader )
+ {
+ V_snprintf( szConstantRegName, 3, "vd" );
+ }
+ else
+ {
+ V_snprintf( szConstantRegName, 3, "pd" );
+ }
+
+ // Put defined constants into their own namespace "d"
+ V_snprintf( buff, sizeof( buff ), "%s%d", szConstantRegName, dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ }
+ else if ( dwToken & D3DSHADER_ADDRESSMODE_MASK ) // Indirect addressing (e.g. skinning in a vertex shader)
+ {
+ char szConstantRegName[3];
+ if ( m_bVertexShader )
+ {
+ V_snprintf( szConstantRegName, 3, "vc" );
+ }
+ else // No indirect addressing in PS, this shouldn't happen
+ {
+ Assert(0);
+ V_snprintf( szConstantRegName, 3, "pc" );
+ }
+
+ // Index into single pc/vc[] register array with relative addressing
+ FlagIndirectRegister( GetNextToken(), pARLDestReg );
+ V_snprintf( buff, sizeof( buff ), m_bGLSL ? "%s[a0 + %d]" : "%s[a0.x + %d]", szConstantRegName, dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ bAllowSwizzle = false;
+
+ m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
+ }
+ else // Direct addressing of constant array
+ {
+ char szConstantRegName[3];
+ V_snprintf( szConstantRegName, 3, m_bVertexShader ? "vc" : "pc" );
+
+ // Index into single pc/vc[] register array with absolute addressing, same for GLSL and ASM
+ V_snprintf( buff, sizeof( buff ), "%s[%d]", szConstantRegName, dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+
+ //// NOGO if (dwRegNum != 255) // have seen cases where dwRegNum is 0xFF... need to figure out where those opcodes are coming from
+ {
+ m_nHighestRegister = std::max( m_nHighestRegister, dwRegNum );
+ }
+
+ Assert( m_nHighestRegister < DXABSTRACT_VS_PARAM_SLOTS );
+ }
+ break;
+ case D3DSPR_ADDR: // aliases to D3DSPR_TEXTURE
+ if ( m_bVertexShader )
+ {
+ if ( m_bGLSL )
+ {
+ Assert( dwRegNum == 0 );
+
+ V_snprintf( buff, sizeof( buff ), "va_r" );
+ }
+ else
+ {
+ V_snprintf( buff, sizeof( buff ), "VA_REG" ); // Move into our temp, rather than a0
+ }
+ }
+ else // D3DSPR_TEXTURE in the pixel shader
+ {
+ // If dest reg, this is an iterator/varying declaration
+ if ( dwSourceOrDest == DST_REGISTER )
+ {
+ if ( m_bGLSL )
+ {
+ // Is this iterator centroid?
+ if ( m_nCentroidMask & ( 0x00000001 << dwRegNum ) )
+ {
+ V_snprintf( buff, sizeof( buff ), "centroid varying vec4 oT%d", dwRegNum ); // centroid varying
+ }
+ else
+ {
+ V_snprintf( buff, sizeof( buff ), "varying vec4 oT%d", dwRegNum );
+ }
+ }
+ else
+ {
+ V_snprintf( buff, sizeof( buff ), "t%d = fragment.texcoord[%d]", dwRegNum, dwRegNum );
+ }
+
+ bAllowWriteMask = false;
+ }
+ else // source register
+ {
+ if ( m_bGLSL )
+ {
+ V_snprintf( buff, sizeof( buff ), "oT%d", dwRegNum );
+ }
+ else
+ {
+ V_snprintf( buff, sizeof( buff ), "t%d", dwRegNum );
+ }
+ }
+ }
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_RASTOUT: // vertex shader oPos
+ Assert( m_bVertexShader );
+ switch( dwRegNum )
+ {
+ case D3DSRO_POSITION:
+ strcat_s( pRegisterName, nBufLen, m_bGLSL ? "vTempPos" : "oPos" ); // In GLSL, this ends up in gl_Position later on
+ m_bDeclareVSOPos = true;
+ break;
+
+ case D3DSRO_FOG:
+ strcat_s( pRegisterName, nBufLen, m_bGLSL ? "gl_FogFragCoord" : "oFog" );
+ m_bDeclareVSOFog = true;
+ break;
+
+ default:
+ printf( "\nD3DSPR_RASTOUT: dwRegNum is %08x and token is %08x", dwRegNum, dwToken );
+ Assert(0);
+ break;
+ }
+ break;
+ case D3DSPR_ATTROUT:
+ Assert( m_bVertexShader );
+ if ( m_bGLSL )
+ {
+ if ( dwRegNum == 0 )
+ {
+ V_snprintf( buff, sizeof( buff ), "gl_FrontColor" );
+ }
+ else if ( dwRegNum == 1 )
+ {
+ V_snprintf( buff, sizeof( buff ), "gl_FrontSecondaryColor" );
+ }
+ else
+ {
+ Error( "Invalid D3DSPR_ATTROUT index" );
+ }
+ }
+ else
+ {
+ V_snprintf( buff, sizeof( buff ), "oD%d", dwRegNum );
+ }
+ strcat_s( pRegisterName, nBufLen, buff );
+ m_bOutputColorRegister[dwRegNum] = true;
+ break;
+ case D3DSPR_TEXCRDOUT: // aliases to D3DSPR_OUTPUT
+ if ( m_bVertexShader )
+ {
+ if ( m_bGLSL )
+ {
+ V_snprintf( buff, sizeof( buff ), "oT%d", dwRegNum );
+ }
+ else
+ {
+ V_snprintf( buff, sizeof( buff ), "oT%d", dwRegNum );
+ }
+ m_dwTexCoordOutMask |= ( 0x00000001 << dwRegNum );
+ }
+ else
+ {
+ V_snprintf( buff, sizeof( buff ), "oC%d", dwRegNum );
+ }
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_CONSTINT:
+ Assert( m_bGLSL && m_bAllowStaticControlFlow );
+ V_snprintf( buff, sizeof( buff ), "i%d", dwRegNum ); // Loops use these
+ strcat_s( pRegisterName, nBufLen, buff );
+ m_dwConstIntUsageMask |= 0x00000001 << dwRegNum; // Keep track of the use of this integer constant
+ break;
+ case D3DSPR_COLOROUT:
+ if ( m_bGLSL )
+ {
+ V_snprintf( buff, sizeof( buff ), "gl_FragData[%d]", dwRegNum );
+ }
+ else
+ {
+ V_snprintf( buff, sizeof( buff ), "oC%d", dwRegNum );
+ }
+ strcat_s( pRegisterName, nBufLen, buff );
+ m_bOutputColorRegister[dwRegNum] = true;
+ break;
+ case D3DSPR_DEPTHOUT:
+ V_snprintf( buff, sizeof( buff ), m_bGLSL ? "gl_FragDepth" : "oDepth" );
+ strcat_s( pRegisterName, nBufLen, buff );
+ m_bOutputDepthRegister = true;
+ break;
+ case D3DSPR_SAMPLER:
+ V_snprintf( buff, sizeof( buff ), m_bGLSL ? "sampler%d" : "texture[%d]", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_CONST2:
+ Assert(0);
+ V_snprintf( buff, sizeof( buff ), "c%d", dwRegNum+2048);
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_CONST3:
+ Assert(0);
+ V_snprintf( buff, sizeof( buff ), "c%d", dwRegNum+4096);
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_CONST4:
+ Assert(0);
+ V_snprintf( buff, sizeof( buff ), "c%d", dwRegNum+6144);
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_CONSTBOOL:
+ Assert( m_bGLSL && m_bAllowStaticControlFlow );
+ V_snprintf( buff, sizeof( buff ), "b%d", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ m_dwConstBoolUsageMask |= 0x00000001 << dwRegNum; // Keep track of the use of this bool constant
+ break;
+ case D3DSPR_LOOP:
+ Assert(0);
+ V_snprintf( buff, sizeof( buff ), "aL%d", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_TEMPFLOAT16:
+ Assert(0);
+ V_snprintf( buff, sizeof( buff ), "temp_float16_xxx%d", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_MISCTYPE:
+ if ( !m_bGLSL && !m_bGeneratingDebugText )
+ {
+ Assert(0);
+ }
+ V_snprintf( buff, sizeof( buff ), "misc%d", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_LABEL:
+ Assert(0);
+ V_snprintf( buff, sizeof( buff ), "label%d", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ case D3DSPR_PREDICATE:
+ Assert(0);
+ V_snprintf( buff, sizeof( buff ), "p%d", dwRegNum );
+ strcat_s( pRegisterName, nBufLen, buff );
+ break;
+ }
+
+ // If this is a dest register
+ if ( dwSourceOrDest == DST_REGISTER )
+ {
+ //
+ // Write masks
+ //
+ // If some (not all, not none) of the write masks are set, we should include them
+ //
+ if ( bAllowWriteMask && ( !((dwToken & D3DSP_WRITEMASK_ALL) == D3DSP_WRITEMASK_ALL) || ((dwToken & D3DSP_WRITEMASK_ALL) == 0x00000000) ) )
+ {
+ // Put the dot on there
+ strcat_s( pRegisterName, nBufLen, "." );
+
+ // Optionally put on the x, y, z or w
+ int nMasksWritten = 0;
+ (void)nMasksWritten;
+
+ if ( dwToken & D3DSP_WRITEMASK_0 )
+ {
+ strcat_s( pRegisterName, nBufLen, "x" );
+ ++nMasksWritten;
+ }
+ if ( dwToken & D3DSP_WRITEMASK_1 )
+ {
+ strcat_s( pRegisterName, nBufLen, "y" );
+ ++nMasksWritten;
+ }
+ if ( dwToken & D3DSP_WRITEMASK_2 )
+ {
+ strcat_s( pRegisterName, nBufLen, "z" );
+ ++nMasksWritten;
+ }
+ if ( dwToken & D3DSP_WRITEMASK_3 )
+ {
+ strcat_s( pRegisterName, nBufLen, "w" );
+ ++nMasksWritten;
+ }
+ }
+ }
+ else // must be a source register
+ {
+ if ( bAllowSwizzle ) // relative addressing hard-codes the swizzle on a0.x
+ {
+ uint32 dwXSwizzle, dwYSwizzle, dwZSwizzle, dwWSwizzle;
+
+ // Mask out the swizzle modifier
+ dwSwizzle = dwToken & D3DVS_SWIZZLE_MASK;
+
+ // If there are any swizzles at all, tack on the appropriate notation
+ if ( dwSwizzle != D3DVS_NOSWIZZLE )
+ {
+ // Separate out the two-bit codes for each component swizzle
+ dwXSwizzle = dwSwizzle & D3DVS_X_W;
+ dwYSwizzle = dwSwizzle & D3DVS_Y_W;
+ dwZSwizzle = dwSwizzle & D3DVS_Z_W;
+ dwWSwizzle = dwSwizzle & D3DVS_W_W;
+
+ // Put on the dot
+ strcat_s( pRegisterName, nBufLen, "." );
+
+ // See where X comes from
+ switch ( dwXSwizzle )
+ {
+ case D3DVS_X_X:
+ strcat_s( pRegisterName, nBufLen, "x" );
+ break;
+ case D3DVS_X_Y:
+ strcat_s( pRegisterName, nBufLen, "y" );
+ break;
+ case D3DVS_X_Z:
+ strcat_s( pRegisterName, nBufLen, "z" );
+ break;
+ case D3DVS_X_W:
+ strcat_s( pRegisterName, nBufLen, "w" );
+ break;
+ }
+
+ if ( !bForceScalarSource )
+ {
+ // If the source of the remaining components are aren't
+ // identical to the source of x, continue with swizzle
+ if ( ((dwXSwizzle >> D3DVS_SWIZZLE_SHIFT) != (dwYSwizzle >> (D3DVS_SWIZZLE_SHIFT + 2))) || // X and Y sources match?
+ ((dwXSwizzle >> D3DVS_SWIZZLE_SHIFT) != (dwZSwizzle >> (D3DVS_SWIZZLE_SHIFT + 4))) || // X and Z sources match?
+ ((dwXSwizzle >> D3DVS_SWIZZLE_SHIFT) != (dwWSwizzle >> (D3DVS_SWIZZLE_SHIFT + 6)))) // X and W sources match?
+ {
+
+ // OpenGL seems to want us to have either 1 or 4 components in a swizzle, so just plow on through the rest
+ switch ( dwYSwizzle )
+ {
+ case D3DVS_Y_X:
+ strcat_s( pRegisterName, nBufLen, "x" );
+ break;
+ case D3DVS_Y_Y:
+ strcat_s( pRegisterName, nBufLen, "y" );
+ break;
+ case D3DVS_Y_Z:
+ strcat_s( pRegisterName, nBufLen, "z" );
+ break;
+ case D3DVS_Y_W:
+ strcat_s( pRegisterName, nBufLen, "w" );
+ break;
+ }
+
+ switch ( dwZSwizzle )
+ {
+ case D3DVS_Z_X:
+ strcat_s( pRegisterName, nBufLen, "x" );
+ break;
+ case D3DVS_Z_Y:
+ strcat_s( pRegisterName, nBufLen, "y" );
+ break;
+ case D3DVS_Z_Z:
+ strcat_s( pRegisterName, nBufLen, "z" );
+ break;
+ case D3DVS_Z_W:
+ strcat_s( pRegisterName, nBufLen, "w" );
+ break;
+ }
+
+ switch ( dwWSwizzle )
+ {
+ case D3DVS_W_X:
+ strcat_s( pRegisterName, nBufLen, "x" );
+ break;
+ case D3DVS_W_Y:
+ strcat_s( pRegisterName, nBufLen, "y" );
+ break;
+ case D3DVS_W_Z:
+ strcat_s( pRegisterName, nBufLen, "z" );
+ break;
+ case D3DVS_W_W:
+ strcat_s( pRegisterName, nBufLen, "w" );
+ break;
+ }
+
+ }
+
+ } // end !bForceScalarSource
+ }
+ else // dwSwizzle == D3DVS_NOSWIZZLE
+ {
+ // If this is a MOVA / ARL, GL on the Mac requires us to tack the .x onto the source register
+ if ( bForceScalarSource )
+ {
+ strcat_s( pRegisterName, nBufLen, ".x" );
+ }
+ }
+ } // bAllowSwizzle
+
+ // If there are any source modifiers, check to see if they're at
+ // least partially "postfix" and tack them on as appropriate
+ if ( dwSrcModifier != D3DSPSM_NONE )
+ {
+ switch ( dwSrcModifier )
+ {
+ case D3DSPSM_BIAS: // bias
+ case D3DSPSM_BIASNEG: // bias and negate
+ Assert(0);
+ strcat_s( pRegisterName, nBufLen, "_bx2" );
+ break;
+ case D3DSPSM_SIGN: // sign
+ case D3DSPSM_SIGNNEG: // sign and negate
+ Assert(0);
+ strcat_s( pRegisterName, nBufLen, "_sgn" );
+ break;
+ case D3DSPSM_X2: // *2
+ case D3DSPSM_X2NEG: // *2 and negate
+ Assert(0);
+ strcat_s( pRegisterName, nBufLen, "_x2" );
+ break;
+ case D3DSPSM_ABS: // abs()
+ case D3DSPSM_ABSNEG: // -abs()
+ if ( m_bGLSL )
+ {
+ strcat_s( pRegisterName, nBufLen, ")" );
+ }
+ break;
+ case D3DSPSM_DZ: // divide through by z component
+ Assert(0);
+ strcat_s( pRegisterName, nBufLen, "_dz" );
+ break;
+ case D3DSPSM_DW: // divide through by w component
+ Assert(0);
+ strcat_s( pRegisterName, nBufLen, "_dw" );
+ break;
+ }
+ } // end postfix modifiers (really only ps.1.x)
+ }
+}
+
+void D3DToGL::RecordInputAndOutputPositions()
+{
+ // Remember where we are in the token stream.
+ m_pRecordedInputTokenStart = m_pdwNextToken;
+
+ // Remember where our outputs are.
+ m_nRecordedParamCodeStrlen = V_strlen( (char*)m_pBufParamCode->Base() );
+ m_nRecordedALUCodeStrlen = V_strlen( (char*)m_pBufALUCode->Base() );
+ m_nRecordedAttribCodeStrlen = V_strlen( (char*)m_pBufAttribCode->Base() );
+}
+void D3DToGL::AddTokenHexCodeToBuffer( char *pBuffer, int nSize, int nLastStrlen )
+{
+ int nCurStrlen = V_strlen( pBuffer );
+ if ( nCurStrlen == nLastStrlen )
+ return;
+
+ // Build a string with all the hex codes of the tokens since last time.
+ char szHex[512];
+ szHex[0] = '\n';
+ V_snprintf( &szHex[1], sizeof( szHex )-1, HEXCODE_HEADER );
+ int nTokens = std::min( 10, m_pdwNextToken - m_pRecordedInputTokenStart );
+ for ( int i=0; i < nTokens; i++ )
+ {
+ char szTemp[32];
+ V_snprintf( szTemp, sizeof( szTemp ), "0x%x ", m_pRecordedInputTokenStart[i] );
+ strncat( szHex, szTemp, sizeof(szHex) - strlen(szHex) - 1 );
+ }
+ strncat( szHex, "\n", sizeof(szHex) - strlen(szHex) - 1 );
+
+ // Insert the hex codes into the string.
+ int nBytesToInsert = V_strlen( szHex );
+ if ( nCurStrlen + nBytesToInsert + 1 >= nSize )
+ Error( "Buffer overflow writing token hex codes" );
+
+ if ( m_bPutHexCodesAfterLines )
+ {
+ // Put it at the end of the last line.
+ if ( pBuffer[nCurStrlen-1] == '\n' )
+ pBuffer[nCurStrlen-1] = 0;
+
+ strncat( pBuffer, &szHex[1], nSize - strlen( pBuffer ) - 1 );
+ }
+ else
+ {
+ memmove( pBuffer + nLastStrlen + nBytesToInsert, pBuffer + nLastStrlen, nCurStrlen - nLastStrlen + 1 );
+ memcpy( pBuffer + nLastStrlen, szHex, nBytesToInsert );
+ }
+}
+
+void D3DToGL::AddTokenHexCode()
+{
+ if ( m_pdwNextToken > m_pRecordedInputTokenStart )
+ {
+ AddTokenHexCodeToBuffer( (char*)m_pBufParamCode->Base(), m_pBufParamCode->Size(), m_nRecordedParamCodeStrlen );
+ AddTokenHexCodeToBuffer( (char*)m_pBufALUCode->Base(), m_pBufALUCode->Size(), m_nRecordedALUCodeStrlen );
+ AddTokenHexCodeToBuffer( (char*)m_pBufAttribCode->Base(), m_pBufAttribCode->Size(), m_nRecordedAttribCodeStrlen );
+ }
+}
+
+uint32 D3DToGL::MaintainAttributeMap( uint32 dwToken, uint32 dwRegToken )
+{
+ // Check that this reg index has not been used before - if it has, let Houston know
+ uint dwRegIndex = dwRegToken & D3DSP_REGNUM_MASK;
+ if ( m_dwAttribMap[ dwRegIndex ] == 0xFFFFFFFF )
+ {
+ // log it
+ // semantic/usage in the higher nibble
+ // usage index in the low nibble
+
+ uint usage = dwToken & D3DSP_DCL_USAGE_MASK;
+ uint usageindex = ( dwToken & D3DSP_DCL_USAGEINDEX_MASK ) >> D3DSP_DCL_USAGEINDEX_SHIFT;
+
+ m_dwAttribMap[ dwRegIndex ] = ( usage << 4 ) | usageindex;
+
+ // avoid writing 0xBB since runtime code uses that for an 'unused' marker
+ if ( m_dwAttribMap[ dwRegIndex ] == 0xBB )
+ {
+ Debugger();
+ }
+ }
+ else
+ {
+ //not OK
+ Debugger();
+ }
+
+ return dwRegIndex;
+}
+
+void D3DToGL::Handle_DCL()
+{
+ uint32 dwToken = GetNextToken(); // What kind of dcl is this...
+ uint32 dwRegToken = GetNextToken(); // Look ahead to register token
+
+ if ( m_bVertexShader )
+ {
+ // If this is an output, remember the index (what the ASM code calls o0, o1, o2..) and the semantic.
+ // When GetParameterString( DST_REGISTER ) hits this one, we'll return "oN".
+ // At the end of the main() function, we'll insert a bunch of statements like "gl_Color = o2" based on what we remembered here.
+ if ( m_bGLSL )
+ {
+ if ( m_dwMajorVersion >= 3 && GetRegTypeFromToken( dwRegToken ) == D3DSPR_OUTPUT )
+ {
+ uint32 dwRegNum = dwRegToken & D3DSP_REGNUM_MASK;
+
+ if ( dwRegNum >= MAX_DECLARED_OUTPUTS )
+ Error( "Output register number (%d) too high (only %d supported).", dwRegNum, MAX_DECLARED_OUTPUTS );
+
+ if ( m_DeclaredOutputs[dwRegNum] != UNDECLARED_OUTPUT )
+ Error( "Output dcl_ hit for register #%d more than once!", dwRegNum );
+
+ Assert( dwToken != UNDECLARED_OUTPUT );
+ m_DeclaredOutputs[dwRegNum] = dwToken;
+
+ if ( m_bAddHexCodeComments )
+ {
+ CUtlString sParam2 = GetUsageAndIndexString( dwToken, SEMANTIC_OUTPUT );
+ PrintToBuf( *m_pBufHeaderCode, "// [GL remembering that o%d maps to %s]\n", dwRegNum, sParam2.String() );
+ }
+
+ PrintToBuf( *m_pBufHeaderCode, "varying vec4 o%d = vec4( 0.0, 0.0, 0.0, 0.0 );\n", dwRegNum );
+ }
+ else
+ {
+ CUtlString sParam1 = GetParameterString( dwRegToken, DST_REGISTER, false, NULL );
+ CUtlString sParam2 = GetUsageAndIndexString( dwToken, SEMANTIC_INPUT );
+
+ sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
+ PrintToBuf( *m_pBufHeaderCode, "attribute vec4 %s; // ", sParam1.String() );
+
+ MaintainAttributeMap( dwToken, dwRegToken );
+
+ char temp[128];
+ // regnum goes straight into the vertex.attrib[n] index
+ sprintf( temp, "%08x %08x\n", dwToken, dwRegToken );
+ StrcatToHeaderCode( temp );
+ }
+ }
+ else // ARB_vertex_program ASM
+ {
+ StrcatToAttribCode( "ATTRIB" );
+ char buff[64];
+ PrintParameterToString( dwRegToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToAttribCode( buff );
+ StrcatToAttribCode( " = " );
+
+ uint regIndex = MaintainAttributeMap( dwToken, dwRegToken );
+
+ char temp[128];
+ // regnum goes straight into the vertex.attrib[n] index
+ sprintf( temp, "vertex.attrib[%d]; # %08x %08x\n", regIndex, dwToken, dwRegToken );
+ StrcatToAttribCode( temp );
+
+ // ASM
+// CUtlString sParam1 = GetParameterString( dwRegToken, DST_REGISTER );
+// CUtlString sParam2 = GetUsageAndIndexString( dwToken, SEMANTIC_INPUT );
+// PrintToBuf( m_pAttribCode, m_nAttribCodeBufSize, "ATTRIB%s = %s;\n", sParam1.String(), sParam2.String() );
+ }
+ }
+ else // Pixel shader
+ {
+ // If the register is a sampler, the dcl has a dimension decorator that we have to save for subsequent TEX instructions
+ uint32 nRegType = GetRegType( dwRegToken );
+ if ( nRegType == D3DSPR_SAMPLER )
+ {
+ int nRegNum = dwRegToken & D3DSP_REGNUM_MASK;
+ switch ( TextureType( dwToken ) )
+ {
+ default:
+ case D3DSTT_UNKNOWN:
+ case D3DSTT_2D:
+ m_dwSamplerTypes[nRegNum] = SAMPLER_TYPE_2D;
+ break;
+ case D3DSTT_CUBE:
+ m_dwSamplerTypes[nRegNum] = SAMPLER_TYPE_CUBE;
+ break;
+ case D3DSTT_VOLUME:
+ m_dwSamplerTypes[nRegNum] = SAMPLER_TYPE_3D;
+ break;
+ }
+
+ // Track sampler declarations
+ m_dwSamplerUsageMask |= 1 << nRegNum;
+ }
+ else // Not a sampler, we're going to generate vaying declaration code
+ {
+ if ( m_bGLSL )
+ {
+ // In pixel shaders we only declare texture coordinate varyings since they may be using centroid
+ if ( (!m_bVertexShader) && ( GetRegType( dwRegToken ) == D3DSPR_TEXTURE ) )
+ {
+ char buff[256];
+ PrintParameterToString( dwRegToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
+ PrintToBuf( *m_pBufHeaderCode, "%s;\n",buff );
+ }
+ }
+ else // asm
+ {
+ char buff[256];
+ PrintParameterToString( dwRegToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
+ PrintToBuf( *m_pBufAttribCode, "ATTRIB%s;\n", buff );
+ }
+ }
+ }
+}
+
+
+void D3DToGL::Handle_DEF()
+{
+ //
+ // JasonM TODO: catch D3D's sincos-specific D3DSINCOSCONST1 and D3DSINCOSCONST2 constants and filter them out here
+ //
+
+ // Which register is being defined
+ uint32 dwToken = GetNextToken();
+
+ // Note that this constant was explicitly defined
+ m_bConstantRegisterDefined[dwToken & D3DSP_REGNUM_MASK] = true;
+ CUtlString sParamName = GetParameterString( dwToken, DST_REGISTER, false, NULL );
+
+ const char float_fmt[] = "%.12f";
+ const char float_fmt_commaspace[] = "%.12f, "; // %g causes GLSL compile problems around consts like "1e+2.0" - try %f
+
+ if ( m_bGLSL )
+ {
+ PrintToBuf( *m_pBufParamCode, "vec4 %s = vec4( ", sParamName.String() );
+
+ // Run through the 4 floats
+ for ( int i=0; i < 4; i++ )
+ {
+ float fConst = uint32ToFloat( GetNextToken() );
+
+ // It must have a decimal point.
+ char szTemp[256];
+ V_snprintf( szTemp, sizeof( szTemp ), float_fmt, fConst );
+ StripExtraTrailingZeros( szTemp ); // Turn 1.00000 into 1.0
+
+ if ( !strchr( szTemp, '.' ) )
+ {
+ strncat( szTemp, ".0", sizeof(szTemp) - strlen(szTemp) - 1 );
+ }
+
+ PrintToBuf( *m_pBufParamCode, i != 3 ? "%s, " : "%s", szTemp ); // end with comma-space
+ }
+
+ PrintToBuf( *m_pBufParamCode, " );\n" );
+ }
+ else
+ {
+ PrintToBuf( *m_pBufParamCode, "PARAM%s = { ", sParamName.String() );
+
+ // Run through the 4 floats
+ for ( int i=0; i < 4; i++ )
+ {
+ float fConst = uint32ToFloat( GetNextToken() );
+ PrintToBuf( *m_pBufParamCode, i != 3 ? float_fmt_commaspace : float_fmt, fConst ); // end with comma-space
+ }
+
+ PrintToBuf( *m_pBufParamCode, " };\n" );
+ }
+}
+
+void D3DToGL::Handle_MAD( uint32 nInstruction )
+{
+ uint32 nDestToken = GetNextToken();
+ CUtlString sParam1 = GetParameterString( nDestToken, DST_REGISTER, false, NULL );
+ int nARLComp0 = ARL_DEST_NONE;
+ CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp0 );
+ int nARLComp1 = ARL_DEST_NONE;
+ CUtlString sParam3 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp1 );
+ int nARLComp2 = ARL_DEST_NONE;
+ CUtlString sParam4 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp2 );
+
+ // This optionally inserts a move from our dummy address register to the .x component of the real one
+ InsertMoveFromAddressRegister( m_pBufALUCode, nARLComp0, nARLComp1, nARLComp2 );
+
+ if ( m_bGLSL )
+ {
+ sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
+ sParam3 = FixGLSLSwizzle( sParam1, sParam3 );
+ sParam4 = FixGLSLSwizzle( sParam1, sParam4 );
+ PrintToBuf( *m_pBufALUCode, "%s = %s * %s + %s;\n", sParam1.String(), sParam2.String(), sParam3.String(), sParam4.String() );
+
+ // If the _SAT instruction modifier is used, then do a saturate here.
+ if ( nDestToken & D3DSPDM_SATURATE )
+ {
+ int nComponents = GetNumSwizzleComponents( sParam1.String() );
+ if ( nComponents == 0 )
+ nComponents = 4;
+
+ PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", sParam1.String(), sParam1.String(), g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
+ }
+ }
+ else
+ {
+ char buff[256];
+ PrintOpcode( nInstruction, buff, sizeof( buff ) );
+ PrintToBuf( *m_pBufALUCode, "%s%s, %s, %s, %s;\n", buff, sParam1.String(), sParam2.String(), sParam3.String(), sParam4.String() );
+
+ if ( nDestToken & D3DSPDM_SATURATE )
+ {
+ // Need to saturate asm!
+ Assert(0);
+ }
+ }
+}
+
+
+void D3DToGL::Handle_DP2ADD()
+{
+ char pDestReg[16], pSrc0Reg[16], pSrc1Reg[16], pSrc2Reg[16];
+ uint32 nDestToken = GetNextToken();
+ PrintParameterToString( nDestToken, DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc1Reg, sizeof( pSrc1Reg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc2Reg, sizeof( pSrc2Reg ), false, NULL );
+
+ if ( m_bGLSL )
+ {
+ // We should only be assigning to a single component of the dest.
+ Assert( GetNumSwizzleComponents( pDestReg ) == 1 );
+ Assert( GetNumSwizzleComponents( pSrc2Reg ) == 1 );
+
+ // This is a 2D dot product, so we only want two entries from the middle components.
+ CUtlString sArg0 = EnsureNumSwizzleComponents( pSrc0Reg, 2 );
+ CUtlString sArg1 = EnsureNumSwizzleComponents( pSrc1Reg, 2 );
+
+ PrintToBuf( *m_pBufALUCode, "%s = dot( %s, %s ) + %s;\n", pDestReg, sArg0.String(), sArg1.String(), pSrc2Reg );
+
+ // If the _SAT instruction modifier is used, then do a saturate here.
+ if ( nDestToken & D3DSPDM_SATURATE )
+ {
+ int nComponents = GetNumSwizzleComponents( pDestReg );
+ if ( nComponents == 0 )
+ nComponents = 4;
+
+ PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", pDestReg, pDestReg, g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
+ }
+ }
+ else
+ {
+ m_bNeedsD2AddTemp = true;
+
+ PrintToBuf( *m_pBufALUCode, "MOV DP2A0, %s;\n", pSrc0Reg ); // MOV DP2A0, src0;
+ PrintToBuf( *m_pBufALUCode, "MOV DP2A0.z, 1;\n" ); // MOV DP2A0.z, 1;
+
+ PrintToBuf( *m_pBufALUCode, "MOV DP2A1, %s;\n", pSrc1Reg ); // MOV DP2A1, src1;
+ PrintToBuf( *m_pBufALUCode, "MOV DP2A1.z, %s;\n", pSrc2Reg ); // MOV DP2A1.z, src2;
+
+ PrintToBuf( *m_pBufALUCode, "DP3%s, DP2A0, DP2A1;\n", pDestReg ); // DP3 dest, DP2A0, DP2A1;
+
+ if ( nDestToken & D3DSPDM_SATURATE )
+ {
+ // Need to saturate asm!
+ Assert(0);
+ }
+ }
+}
+
+
+void D3DToGL::Handle_SINCOS()
+{
+ char pDestReg[16], pSrc0Reg[16];
+ PrintParameterToString( GetNextToken(), DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), true, NULL );
+ m_bNeedsSinCosDeclarations = true;
+
+ if ( m_bGLSL )
+ {
+ CUtlString sDest( pDestReg );
+ CUtlString sArg0 = EnsureNumSwizzleComponents( pSrc0Reg, 1 );// Ensure input is scalar
+ CUtlString sResult( "vSinCosTmp.xy" ); // Always going to populate this
+ sResult = FixGLSLSwizzle( sDest, sResult ); // Make sure we match the desired output reg
+
+ PrintToBuf( *m_pBufALUCode, "vSinCosTmp.z = %s * %s;\n", sArg0.String(), sArg0.String() );
+
+ PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.zz * scA.xy + scA.wz;\n" );
+ PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.xy * vSinCosTmp.zz + scB.xy;\n" );
+ PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.xy * vSinCosTmp.zz + scB.wz;\n" );
+
+ PrintToBuf( *m_pBufALUCode, "vSinCosTmp.x = vSinCosTmp.x * %s;\n", sArg0.String() );
+
+ PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.xy * vSinCosTmp.xx;\n" );
+ PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.xy + vSinCosTmp.xy;\n" );
+ PrintToBuf( *m_pBufALUCode, "vSinCosTmp.x = -vSinCosTmp.x + scB.z;\n" );
+
+ PrintToBuf( *m_pBufALUCode, "%s = %s;\n", sDest.String(), sResult.String() );
+ }
+ else
+ {
+ // This is the code sequence recommended to IHVs by Microsoft in the DirectX 9 DDK:
+ //
+ // http://msdn.microsoft.com/en-us/library/ms800337.aspx
+ //
+ // MUL SC_TEMP.z, src, src;
+ // MAD SC_TEMP.xy, SC_TEMP.z, scA, scA.wzyx;
+ // MAD SC_TEMP.xy, SC_TEMP, SC_TEMP.z, scB;
+ // MAD SC_TEMP.xy, SC_TEMP, SC_TEMP.z, scB.wzyx;
+ // MUL SC_TEMP.x, SC_TEMP.x, src;
+ // MUL SC_TEMP.xy, SC_TEMP, SC_TEMP.x;
+ // ADD SC_TEMP.xy, SC_TEMP, SC_TEMP;
+ // ADD SC_TEMP.x, -SC_TEMP.x, scB.z;
+
+ StrcatToALUCode( "MUL SC_TEMP.z, " ); // MUL SC_TEMP.z, src, src;
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ", " );
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ";\n" );
+
+ StrcatToALUCode( "MAD SC_TEMP.xy, SC_TEMP.z, scA, scA.wzyx;\n" );
+ StrcatToALUCode( "MAD SC_TEMP.xy, SC_TEMP, SC_TEMP.z, scB;\n" );
+ StrcatToALUCode( "MAD SC_TEMP.xy, SC_TEMP, SC_TEMP.z, scB.wzyx;\n" );
+
+ StrcatToALUCode( "MUL SC_TEMP.x, SC_TEMP.x, " );
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ";\n" );
+ StrcatToALUCode( "MUL SC_TEMP.xy, SC_TEMP, SC_TEMP.x;\n" );
+ StrcatToALUCode( "ADD SC_TEMP.xy, SC_TEMP, SC_TEMP;\n" );
+ StrcatToALUCode( "ADD SC_TEMP.x, -SC_TEMP.x, scB.z;\n" );
+
+ StrcatToALUCode( "MOV" );
+ StrcatToALUCode( pDestReg );
+ StrcatToALUCode( ", SC_TEMP;\n" );
+ }
+
+ // Eat two more tokens since D3D defines Taylor series constants that we won't need
+ SkipTokens( 2 );
+}
+
+
+void D3DToGL::Handle_LRP( uint32 nInstruction )
+{
+ if ( m_bGLSL )
+ {
+ uint32 nDestToken = GetNextToken();
+ CUtlString sDest = GetParameterString( nDestToken, DST_REGISTER, false, NULL );
+ int nARLComp0 = ARL_DEST_NONE;
+ CUtlString sParam0 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp0 );
+ int nARLComp1 = ARL_DEST_NONE;
+ CUtlString sParam1 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp1 );
+ int nARLComp2 = ARL_DEST_NONE;
+ CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp2 );
+
+ // This optionally inserts a move from our dummy address register to the .x component of the real one
+ InsertMoveFromAddressRegister( m_pBufALUCode, nARLComp0, nARLComp1, nARLComp2 );
+
+ sParam0 = FixGLSLSwizzle( sDest, sParam0 );
+ sParam1 = FixGLSLSwizzle( sDest, sParam1 );
+ sParam2 = FixGLSLSwizzle( sDest, sParam2 );
+
+ // dest = src0 * (src1 - src2) + src2;
+ PrintToBuf( *m_pBufALUCode, "%s = %s * ( %s - %s ) + %s;\n", sDest.String(), sParam0.String(), sParam1.String(), sParam2.String(), sParam2.String() );
+
+ // If the _SAT instruction modifier is used, then do a saturate here.
+ if ( nDestToken & D3DSPDM_SATURATE )
+ {
+ int nComponents = GetNumSwizzleComponents( sDest.String() );
+ if ( nComponents == 0 )
+ nComponents = 4;
+
+ PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", sDest.String(), sDest.String(), g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
+ }
+ }
+ else
+ {
+ if ( !m_bVertexShader )
+ {
+ char buff[256];
+ PrintOpcode( nInstruction, buff, sizeof( buff ) );
+ StrcatToALUCode( buff );
+ PrintParameterToString( GetNextToken(), DST_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ", " );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ", " );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ", " );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ";\n" );
+ }
+ else // VS doesn't actually have a LRP instruction. Emulate with a SUB and a MAD
+ {
+ char pDestReg[16], pSrc0Reg[16], pSrc1Reg[16], pSrc2Reg[16];
+
+ m_bNeedsLerpTemp = true;
+
+ // dest = src0 * (src1 - src2) + src2;
+ PrintParameterToString( GetNextToken(), DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc1Reg, sizeof( pSrc1Reg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc2Reg, sizeof( pSrc2Reg ), false, NULL );
+
+ StrcatToALUCode( "SUB LRP_TEMP, " ); // SUB LRP_TEMP, src1, src2;
+ StrcatToALUCode( pSrc1Reg );
+ StrcatToALUCode( ", " );
+ StrcatToALUCode( pSrc2Reg );
+ StrcatToALUCode( ";\n" );
+
+ StrcatToALUCode( "MAD" ); // MAD dst, src0, LRP_TEMP, src2;
+ StrcatToALUCode( pDestReg );
+ StrcatToALUCode( ", " );
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ", LRP_TEMP, " );
+ StrcatToALUCode( pSrc2Reg );
+ StrcatToALUCode( ";\n" );
+ }
+ }
+}
+
+
+void D3DToGL::Handle_TEX( uint32 dwToken, bool bIsTexLDL )
+{
+ char pDestReg[64], pSrc0Reg[64], pSrc1Reg[64];
+ PrintParameterToString( GetNextToken(), DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
+
+ DWORD dwSrc1Token = GetNextToken();
+ PrintParameterToString( dwSrc1Token, SRC_REGISTER, pSrc1Reg, sizeof( pSrc1Reg ), false, NULL );
+
+
+ if ( m_bGLSL )
+ {
+ Assert( (dwSrc1Token & D3DSP_REGNUM_MASK) < ARRAYSIZE( m_dwSamplerTypes ) );
+ uint32 nSamplerType = m_dwSamplerTypes[dwSrc1Token & D3DSP_REGNUM_MASK];
+ if ( nSamplerType == SAMPLER_TYPE_2D )
+ {
+ CUtlString sCoordVar = EnsureNumSwizzleComponents( pSrc0Reg, 2 );
+
+ if ( bIsTexLDL )
+ {
+ // Strip out the W component of the pSrc0Reg and pass that as the LOD to texture2DLod.
+ char szLOD[128], szExtra[8];
+ GetParamNameWithoutSwizzle( pSrc0Reg, szLOD, sizeof( szLOD ) );
+ V_snprintf( szExtra, sizeof( szExtra ), ".%c", GetSwizzleComponent( pSrc0Reg, 3 ) );
+ strncat( szLOD, szExtra, sizeof(szLOD) - strlen(szLOD) - 1 );
+
+ PrintToBuf( *m_pBufALUCode, "%s = texture2DLod( %s, %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar.String(), szLOD );
+ }
+ else if ( ( (int) ( dwSrc1Token & D3DSP_REGNUM_MASK ) ) == m_nShadowDepthSampler ) // Syntax for shadow depth sampler
+ {
+ // .z is meant to contain the object depth, while .xy contains the 2D tex coords
+ CUtlString sCoordVar3D = EnsureNumSwizzleComponents( pSrc0Reg, 3 );
+
+ PrintToBuf( *m_pBufALUCode, "%s = shadow2D( %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar3D.String() );
+ Assert( m_dwSamplerTypes[dwSrc1Token & D3DSP_REGNUM_MASK] == SAMPLER_TYPE_2D );
+ }
+ else if( ( OpcodeSpecificData( dwToken ) << D3DSP_OPCODESPECIFICCONTROL_SHIFT ) == D3DSI_TEXLD_PROJECT )
+ {
+ // This projective case is after the shadow case intentionally, due to the way that "projective"
+ // loads are overloaded in our D3D shaders for shadow lookups.
+ //
+ // We use the vec4 variant of texture2DProj() intentionally here, since it lines up well with Direct3D.
+
+ CUtlString s4DProjCoords = EnsureNumSwizzleComponents( pSrc0Reg, 4 ); // Ensure vec4 variant
+ PrintToBuf( *m_pBufALUCode, "%s = texture2DProj( %s, %s );\n", pDestReg, pSrc1Reg, s4DProjCoords.String() );
+ }
+ else
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = texture2D( %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar.String() );
+ }
+ }
+ else if ( nSamplerType == SAMPLER_TYPE_3D )
+ {
+ CUtlString sCoordVar = EnsureNumSwizzleComponents( pSrc0Reg, 3 );
+ PrintToBuf( *m_pBufALUCode, "%s = texture3D( %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar.String() );
+ }
+ else if ( nSamplerType == SAMPLER_TYPE_CUBE )
+ {
+ CUtlString sCoordVar = EnsureNumSwizzleComponents( pSrc0Reg, 3 );
+ PrintToBuf( *m_pBufALUCode, "%s = textureCube( %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar.String() );
+ }
+ else
+ {
+ Error( "TEX instruction: unsupported sampler type used" );
+ }
+ }
+ else
+ {
+ Assert( !( bIsTexLDL && !m_bGeneratingDebugText ) );
+
+ if( ( OpcodeSpecificData( dwToken ) << D3DSP_OPCODESPECIFICCONTROL_SHIFT ) == D3DSI_TEXLD_PROJECT )
+ {
+ StrcatToALUCode( "TXP" );
+ }
+ else if( ( OpcodeSpecificData( dwToken ) << D3DSP_OPCODESPECIFICCONTROL_SHIFT) == D3DSI_TEXLD_BIAS )
+ {
+ StrcatToALUCode( "TXB" );
+ }
+ else
+ {
+ StrcatToALUCode( "TEX" );
+ }
+
+ // Destination
+ StrcatToALUCode( pDestReg );
+ StrcatToALUCode( ", " );
+
+ // Source0
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ", " );
+
+ // Source1
+ StrcatToALUCode( pSrc1Reg );
+ StrcatToALUCode( ", " );
+
+ // Syntax for shadow depth sampler
+ if ( ( (int) ( dwSrc1Token & D3DSP_REGNUM_MASK ) ) == m_nShadowDepthSampler )
+ {
+ m_bDeclareShadowOption = true;
+
+ StrcatToALUCode( "SHADOW" ); // Should result in SHADOW2D target
+ Assert( m_dwSamplerTypes[dwSrc1Token & D3DSP_REGNUM_MASK] == SAMPLER_TYPE_2D );
+ }
+
+ // Sampler dimension (2D, CUBE, 3D) determined by earlier declaration
+ StrcatToALUCode( g_szSamplerStrings[m_dwSamplerTypes[dwSrc1Token & D3DSP_REGNUM_MASK]] );
+ StrcatToALUCode( ";\n" );
+ }
+}
+
+void D3DToGL::StrcatToHeaderCode( const char *pBuf )
+{
+ strcat_s( (char*)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), pBuf );
+}
+
+void D3DToGL::StrcatToALUCode( const char *pBuf )
+{
+ strcat_s( (char*)m_pBufALUCode->Base(), m_pBufALUCode->Size(), pBuf );
+}
+
+void D3DToGL::StrcatToParamCode( const char *pBuf )
+{
+ strcat_s( (char*)m_pBufParamCode->Base(), m_pBufParamCode->Size(), pBuf );
+}
+
+void D3DToGL::StrcatToAttribCode( const char *pBuf )
+{
+ strcat_s( (char*)m_pBufAttribCode->Base(), m_pBufAttribCode->Size(), pBuf );
+}
+
+void D3DToGL::Handle_TexLDD( uint32 nInstruction )
+{
+ Assert( !m_bGLSL ); // Not supported yet, but can be if we need it.
+
+ char buff[256];
+ PrintOpcode( nInstruction, buff, sizeof( buff ) );
+
+ StrcatToALUCode( buff );
+ PrintParameterToString( GetNextToken(), DST_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ", " );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ", " );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ", " );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ", " );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ";\n" );
+}
+
+
+void D3DToGL::Handle_TexCoord()
+{
+ Assert(0);
+
+ // If ps_1_4, this is texcrd
+ if ( (m_dwMajorVersion == 1) && (m_dwMinorVersion == 4) && (!m_bVertexShader) )
+ {
+ StrcatToALUCode( "texcrd" );
+ }
+ else // else it's texcoord
+ {
+ Assert(0);
+ StrcatToALUCode( "texcoord" );
+ }
+
+ char buff[256];
+ PrintParameterToString( GetNextToken(), DST_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+
+ // If ps_1_4, texcrd also has a source parameter
+ if ((m_dwMajorVersion == 1) && (m_dwMinorVersion == 4) && (!m_bVertexShader))
+ {
+ StrcatToALUCode( ", " );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ }
+
+ StrcatToALUCode( ";\n" );
+}
+
+void D3DToGL::HandleBinaryOp_GLSL( uint32 nInstruction )
+{
+ uint32 nDestToken = GetNextToken();
+ CUtlString sParam1 = GetParameterString( nDestToken, DST_REGISTER, false, NULL );
+ int nARLComp0 = ARL_DEST_NONE;
+ CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp0 );
+ int nARLComp1 = ARL_DEST_NONE;
+ CUtlString sParam3 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp1 );
+
+ // This optionally inserts a move from our dummy address register to the .x component of the real one
+ InsertMoveFromAddressRegister( m_pBufALUCode, nARLComp0, nARLComp1 );
+
+ // DST is a weird one. I haven't seen it used anywhere yet but can add support if necessary. This is what it does:
+ // dest.x = 1;
+ // dest.y = src0.y * src1.y;
+ // dest.z = src0.z;
+ // dest.w = src1.w;
+ Assert( nInstruction != D3DSIO_DST );
+
+ // Since DP3 and DP4 have a scalar as the dest and vectors as the src, don't screw with the swizzle specifications.
+ if ( nInstruction == D3DSIO_DP3 )
+ {
+ sParam2 = EnsureNumSwizzleComponents( sParam2, 3 );
+ sParam3 = EnsureNumSwizzleComponents( sParam3, 3 );
+ }
+ else if ( nInstruction == D3DSIO_DP4 )
+ {
+ sParam2 = EnsureNumSwizzleComponents( sParam2, 4 );
+ sParam3 = EnsureNumSwizzleComponents( sParam3, 4 );
+ }
+ else
+ {
+ sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
+ sParam3 = FixGLSLSwizzle( sParam1, sParam3 );
+ }
+
+ char buff[256];
+ if ( nInstruction == D3DSIO_ADD || nInstruction == D3DSIO_SUB || nInstruction == D3DSIO_MUL )
+ {
+ // These all look like x = y op z
+ PrintToBuf( *m_pBufALUCode, "%s = %s %s %s;\n", sParam1.String(), sParam2.String(), GetGLSLOperatorString( nInstruction ), sParam3.String() );
+ }
+ else
+ {
+ if ( ( nInstruction == D3DSIO_SGE ) || ( nInstruction == D3DSIO_SLT ) )
+ {
+ sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
+ sParam3 = FixGLSLSwizzle( sParam1, sParam3 );
+ }
+
+ int nDestComponents = GetNumSwizzleComponents( sParam1.String() );
+ int nSrcComponents = GetNumSwizzleComponents( sParam2.String() );
+
+ // All remaining instructions can use GLSL intrinsics like dot() and cross().
+ bool bDoubleClose = OpenIntrinsic( nInstruction, buff, sizeof( buff ), nDestComponents, nSrcComponents );
+
+ if ( ( nSrcComponents == 1 ) && ( nInstruction == D3DSIO_SGE ) )
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = %s%s >= %s );\n", sParam1.String(), buff, sParam2.String(), sParam3.String() );
+ }
+ else if ( ( nSrcComponents == 1 ) && ( nInstruction == D3DSIO_SLT ) )
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = %s%s < %s );\n", sParam1.String(), buff, sParam2.String(), sParam3.String() );
+ }
+ else
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = %s%s, %s %s;\n", sParam1.String(), buff, sParam2.String(), sParam3.String(), bDoubleClose ? ") )" : ")" );
+ }
+ }
+
+ // If the _SAT instruction modifier is used, then do a saturate here.
+ if ( nDestToken & D3DSPDM_SATURATE )
+ {
+ int nComponents = GetNumSwizzleComponents( sParam1.String() );
+ if ( nComponents == 0 )
+ nComponents = 4;
+
+ PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", sParam1.String(), sParam1.String(), g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
+ }
+}
+
+void D3DToGL::HandleBinaryOp_ASM( uint32 nInstruction )
+{
+ CUtlString sParam1 = GetParameterString( GetNextToken(), DST_REGISTER, false, NULL );
+ int nARLComp0 = ARL_DEST_NONE;
+ CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp0 );
+ int nARLComp1 = ARL_DEST_NONE;
+ CUtlString sParam3 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp1 );
+
+ // This optionally inserts a move from our dummy address register to the .x component of the real one
+ InsertMoveFromAddressRegister( m_pBufALUCode, nARLComp0, nARLComp1 );
+
+ char buff[256];
+ PrintOpcode( nInstruction, buff, sizeof( buff ) );
+ PrintToBuf( *m_pBufALUCode, "%s%s, %s, %s;\n", buff, sParam1.String(), sParam2.String(), sParam3.String() );
+}
+
+void D3DToGL::WriteGLSLCmp( const char *pDestReg, const char *pSrc0Reg, const char *pSrc1Reg, const char *pSrc2Reg )
+{
+ int nWriteMaskEntries = GetNumWriteMaskEntries( pDestReg );
+ for ( int i=0; i < nWriteMaskEntries; i++ )
+ {
+ char params[4][256];
+ WriteParamWithSingleMaskEntry( pDestReg, i, params[0], sizeof( params[0] ) );
+ WriteParamWithSingleMaskEntry( pSrc0Reg, i, params[1], sizeof( params[1] ) );
+ WriteParamWithSingleMaskEntry( pSrc1Reg, i, params[2], sizeof( params[2] ) );
+ WriteParamWithSingleMaskEntry( pSrc2Reg, i, params[3], sizeof( params[3] ) );
+
+ PrintToBuf( *m_pBufALUCode, "%s = ( %s >= 0.0 ) ? %s : %s;\n", params[0], params[1], params[2], params[3] );
+ }
+}
+
+void D3DToGL::Handle_CMP()
+{
+ // In Direct3D, result = (src0 >= 0.0) ? src1 : src2
+ // In OpenGL, result = (src0 < 0.0) ? src1 : src2
+ //
+ // As a result, arguments are effectively in a different order than Direct3D! !#$&*!%#$&
+ char pDestReg[64], pSrc0Reg[64], pSrc1Reg[64], pSrc2Reg[64];
+ uint32 nDestToken = GetNextToken();
+ PrintParameterToString( nDestToken, DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc1Reg, sizeof( pSrc1Reg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc2Reg, sizeof( pSrc2Reg ), false, NULL );
+
+ if ( m_bGLSL )
+ {
+ // These are a tricky case.. we have to expand it out into multiple statements.
+ char szDestBase[256];
+ GetParamNameWithoutSwizzle( pDestReg, szDestBase, sizeof( szDestBase ) );
+
+ V_strncpy( pSrc0Reg, FixGLSLSwizzle( pDestReg, pSrc0Reg ), sizeof( pSrc0Reg ) );
+ V_strncpy( pSrc1Reg, FixGLSLSwizzle( pDestReg, pSrc1Reg ), sizeof( pSrc1Reg ) );
+ V_strncpy( pSrc2Reg, FixGLSLSwizzle( pDestReg, pSrc2Reg ), sizeof( pSrc2Reg ) );
+
+ if ( DoParamNamesMatch( pDestReg, pSrc0Reg ) && GetNumSwizzleComponents( pDestReg ) > 1 )
+ {
+ // So the dest register is the same as the comperand. We're in danger of screwing up our results.
+ //
+ // For example, this code:
+ // CMP r0.xy, r0.xx, r1, r2
+ // would generate this:
+ // r0.x = (r0.x >= 0) ? r1.x : r2.x;
+ // r0.y = (r0.x >= 0) ? r1.x : r2.x;
+ //
+ // But the first lines changes r0.x and thus screws the atomicity of the CMP instruction for the second line.
+ // So we assign r0 to a temporary first and then write to the temporary.
+ PrintToBuf( *m_pBufALUCode, "%s = %s;\n", g_pAtomicTempVarName, szDestBase );
+
+ char szTempVar[256];
+ ReplaceParamName( pDestReg, g_pAtomicTempVarName, szTempVar, sizeof( szTempVar ) );
+ WriteGLSLCmp( szTempVar, pSrc0Reg, pSrc1Reg, pSrc2Reg );
+
+ PrintToBuf( *m_pBufALUCode, "%s = %s;\n", szDestBase, g_pAtomicTempVarName );
+ m_bUsedAtomicTempVar = true;
+ }
+ else
+ {
+ // Just write out the simple expanded version of the CMP. No need to use atomic_temp_var.
+ WriteGLSLCmp( pDestReg, pSrc0Reg, pSrc1Reg, pSrc2Reg );
+ }
+
+ // If the _SAT instruction modifier is used, then do a saturate here.
+ if ( nDestToken & D3DSPDM_SATURATE )
+ {
+ int nComponents = GetNumSwizzleComponents( pDestReg );
+ if ( nComponents == 0 )
+ nComponents = 4;
+
+ PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", pDestReg, pDestReg, g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
+ }
+ }
+ else
+ {
+ StrcatToALUCode( "CMP" );
+ StrcatToALUCode( pDestReg );
+ StrcatToALUCode( ", " );
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ", " );
+ StrcatToALUCode( pSrc2Reg ); // Src 2 |
+ StrcatToALUCode( ", " ); // |--- Swap these guys from Direct3D's convention
+ StrcatToALUCode( pSrc1Reg ); // Src 1 |
+ StrcatToALUCode( ";\n" );
+ }
+}
+
+void D3DToGL::Handle_NRM()
+{
+ char pDestReg[64];
+ char pSrc0Reg[64];
+ PrintParameterToString( GetNextToken(), DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
+ PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
+
+ if ( m_bGLSL )
+ {
+ CUtlString sSrc = EnsureNumSwizzleComponents( pSrc0Reg, 3 );
+ PrintToBuf( *m_pBufALUCode, "%s = normalize( %s );\n", pDestReg, sSrc.String() );
+ }
+ else
+ {
+ m_bNeedsNRMTemp = true;
+
+ StrcatToALUCode( "DP3 NRM_TEMP.w, " );
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ", " );
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ";\nRSQ NRM_TEMP.w, NRM_TEMP.w;\nMUL" );
+ StrcatToALUCode( pDestReg );
+ StrcatToALUCode( ", NRM_TEMP.w, " );
+ StrcatToALUCode( pSrc0Reg );
+ StrcatToALUCode( ";\n" );
+ }
+}
+
+void D3DToGL::Handle_UnaryOp( uint32 nInstruction )
+{
+ uint32 nDestToken = GetNextToken();
+ CUtlString sParam1 = GetParameterString( nDestToken, DST_REGISTER, false, NULL );
+ CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, ( nInstruction == D3DSIO_MOVA) && !m_bGLSL, NULL );
+ sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
+
+ if ( m_bGLSL )
+ {
+ if ( nInstruction == D3DSIO_MOV )
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = %s;\n", sParam1.String(), sParam2.String() );
+ }
+ else if ( nInstruction == D3DSIO_RSQ )
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = inversesqrt( %s );\n", sParam1.String(), sParam2.String() );
+ }
+ else if ( nInstruction == D3DSIO_RCP )
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = 1.0 / %s;\n", sParam1.String(), sParam2.String() );
+ }
+ else if ( nInstruction == D3DSIO_EXP )
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = exp2( %s );\n", sParam1.String(), sParam2.String() );
+ }
+ else if ( nInstruction == D3DSIO_FRC )
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = fract( %s );\n", sParam1.String(), sParam2.String() );
+ }
+ else if ( nInstruction == D3DSIO_LOG ) // d3d 'log' is log base 2
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = log2( %s );\n", sParam1.String(), sParam2.String() );
+ }
+ else if ( nInstruction == D3DSIO_ABS ) // rbarris did this one, Jason please check
+ {
+ PrintToBuf( *m_pBufALUCode, "%s = abs( %s );\n", sParam1.String(), sParam2.String() );
+ }
+ else if ( nInstruction == D3DSIO_MOVA )
+ {
+ m_bDeclareAddressReg = true;
+ PrintToBuf( *m_pBufALUCode, "%s = %s;\n", sParam1.String(), sParam2.String() );
+
+ m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
+ }
+ else
+ {
+ Error( "Unsupported instruction" );
+ }
+
+ // If the _SAT instruction modifier is used, then do a saturate here.
+ if ( nDestToken & D3DSPDM_SATURATE )
+ {
+ int nComponents = GetNumSwizzleComponents( sParam1.String() );
+ if ( nComponents == 0 )
+ {
+ nComponents = 4;
+ }
+
+ PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", sParam1.String(), sParam1.String(), g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
+ }
+ }
+ else
+ {
+ if ( nInstruction == D3DSIO_MOVA )
+ {
+ m_bDeclareAddressReg = true;
+ m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
+ Assert( m_nHighestRegister < DXABSTRACT_VS_PARAM_SLOTS );
+ }
+
+ char buff[256];
+ PrintOpcode( nInstruction, buff, sizeof( buff ) );
+ PrintToBuf( *m_pBufALUCode, "%s%s, %s;\n", buff, sParam1.String(), sParam2.String() );
+ }
+}
+
+void D3DToGL::WriteGLSLSamplerDefinitions()
+{
+ int nSamplersWritten = 0;
+ for ( int i=0; i < ARRAYSIZE( m_dwSamplerTypes ); i++ )
+ {
+ if ( m_dwSamplerTypes[i] == SAMPLER_TYPE_2D )
+ {
+ if ( i == m_nShadowDepthSampler )
+ {
+ PrintToBuf( *m_pBufHeaderCode, "uniform sampler2DShadow sampler%d;\n", i );
+ }
+ else
+ {
+ PrintToBuf( *m_pBufHeaderCode, "uniform sampler2D sampler%d;\n", i );
+ }
+ ++nSamplersWritten;
+ }
+ else if ( m_dwSamplerTypes[i] == SAMPLER_TYPE_3D )
+ {
+ PrintToBuf( *m_pBufHeaderCode, "uniform sampler3D sampler%d;\n", i );
+ ++nSamplersWritten;
+ }
+ else if ( m_dwSamplerTypes[i] == SAMPLER_TYPE_CUBE )
+ {
+ PrintToBuf( *m_pBufHeaderCode, "uniform samplerCube sampler%d;\n", i );
+ ++nSamplersWritten;
+ }
+ else if ( m_dwSamplerTypes[i] != SAMPLER_TYPE_UNUSED )
+ {
+ Error( "Unknown sampler type." );
+ }
+ }
+
+ if ( nSamplersWritten > 0 )
+ PrintToBuf( *m_pBufHeaderCode, "\n\n" );
+}
+
+void D3DToGL::WriteGLSLOutputVariableAssignments()
+{
+ if ( m_bVertexShader )
+ {
+ // Map output "oN" registers back to GLSL output variables.
+ if ( m_bAddHexCodeComments )
+ {
+ PrintToBuf( *m_pBufAttribCode, "\n// Now we're storing the oN variables from the output dcl_ statements back into their GLSL equivalents.\n" );
+ }
+
+ for ( int i=0; i < ARRAYSIZE( m_DeclaredOutputs ); i++ )
+ {
+ if ( m_DeclaredOutputs[i] == UNDECLARED_OUTPUT )
+ continue;
+
+ CUtlString sOutputName = GetUsageAndIndexString( m_DeclaredOutputs[i], SEMANTIC_OUTPUT );
+ PrintToBuf( *m_pBufAttribCode, "%s = oT%d;\n", sOutputName.String(), i );
+ }
+ }
+}
+
+void D3DToGL::Handle_DeclarativeNonDclOp( uint32 nInstruction )
+{
+ char buff[128];
+ uint32 dwToken = GetNextToken();
+ PrintParameterToString( dwToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
+
+ if ( m_bGLSL && nInstruction == D3DSIO_TEXKILL )
+ {
+ // TEXKILL is supposed to discard the pixel if any of the src register's X, Y, or Z components are less than zero.
+ // We have to translate it to something like:
+ // if ( r0.x < 0.0 || r0.y < 0.0 )
+ // discard;
+ char c[3];
+ c[0] = GetSwizzleComponent( buff, 0 );
+ c[1] = GetSwizzleComponent( buff, 1 );
+ c[2] = GetSwizzleComponent( buff, 2 );
+
+ // Get the unique components.
+ char cUnique[3];
+ cUnique[0] = c[0];
+
+ int nUnique = 1;
+ if ( c[1] != c[0] )
+ cUnique[nUnique++] = c[1];
+
+ if ( c[2] != c[1] && c[2] != c[0] )
+ cUnique[nUnique++] = c[2];
+
+ // Get the src register base name.
+ char szBase[256];
+ GetParamNameWithoutSwizzle( buff, szBase, sizeof( szBase ) );
+
+ PrintToBuf( *m_pBufALUCode, "if ( %s.%c < 0.0 ", szBase, cUnique[0] );
+ for ( int i=1; i < nUnique; i++ )
+ {
+ PrintToBuf( *m_pBufALUCode, "|| %s.%c < 0.0 ", szBase, cUnique[i] );
+ }
+ PrintToBuf( *m_pBufALUCode, ")\n{\n\tdiscard;\n}\n" );
+ }
+ else
+ {
+ char szOpcode[128];
+ PrintOpcode( nInstruction, szOpcode, sizeof( szOpcode ) );
+ StrcatToALUCode( szOpcode );
+
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ";\n" );
+ }
+}
+
+
+void D3DToGL::NoteTangentInputUsed()
+{
+ if ( !m_bTangentInputUsed )
+ {
+ m_bTangentInputUsed = true;
+// PrintToBuf( *m_pBufParamCode, "attribute vec4 %s;\n", g_pTangentAttributeName );
+ }
+}
+
+
+// These are the only ARL instructions that should appear in the instruction stream
+void D3DToGL::InsertMoveInstruction( CUtlBuffer *pCode, int nARLComponent )
+{
+ switch ( nARLComponent )
+ {
+ case ARL_DEST_X:
+ strcat_s( ( char * )pCode->Base(), pCode->Size(), m_bGLSL ? "a0 = int( va_r.x );\n" : "ARL a0.x, VA_REG.x;\n" );
+ break;
+ case ARL_DEST_Y:
+ strcat_s( ( char * )pCode->Base(), pCode->Size(), m_bGLSL ? "a0 = int( va_r.y );\n" : "ARL a0.x, VA_REG.y;\n" );
+ break;
+ case ARL_DEST_Z:
+ strcat_s( ( char * )pCode->Base(), pCode->Size(), m_bGLSL ? "a0 = int( va_r.z );\n" : "ARL a0.x, VA_REG.z;\n" );
+ break;
+ case ARL_DEST_W:
+ strcat_s( ( char * )pCode->Base(), pCode->Size(), m_bGLSL ? "a0 = int( va_r.w );\n" : "ARL a0.x, VA_REG.w;\n" );
+ break;
+ }
+}
+
+// This optionally inserts a move from our dummy address register to the .x component of the real one
+void D3DToGL::InsertMoveFromAddressRegister( CUtlBuffer *pCode, int nARLComp0, int nARLComp1, int nARLComp2 /* = ARL_DEST_NONE */ )
+{
+ int nNumSwizzles = 0;
+ (void)nNumSwizzles;
+
+ if ( nARLComp0 != ARL_DEST_NONE )
+ nNumSwizzles++;
+
+ if ( nARLComp1 != ARL_DEST_NONE )
+ nNumSwizzles++;
+
+ if ( nARLComp2 != ARL_DEST_NONE )
+ nNumSwizzles++;
+
+ // We shouldn't have any more than one indirect address usage in a single instruction
+ Assert( nNumSwizzles <= 1 );
+
+ if ( nARLComp0 != ARL_DEST_NONE )
+ {
+ InsertMoveInstruction( pCode, nARLComp0 );
+ }
+ else if ( nARLComp1 != ARL_DEST_NONE )
+ {
+ InsertMoveInstruction( pCode, nARLComp1 );
+ }
+ else if ( nARLComp2 != ARL_DEST_NONE )
+ {
+ InsertMoveInstruction( pCode, nARLComp2 );
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// TranslateShader()
+//
+// This is the main function that the outside world sees. A pointer to the
+// uint32 stream returned from the D3DX compile routine is parsed and used
+// to write human-readable asm code into the character array pointed to by
+// pDisassembledCode. An error code is returned.
+//------------------------------------------------------------------------------
+
+static int g_translationCounter = 0;
+
+int D3DToGL::TranslateShader( uint32* code, CUtlBuffer *pBufDisassembledCode, bool *bVertexShader, uint32 options, int32 nShadowDepthSampler, uint32 nCentroidMask, char *debugLabel )
+{
+ CUtlString sLine, sParamName;
+ uint32 dwToken, nInstruction, nNumTokensToSkip;
+ char buff[256];
+
+ // obey options
+ m_bUseEnvParams = (options & D3DToGL_OptionUseEnvParams) != 0;
+ m_bDoFixupZ = (options & D3DToGL_OptionDoFixupZ) != 0;
+ m_bDoFixupY = (options & D3DToGL_OptionDoFixupY) != 0;
+ m_bDoUserClipPlanes = (options & D3DToGL_OptionDoUserClipPlanes) != 0;
+ m_bGLSL = (options & D3DToGL_OptionGLSL) != 0;
+ m_bAllowStaticControlFlow = m_bGLSL && (options & D3DToGL_OptionAllowStaticControlFlow) != 0;
+ m_bAddHexCodeComments = (options & D3DToGL_AddHexComments) != 0;
+ m_bPutHexCodesAfterLines = (options & D3DToGL_PutHexCommentsAfterLines) != 0;
+ m_bGeneratingDebugText = (options & D3DToGL_GeneratingDebugText) != 0;
+ m_bUseBindableUniforms = (options & D3DToGL_OptionUseBindableUniforms) != 0;
+ m_bGenerateSRGBWriteSuffix = (options & D3DToGL_OptionSRGBWriteSuffix) != 0;
+
+ m_nLoopDepth = 0;
+
+ // debugging
+ m_bSpew = (options & D3DToGL_OptionSpew) != 0;
+
+ // m_bSpew |= (g_translationCounter == 1012 ); // interested in this specific translation run
+
+ // These are not accessed below in a way that will cause them to glow, so
+ // we could overflow these and/or the buffer pointed to by pDisassembledCode
+ m_pBufAttribCode = new CUtlBuffer( 100, 10000, CUtlBuffer::TEXT_BUFFER );
+ m_pBufParamCode = new CUtlBuffer( 100, 10000, CUtlBuffer::TEXT_BUFFER );
+ m_pBufALUCode = new CUtlBuffer( 100, 60000, CUtlBuffer::TEXT_BUFFER );
+
+ // Pointers to text buffers for assembling sections of the program
+ m_pBufHeaderCode = pBufDisassembledCode;
+ char *pAttribMapStart = NULL;
+ ((char*)m_pBufHeaderCode->Base())[0] = 0;
+ ((char*)m_pBufAttribCode->Base())[0] = 0;
+ ((char*)m_pBufParamCode->Base())[0] = 0;
+ ((char*)m_pBufALUCode->Base())[0] = 0;
+
+
+ for ( int i = 0; i < MAX_SHADER_CONSTANTS; i++ )
+ {
+ m_bConstantRegisterDefined[i] = false;
+ }
+
+ // Track shadow sampler usage for proper declaration
+ m_nShadowDepthSampler = nShadowDepthSampler;
+ m_bDeclareShadowOption = false;
+
+ // Various flags set while parsing code to drive various declaration instructions
+ m_bNeedsD2AddTemp = false;
+ m_bNeedsLerpTemp = false;
+ m_bNeedsNRMTemp = false;
+ m_bNeedsSinCosDeclarations = false;
+ m_bDeclareAddressReg = false;
+ m_bDeclareVSOPos = false;
+ m_bDeclareVSOFog = false;
+ m_dwTexCoordOutMask = 0x00000000;
+ m_bOutputColorRegister[0] = false;
+ m_bOutputColorRegister[1] = false;
+ m_bOutputColorRegister[2] = false;
+ m_bOutputColorRegister[3] = false;
+ m_bOutputDepthRegister = false;
+ m_bTangentInputUsed = false;
+ m_dwTempUsageMask = 0x00000000;
+ m_dwSamplerUsageMask = 0x00000000;
+ m_dwConstIntUsageMask = 0x00000000;
+ m_dwConstBoolUsageMask = 0x00000000;
+ m_nCentroidMask = nCentroidMask;
+ m_nHighestRegister = 0;
+
+ m_bUsedAtomicTempVar = false;
+ for ( int i = 0; i < ARRAYSIZE( m_dwSamplerTypes ); i++ )
+ {
+ m_dwSamplerTypes[i] = SAMPLER_TYPE_UNUSED;
+ }
+ for ( int i = 0; i < ARRAYSIZE( m_DeclaredOutputs ); i++ )
+ {
+ m_DeclaredOutputs[i] = UNDECLARED_OUTPUT;
+ }
+
+ memset( m_dwAttribMap, 0xFF, sizeof(m_dwAttribMap) );
+
+ m_pdwBaseToken = m_pdwNextToken = code; // Initialize dwToken pointers
+
+ dwToken = GetNextToken();
+ m_dwMajorVersion = D3DSHADER_VERSION_MAJOR( dwToken );
+ m_dwMinorVersion = D3DSHADER_VERSION_MINOR( dwToken );
+
+ // We only do vs_2_0 and ps_2_x
+ if ( m_dwMajorVersion != 2 )
+ {
+ Debugger();
+ }
+
+ // If pixel shader
+ char *glslBindableUniformExtText = (char*)((m_bGLSL && m_bUseBindableUniforms) ? "#extension GL_EXT_bindable_uniform : enable\n" : "");
+
+ if ( ( dwToken & 0xFFFF0000 ) == 0xFFFF0000 )
+ {
+ // must explicitly enable extensions if emitting GLSL
+ V_snprintf( (char *)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), m_bGLSL ? "#version 120\n%s" : "!!ARBfp1.0\n%s", glslBindableUniformExtText );
+ m_bVertexShader = false;
+ }
+ else // vertex shader
+ {
+ m_bGenerateSRGBWriteSuffix = false;
+
+ if ( m_bGLSL )
+ {
+ V_snprintf( (char *)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), "#version 120\n%s//ATTRIBMAP-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx\n", glslBindableUniformExtText );
+ }
+ else // asm
+ {
+ if ( m_bDoUserClipPlanes )
+ {
+ // include "OPTION NV_vertex_program2;"
+ V_snprintf( (char *)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), "!!ARBvp1.0\n#//ATTRIBMAP-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx\nOPTION NV_vertex_program2;\n" );
+ }
+ else
+ {
+ // do not include "OPTION NV_vertex_program2;"
+ V_snprintf( (char *)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), "!!ARBvp1.0\n#//ATTRIBMAP-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx\n" );
+ }
+ }
+
+ // find that first '-xx' which is where the attrib map will be written later.
+ pAttribMapStart = strstr( (char *)m_pBufHeaderCode->Base(), "-xx" ) + 1;
+
+ m_bVertexShader = true;
+ }
+
+ *bVertexShader = m_bVertexShader;
+
+ if ( m_bAddHexCodeComments )
+ {
+ RecordInputAndOutputPositions();
+ }
+
+ if ( m_bSpew )
+ {
+ printf("\n************* translating shader " );
+ }
+
+ int opcounter = 0;
+
+ // Loop until we hit the end dwToken...note that D3DPS_END() == D3DVS_END() so this works for either
+ while ( dwToken != D3DPS_END() )
+ {
+ if ( m_bAddHexCodeComments )
+ {
+ AddTokenHexCode();
+ RecordInputAndOutputPositions();
+ }
+
+#ifdef POSIX
+ int tokenIndex = m_pdwNextToken - code;
+#endif
+ int aluCodeLength0 = V_strlen( (char *) m_pBufALUCode->Base() );
+
+ dwToken = GetNextToken(); // Get next dwToken in the stream
+ nInstruction = Opcode( dwToken ); // Mask out the instruction opcode
+
+ if ( m_bSpew )
+ {
+#ifdef POSIX
+ printf("\n** token# %04x inst# %04d opcode %s (%08x)", tokenIndex, opcounter, GLMDecode(eD3D_SIO, nInstruction), dwToken );
+#endif
+ opcounter++;
+ }
+
+ switch ( nInstruction )
+ {
+ // -- No arguments at all -----------------------------------------------
+ case D3DSIO_NOP:
+ case D3DSIO_PHASE:
+ case D3DSIO_RET:
+ case D3DSIO_ENDLOOP:
+ case D3DSIO_BREAK:
+ Assert(0);
+ PrintOpcode( nInstruction, buff, sizeof( buff ) );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ";\n" );
+ break;
+
+ // -- "Declarative" non dcl ops ----------------------------------------
+ case D3DSIO_TEXDEPTH:
+ case D3DSIO_TEXKILL:
+ Handle_DeclarativeNonDclOp( nInstruction );
+ break;
+
+ // -- Unary ops -------------------------------------------------
+ case D3DSIO_BEM:
+ case D3DSIO_TEXBEM:
+ case D3DSIO_TEXBEML:
+ case D3DSIO_TEXDP3:
+ case D3DSIO_TEXDP3TEX:
+ case D3DSIO_TEXM3x2DEPTH:
+ case D3DSIO_TEXM3x2TEX:
+ case D3DSIO_TEXM3x3:
+ case D3DSIO_TEXM3x3PAD:
+ case D3DSIO_TEXM3x3TEX:
+ case D3DSIO_TEXM3x3VSPEC:
+ case D3DSIO_TEXREG2AR:
+ case D3DSIO_TEXREG2GB:
+ case D3DSIO_TEXREG2RGB:
+ case D3DSIO_LABEL:
+ case D3DSIO_CALL:
+ case D3DSIO_LOOP:
+ case D3DSIO_BREAKP:
+ case D3DSIO_DSX:
+ case D3DSIO_DSY:
+ Assert(0);
+ break;
+
+ case D3DSIO_IF:
+ Assert( m_bGLSL && m_bAllowStaticControlFlow );
+ if ( m_bGLSL && m_bAllowStaticControlFlow )
+ {
+ dwToken = GetNextToken();
+ PrintParameterToString( dwToken, SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+
+ // In practice, this is the only form of for loop that will appear in DX asm
+ PrintToBuf( *m_pBufALUCode, "if ( %s ) {\n", buff );
+ }
+ break;
+
+ case D3DSIO_ELSE:
+ Assert( m_bGLSL && m_bAllowStaticControlFlow );
+ if ( m_bGLSL && m_bAllowStaticControlFlow )
+ {
+ StrcatToALUCode( "}\nelse\n{\n" );
+ }
+ break;
+
+ case D3DSIO_ENDIF:
+ Assert( m_bGLSL && m_bAllowStaticControlFlow );
+ if ( m_bGLSL && m_bAllowStaticControlFlow )
+ {
+ StrcatToALUCode( "}\n" );
+ }
+ break;
+
+ case D3DSIO_REP: // Start a for loop - GLSL only
+ Assert( m_bGLSL && m_bAllowStaticControlFlow );
+ if ( m_bGLSL && m_bAllowStaticControlFlow )
+ {
+ dwToken = GetNextToken();
+ PrintParameterToString( dwToken, SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+
+ // In practice, this is the only form of for loop that will appear in DX asm
+ PrintToBuf( *m_pBufALUCode, "for( int i=0; i < %s; i++ ) {\n", buff );
+
+ m_nLoopDepth++;
+
+ // For now, we don't deal with loop nesting
+ // Easy enough to fix later with an array of loop names i, j, k etc
+ Assert( m_nLoopDepth <= 1 );
+ }
+ break;
+
+ case D3DSIO_ENDREP:
+ Assert( m_bGLSL && m_bAllowStaticControlFlow );
+ if ( m_bGLSL && m_bAllowStaticControlFlow )
+ {
+ m_nLoopDepth--;
+ StrcatToALUCode( "}\n" );
+ }
+ break;
+
+ case D3DSIO_NRM:
+ Handle_NRM();
+ break;
+
+ case D3DSIO_MOVA:
+
+ if ( m_bGLSL )
+ {
+ Handle_UnaryOp( nInstruction );
+ }
+ else // asm
+ {
+ m_bDeclareAddressReg = true;
+ m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
+
+ PrintOpcode( nInstruction, buff, sizeof( buff ) );
+ StrcatToALUCode( buff );
+
+ dwToken = GetNextToken();
+ PrintParameterToString( dwToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ", " );
+
+ dwToken = GetNextToken();
+ PrintParameterToString( dwToken, SRC_REGISTER, buff, sizeof( buff ), false, NULL );
+ StrcatToALUCode( buff );
+ StrcatToALUCode( ";\n" );
+ }
+
+ break;
+
+ // Unary operations
+ case D3DSIO_MOV:
+ case D3DSIO_RCP:
+ case D3DSIO_RSQ:
+ case D3DSIO_EXP:
+ case D3DSIO_EXPP:
+ case D3DSIO_LOG:
+ case D3DSIO_LOGP:
+ case D3DSIO_FRC:
+ case D3DSIO_LIT:
+ case D3DSIO_ABS:
+ Handle_UnaryOp( nInstruction );
+ break;
+
+ // -- Binary ops -------------------------------------------------
+ case D3DSIO_TEXM3x3SPEC:
+ case D3DSIO_M4x4:
+ case D3DSIO_M4x3:
+ case D3DSIO_M3x4:
+ case D3DSIO_M3x3:
+ case D3DSIO_M3x2:
+ case D3DSIO_CALLNZ:
+ case D3DSIO_IFC:
+ case D3DSIO_BREAKC:
+ case D3DSIO_SETP:
+ Assert(0);
+ break;
+
+ // Binary Operations
+ case D3DSIO_ADD:
+ case D3DSIO_SUB:
+ case D3DSIO_MUL:
+ case D3DSIO_DP3:
+ case D3DSIO_DP4:
+ case D3DSIO_MIN:
+ case D3DSIO_MAX:
+ case D3DSIO_DST:
+ case D3DSIO_SLT:
+ case D3DSIO_SGE:
+ case D3DSIO_CRS:
+ case D3DSIO_POW:
+ if ( m_bGLSL )
+ {
+ HandleBinaryOp_GLSL( nInstruction );
+ }
+ else
+ {
+ HandleBinaryOp_ASM( nInstruction );
+ }
+ break;
+
+ // -- Ternary ops -------------------------------------------------
+ case D3DSIO_DP2ADD:
+ Handle_DP2ADD();
+ break;
+ case D3DSIO_LRP:
+ Handle_LRP( nInstruction );
+ break;
+ case D3DSIO_SGN:
+ Assert( m_bVertexShader );
+ Assert(0); // TODO emulate with SLT etc
+ break;
+ case D3DSIO_CND:
+ Assert(0);
+ break;
+ case D3DSIO_CMP:
+ Handle_CMP();
+ break;
+ case D3DSIO_SINCOS:
+ Handle_SINCOS();
+ break;
+ case D3DSIO_MAD:
+ Handle_MAD( nInstruction );
+ break;
+
+ // -- Quaternary op ------------------------------------------------
+ case D3DSIO_TEXLDD:
+ Handle_TexLDD( nInstruction );
+ break;
+
+ // -- Special cases: texcoord vs texcrd and tex vs texld -----------
+ case D3DSIO_TEXCOORD:
+ Handle_TexCoord();
+ break;
+
+ case D3DSIO_TEX:
+ Handle_TEX( dwToken, false );
+ break;
+
+ case D3DSIO_TEXLDL:
+ Handle_TEX( nInstruction, true );
+ break;
+
+ case D3DSIO_DCL:
+ Handle_DCL();
+ break;
+
+ case D3DSIO_DEFB:
+ case D3DSIO_DEFI:
+ // Shouldn't be using bool or integer constants
+ Assert(0);
+ break;
+
+ case D3DSIO_DEF:
+ Handle_DEF();
+ break;
+
+ case D3DSIO_COMMENT:
+ // Using OpcodeSpecificData() can fail here since the comments can be longer than 0xff dwords
+ nNumTokensToSkip = ( dwToken & 0x0fff0000 ) >> 16;
+ SkipTokens( nNumTokensToSkip );
+ break;
+
+ case D3DSIO_END:
+ break;
+ }
+
+ if ( m_bSpew )
+ {
+ int aluCodeLength1 = V_strlen( (char *) m_pBufALUCode->Base() );
+ if ( aluCodeLength1 != aluCodeLength0 )
+ {
+ // code was emitted
+ printf( "\n > %s", ((char *)m_pBufALUCode->Base()) + aluCodeLength0 );
+
+ aluCodeLength0 = aluCodeLength1;
+ }
+ }
+ }
+
+ // Note that this constant packing expects .wzyx swizzles in case we ever use the SINCOS code in a ps_2_x shader
+ //
+ // The Microsoft documentation on this is all kinds of broken and, strangely, these numbers don't even
+ // match the D3DSINCOSCONST1 and D3DSINCOSCONST2 constants used by the D3D assembly sincos instruction...
+ if ( m_bNeedsSinCosDeclarations )
+ {
+ if ( m_bGLSL )
+ {
+ StrcatToParamCode( "vec4 scA = vec4( -1.55009923e-6, -2.17013894e-5, 0.00260416674, 0.00026041668 );\n" );
+ StrcatToParamCode( "vec4 scB = vec4( -0.020833334, -0.125, 1.0, 0.5 );\n" );
+ }
+ else
+ {
+ StrcatToParamCode( "PARAM scA = { -1.55009923e-6, -2.17013894e-5, 0.00260416674, 0.00026041668 };\n" );
+ StrcatToParamCode( "PARAM scB = { -0.020833334, -0.125, 1.0, 0.5 };\n" );
+ }
+ }
+
+ // Stick in the sampler mask in hex
+ PrintToBuf( *m_pBufHeaderCode, "%sSAMPLERMASK-%x\n", m_bGLSL ? "//" : "#", m_dwSamplerUsageMask );
+
+ // Uniforms
+ if ( m_bGLSL )
+ {
+ PrintToBuf( *m_pBufHeaderCode, "//HIGHWATER-%d\n", m_nHighestRegister );
+ PrintToBuf( *m_pBufHeaderCode, "\n%suniform vec4 %s[%d];\n", m_bUseBindableUniforms ? "bindable " : "", m_bVertexShader ? "vc" : "pc", m_nHighestRegister + 1 );
+
+ // On GLSL vertex shaders, we may have integer and boolean constants
+ if ( m_bAllowStaticControlFlow && m_bVertexShader )
+ {
+ for( int i=0; i<32; i++ )
+ {
+ if ( m_dwConstIntUsageMask & ( 0x00000001 << i ) )
+ {
+ PrintToBuf( *m_pBufHeaderCode, "uniform int i%d;\n", i );
+ }
+ }
+
+ for( int i=0; i<32; i++ )
+ {
+ if ( m_dwConstBoolUsageMask & ( 0x00000001 << i ) )
+ {
+ PrintToBuf( *m_pBufHeaderCode, "uniform bool b%d;\n", i );
+ }
+ }
+ }
+
+ // Control bit for sRGB Write suffix
+ if ( m_bGenerateSRGBWriteSuffix )
+ {
+ // R500 Hookup
+ // Set this guy to 1 when the sRGBWrite state is true, otherwise 0
+ StrcatToHeaderCode( "uniform float flSRGBWrite;\n" );
+ }
+
+ PrintToBuf( *m_pBufHeaderCode, "\n" );
+
+ // Write samplers
+ WriteGLSLSamplerDefinitions();
+ }
+ else
+ {
+ PrintToBuf( *m_pBufParamCode, "#HIGHWATER-%d\n", m_nHighestRegister );
+ PrintToBuf( *m_pBufParamCode, "PARAM %s[%d] = { program.%s[0..%d] };\n", m_bVertexShader ? "vc" : "pc", m_nHighestRegister + 1, m_bUseEnvParams ? "env" : "local", m_nHighestRegister );
+ }
+
+ if ( m_bDeclareAddressReg )
+ {
+ m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
+
+ if ( m_bGLSL )
+ {
+ StrcatToParamCode( "vec4 va_r;\nint a0;\n" );
+ }
+ else
+ {
+ StrcatToParamCode( "ADDRESS a0;\n" );
+ StrcatToParamCode( "TEMP VA_REG;\n" );
+ }
+ }
+
+ const char *pTempVarStr = "TEMP";
+ if ( m_bGLSL )
+ {
+ pTempVarStr = "vec4";
+ }
+
+ // Declare temps in Param code buffer
+ for( int i=0; i<32; i++ )
+ {
+ if ( m_dwTempUsageMask & ( 0x00000001 << i ) )
+ {
+ PrintToBuf( *m_pBufParamCode, "%s r%d;\n", pTempVarStr, i );
+ }
+ }
+
+ if ( m_bGLSL && m_bVertexShader )
+ {
+ StrcatToParamCode( "vec4 vTempPos;\n" );
+ }
+
+ if ( m_bNeedsSinCosDeclarations )
+ {
+ if ( m_bGLSL )
+ {
+ StrcatToParamCode( "vec3 vSinCosTmp;\n" ); // declare temp used by GLSL sin and cos intrinsics
+ }
+ else
+ {
+ PrintToBuf( *m_pBufParamCode, "%s SC_TEMP;\n", pTempVarStr );
+ }
+ }
+
+ // Optional temps needed to emulate d2add instruction in DX pixel shaders
+ if ( m_bNeedsD2AddTemp )
+ {
+ PrintToBuf( *m_pBufParamCode, "%s DP2A0;\n%s DP2A1;\n", pTempVarStr, pTempVarStr );
+ }
+
+ // Optional temp needed to emulate lerp instruction in DX vertex shaders
+ if ( m_bNeedsLerpTemp )
+ {
+ PrintToBuf( *m_pBufParamCode, "%s LRP_TEMP;\n", pTempVarStr );
+ }
+
+ // Optional temp needed to emulate NRM instruction in DX shaders
+ if ( m_bNeedsNRMTemp )
+ {
+ PrintToBuf( *m_pBufParamCode, "%s NRM_TEMP;\n", pTempVarStr );
+ }
+
+ // Pixel shader color outputs (MRT support?...just declare MRT outputs as useless TEMPS)
+ if ( !m_bGLSL && !m_bVertexShader )
+ {
+ if ( m_bOutputColorRegister[1] )
+ {
+ StrcatToParamCode( "TEMP oC1;\n" );
+ }
+ if ( m_bOutputColorRegister[2] )
+ {
+ StrcatToParamCode( "TEMP oC2;\n" );
+ }
+ if ( m_bOutputColorRegister[3] )
+ {
+ StrcatToParamCode( "TEMP oC3;\n" );
+ }
+ if ( m_bOutputColorRegister[0] )
+ {
+ StrcatToParamCode( "OUTPUT oC0 = result.color;\n" );
+ }
+ }
+
+ if ( m_bDeclareVSOPos && m_bVertexShader )
+ {
+ if ( m_bGLSL )
+ {
+ if (m_bDoUserClipPlanes)
+ {
+ StrcatToALUCode( "gl_ClipVertex = vTempPos;\n" ); // if user clip is enabled, jam clip space position into gl_ClipVertex
+ }
+ }
+
+ if ( m_bDoFixupZ || m_bDoFixupY )
+ {
+ if ( !m_bGLSL )
+ {
+ // don't write to real reg - declare a temp and then declare a new output reg oPosGL
+ StrcatToParamCode( "TEMP oPos;\n" );
+ StrcatToParamCode( "OUTPUT oPosGL = result.position;\n" );
+ }
+
+ // TODO: insert clip distance computation something like this:
+ //
+ // StrcatToALUCode( "DP4 oCLP[0].x, oPos, vc[215]; \n" );
+ //
+
+ if ( m_bDoFixupZ )
+ {
+ if ( m_bGLSL )
+ {
+ StrcatToALUCode( "vTempPos.z = vTempPos.z * vc[0].z - vTempPos.w; // z' = (2*z)-w\n" );
+ }
+ else
+ {
+ // append instructions to perform Z fixup
+ // new Z = (old Z * 2.0) - W
+
+ // negate Z, double it, then add the 'w'.
+ // near: Z=0 -> Z' = +1.0. this seems wrong....
+ // far: Z=1 -> Z' = -1.0 uh, this ain't right...
+ // StrcatToALUCode( "MAD r0.z, -oPos.z, vc[0].z, oPos.w; # z' = (2*-z)+w\n" );
+
+ // double Z, subtract 'w'.
+ // near: Z=0 -> Z' = -1.0.
+ // far: Z=1 -> Z' = +1.0
+ //StrcatToALUCode( "MAD r0.z, oPos.z, vc[0].z, -oPos.w; # z' = (2*z)-w\n" );
+ StrcatToALUCode( "MAD oPos.z, oPos.z, vc[0].z, -oPos.w; # z' = (2*z)-w\n" );
+ }
+ }
+
+ if ( m_bDoFixupY )
+ {
+ // append instructions to flip Y over
+ // new Y = -(old Y)
+ if ( m_bGLSL )
+ {
+ StrcatToALUCode( "vTempPos.y = -vTempPos.y; // y' = -y \n" );
+ }
+ else
+ {
+ StrcatToALUCode( "MOV oPos.y, -oPos.y; # y' = -y \n" );
+ }
+ }
+
+ if ( m_bGLSL )
+ {
+ StrcatToALUCode( "gl_Position = vTempPos;\n" );
+ }
+ else
+ {
+ StrcatToALUCode( "MOV oPosGL, oPos;\n" );
+ }
+
+ }
+ else
+ {
+ StrcatToParamCode( "OUTPUT oPos = result.position;\n" );
+
+ // TODO: insert clip distance computation something like this:
+ //
+ // StrcatToALUCode( "DP4 oCLP[0].x, oPos, c[215]; \n" );
+ //
+ }
+ }
+
+ if ( m_bVertexShader && m_bDoUserClipPlanes && !m_bGLSL )
+ {
+ // insert oCLP generation instructions
+ char temp[256];
+
+ if(0)
+ {
+ V_snprintf( temp, sizeof( temp ), "DP4 result.clip[0].x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE ); // ask GLM where to stash the secret params
+ V_snprintf( temp, sizeof( temp ), "DP4 result.clip[1].x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE+1 );
+ }
+
+ if(0)
+ {
+ V_snprintf( temp, sizeof( temp ), "DP4 o[CLP0].x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE ); // ask GLM where to stash the secret params
+ V_snprintf( temp, sizeof( temp ), "DP4 o[CLP1].x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE+1 );
+ }
+
+ if(1)
+ {
+ V_snprintf( temp, sizeof( temp ), "DP4 oClip0.x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE ); // ask GLM where to stash the secret params
+ V_snprintf( temp, sizeof( temp ), "DP4 oClip1.x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE+1 );
+ }
+
+ StrcatToALUCode( temp );
+ }
+
+ if ( m_bGLSL )
+ {
+ if ( m_bVertexShader )
+ {
+ for ( int i=0; i<32; i++ )
+ {
+ char outTexCoordBuff[64];
+ if ( m_dwTexCoordOutMask & ( 0x00000001 << i ) )
+ {
+ if ( m_nCentroidMask & ( 0x00000001 << i ) )
+ {
+ V_snprintf( outTexCoordBuff, sizeof( outTexCoordBuff ), "centroid varying vec4 oT%d;\n", i ); // centroid varying
+ StrcatToHeaderCode( outTexCoordBuff );
+ }
+ else
+ {
+ V_snprintf( outTexCoordBuff, sizeof( outTexCoordBuff ), "varying vec4 oT%d;\n", i );
+ StrcatToHeaderCode( outTexCoordBuff );
+ }
+ }
+ }
+ }
+ }
+ else // asm
+ {
+ if ( m_bDeclareVSOFog && m_bVertexShader )
+ {
+ StrcatToParamCode( "OUTPUT oFog = result.fogcoord;\n" );
+ }
+
+ for ( int i=0; i<32; i++ )
+ {
+ char outTexCoordBuff[64];
+ if ( m_dwTexCoordOutMask & ( 0x00000001 << i ) )
+ {
+ V_snprintf( outTexCoordBuff, sizeof( outTexCoordBuff ), "OUTPUT oT%d = result.texcoord[%d];\n", i, i );
+ StrcatToParamCode( outTexCoordBuff );
+ }
+ }
+
+ if ( m_bOutputColorRegister[0] && m_bVertexShader )
+ {
+ StrcatToParamCode( "OUTPUT oD0 = result.color;\n" );
+ }
+
+ if ( m_bOutputColorRegister[1] && m_bVertexShader )
+ {
+ StrcatToParamCode( "OUTPUT oD1 = result.color.secondary;\n" );
+ }
+ }
+
+ if ( m_bOutputDepthRegister && !m_bVertexShader && !m_bGLSL )
+ {
+ StrcatToParamCode( "OUTPUT oDepth = result.depth;\n" );
+ }
+
+ if ( m_bDoUserClipPlanes && m_bVertexShader && !m_bGLSL )
+ {
+ StrcatToParamCode( "OUTPUT oClip0 = result.clip[0];\n" );
+ StrcatToParamCode( "OUTPUT oClip1 = result.clip[1];\n" );
+ }
+
+ // do some annotation at the end of the attrib block
+ {
+ char temp[1000];
+
+ if ( m_bVertexShader )
+ {
+ // write attrib map into the text starting at pAttribMapStart - two hex digits per attrib
+ for( int i=0; i<16; i++ )
+ {
+ if ( m_dwAttribMap[i] != 0xFFFFFFFF )
+ {
+ V_snprintf( temp, sizeof(temp), "%02X", m_dwAttribMap[i] );
+ memcpy( pAttribMapStart + (i*3), temp, 2 );
+ }
+ }
+ }
+
+ V_snprintf( temp, sizeof(temp), "%s trans#%d label:%s\n", m_bGLSL ? "//" : "#", g_translationCounter, debugLabel ? debugLabel : "none" );
+ StrcatToAttribCode( temp );
+
+ g_translationCounter++;
+ }
+
+ // If we actually sample from a shadow depth sampler, we need to declare the shadow option at the top
+ if ( m_bDeclareShadowOption )
+ {
+ StrcatToHeaderCode( "OPTION ARB_fragment_program_shadow;\n" );
+ }
+
+ if ( m_bGLSL )
+ {
+ StrcatToHeaderCode( "\nvoid main()\n{\n" );
+ if ( m_bUsedAtomicTempVar )
+ {
+ PrintToBuf( *m_pBufHeaderCode, "vec4 %s;\n\n", g_pAtomicTempVarName );
+ }
+ }
+
+ // sRGB Write suffix
+ if ( m_bGenerateSRGBWriteSuffix )
+ {
+ Assert( m_bGLSL );
+ if ( m_bGLSL )
+ {
+ StrcatToALUCode( "vec3 sRGBFragData;\n" );
+ StrcatToALUCode( "sRGBFragData.xyz = log( gl_FragData[0].xyz );\n" );
+ StrcatToALUCode( "sRGBFragData.xyz = sRGBFragData.xyz * vec3( 0.454545f, 0.454545f, 0.454545f );\n" );
+ StrcatToALUCode( "sRGBFragData.xyz = exp( sRGBFragData.xyz );\n" );
+ StrcatToALUCode( "gl_FragData[0].xyz = mix( gl_FragData[0].xyz, sRGBFragData, flSRGBWrite );\n" );
+ }
+ }
+
+ if ( m_bGLSL )
+ {
+ WriteGLSLOutputVariableAssignments();
+ StrcatToALUCode( "\n}\n" );
+ }
+ else
+ {
+ StrcatToALUCode( "END\n\0" );
+ }
+
+ // Put all of the strings together for final program ( pHeaderCode + pAttribCode + pParamCode + pALUCode )
+ StrcatToHeaderCode( (char*)m_pBufAttribCode->Base() );
+ StrcatToHeaderCode( (char*)m_pBufParamCode->Base() );
+ StrcatToHeaderCode( (char*)m_pBufALUCode->Base() );
+
+ // Cleanup - don't touch m_pBufHeaderCode, as it is managed by the caller
+ delete m_pBufAttribCode;
+ delete m_pBufParamCode;
+ delete m_pBufALUCode;
+ m_pBufAttribCode = m_pBufParamCode = m_pBufALUCode = NULL;
+
+ if ( m_bSpew )
+ {
+ printf("\n************* translation complete\n\n " );
+ }
+
+ return DISASM_OK;
+}
diff --git a/My project/sdk/glmgr/dx9asmtogl2.h b/My project/sdk/glmgr/dx9asmtogl2.h
new file mode 100644
index 000000000..41ce47740
--- /dev/null
+++ b/My project/sdk/glmgr/dx9asmtogl2.h
@@ -0,0 +1,233 @@
+//------------------------------------------------------------------------------
+// DX9AsmToGL2.h
+//------------------------------------------------------------------------------
+
+#ifndef DX9_ASM_TO_GL_2_H
+#define DX9_ASM_TO_GL_2_H
+
+#include "glmgr.h"
+
+//==============================================================================
+
+
+#define DISASM_OK 0
+#define DISASM_ERROR 1
+
+#define MAX_SHADER_CONSTANTS 512
+
+#define MAX_DECLARED_OUTPUTS 32
+
+#define HEXCODE_HEADER "// Hex: "
+
+// Option bits
+#define D3DToGL_OptionUseEnvParams 0x001
+#define D3DToGL_OptionDoFixupZ 0x002 // Add instructions to put Z in the right interval for GL
+#define D3DToGL_OptionDoFixupY 0x004 // Add instructions to flip the Y over for GL
+#define D3DToGL_OptionDoUserClipPlanes 0x008 // ARB mode: Include OPTION vertex_program_2 and append DP4's to write into oCLP[0] and oCLP[1]
+ // GLSL mode: generate code to write gl_ClipVertex
+#define D3DToGL_OptionGLSL 0x010 // Output GLSL, rather than ASM
+#define D3DToGL_AddHexComments 0x020 // Include hex comments in the code for debugging
+#define D3DToGL_PutHexCommentsAfterLines 0x040 // If D3DToGL_AddHexComments is set, this puts the codes to the right, rather than on separate lines
+#define D3DToGL_GeneratingDebugText 0x080 // This tells it that we're just getting info for debugging so go easy on asserts and errors
+#define D3DToGL_OptionAllowStaticControlFlow 0x100
+#define D3DToGL_OptionUseBindableUniforms 0x200 // add "bindable" in front of "vc" / "pc" constant arrays (GLSL only)
+#define D3DToGL_OptionSRGBWriteSuffix 0x400 // Tack sRGB conversion suffix on to pixel shaders
+#define D3DToGL_OptionSpew 0x80000000
+
+// Code for which component of the "dummy" address register is needed by an instruction
+#define ARL_DEST_NONE -1
+#define ARL_DEST_X 0
+#define ARL_DEST_Y 1
+#define ARL_DEST_Z 2
+#define ARL_DEST_W 3
+
+class D3DToGL
+{
+private:
+ // Pointers for dwToken stream management
+ uint32* m_pdwBaseToken;
+ uint32* m_pdwNextToken;
+
+ // Vertex shader or pixel shader, and version (necessary because some opcodes alias)
+ bool m_bVertexShader;
+ uint32 m_dwMinorVersion;
+ uint32 m_dwMajorVersion;
+
+ // Option flags
+ bool m_bUseEnvParams; // set D3DToGL_OptionUseEnvParams in 'options' to use
+ bool m_bDoFixupZ; // set D3DToGL_OptionDoFixupZ
+ bool m_bDoFixupY; // set D3DToGL_OptionDoFixupZ
+ bool m_bDoUserClipPlanes; // set D3DToGL_OptionDoUserClipPlanes
+ bool m_bSpew; // set D3DToGL_OptionSpew
+ bool m_bUseBindableUniforms; // set D3DToGL_OptionUseBindableUniforms
+ bool m_bGenerateSRGBWriteSuffix; // set D3DToGL_OptionSRGBWriteSuffix
+
+ // Default: false
+ // If you set this to true, it'll convert to GLSL instead of GL ASM.
+ bool m_bGLSL; // set D3DToGL_OptionGLSL
+
+ // Default: false
+ bool m_bAllowStaticControlFlow; // set D3DToGL_OptionAllowStaticControlFlow
+
+ // Counter for dealing with nested loops
+ int m_nLoopDepth;
+
+ // Add "// Hex: 0xFFEEF00"-type statements after each instruction is parsed.
+ bool m_bAddHexCodeComments; // set D3DToGL_AddHexComments
+
+ // Only applicable if m_bAddHexCodeComments is true.
+ // If this is true, then it puts the hex code comments to the right of the instructions in a comment
+ // rather than preceding the instructions.
+ // Defaults to FALSE.
+ bool m_bPutHexCodesAfterLines; // set D3DToGL_PutHexCommentsAtEnd
+
+ // This tells it that we're just getting info for debugging so go easy on asserts and errors.
+ // Defaults to FALSE.
+ bool m_bGeneratingDebugText;
+
+ // Various scratch temps needed to handle mis-matches in instruction sets between D3D and OpenGL
+ bool m_bNeedsD2AddTemp;
+ bool m_bNeedsNRMTemp;
+ bool m_bDeclareAddressReg;
+ bool m_bNeedsLerpTemp;
+ bool m_bNeedsSinCosDeclarations;
+
+ // Keep track of which vs outputs are used so we can declare them
+ bool m_bDeclareVSOPos;
+ bool m_bDeclareVSOFog;
+ uint32 m_dwTexCoordOutMask;
+
+ // Mask of varyings which need centroid decoration
+ uint32 m_nCentroidMask;
+
+ // Keep track of which temps are used so they can be declared
+ uint32 m_dwTempUsageMask;
+ bool m_bOutputColorRegister[4];
+ bool m_bOutputDepthRegister;
+
+ // Declaration of integer and bool constants
+ uint32 m_dwConstIntUsageMask;
+ uint32 m_dwConstBoolUsageMask;
+
+ // Did we use atomic_temp_var?
+ bool m_bUsedAtomicTempVar;
+
+ // Track constants so we know how to declare them
+ bool m_bConstantRegisterDefined[MAX_SHADER_CONSTANTS];
+
+ // Track sampler types when declared so we can properly decorate TEX instructions
+ uint32 m_dwSamplerTypes[32];
+
+ // Track sampler usage
+ uint32 m_dwSamplerUsageMask;
+
+ // Track shadow sampler usage
+ int m_nShadowDepthSampler;
+ bool m_bDeclareShadowOption;
+
+ // Track attribute references
+ // init to 0xFFFFFFFF (unhit)
+ // index by (dwRegToken & D3DSP_REGNUM_MASK) in VS DCL insns
+ // fill with (usage<<4) | (usage index).
+ uint32 m_dwAttribMap[16];
+
+ // Register high water mark
+ uint32 m_nHighestRegister;
+
+ // GLSL does indentation for readability
+ int m_NumIndentTabs;
+
+ // Output buffers.
+ CUtlBuffer *m_pBufHeaderCode;
+ CUtlBuffer *m_pBufAttribCode;
+ CUtlBuffer *m_pBufParamCode;
+ CUtlBuffer *m_pBufALUCode;
+
+ char *m_pFinalAssignmentsCode;
+ int m_nFinalAssignmentsBufSize;
+
+ // Recorded positions for debugging.
+ uint32* m_pRecordedInputTokenStart;
+ int m_nRecordedParamCodeStrlen;
+ int m_nRecordedALUCodeStrlen;
+ int m_nRecordedAttribCodeStrlen;
+
+ // In GLSL mode, these store the semantic attached to each oN register.
+ // They are the values that you pass to GetUsageIndexAndString.
+ uint32 m_DeclaredOutputs[MAX_DECLARED_OUTPUTS];
+
+ // Have they used the tangent input semantic (i.e. is g_pTangentAttributeName declared)?
+ bool m_bTangentInputUsed;
+
+
+private:
+ // Utilities to aid in decoding token stream
+ uint32 GetNextToken( void );
+ void SkipTokens( uint32 numToSkip );
+ uint32 Opcode( uint32 dwToken );
+ uint32 OpcodeSpecificData( uint32 dwToken );
+ uint32 TextureType ( uint32 dwToken );
+ uint32 GetRegType( uint32 dwRegToken );
+
+ // Write to the different buffers.
+ void StrcatToHeaderCode( const char *pBuf );
+ void StrcatToALUCode( const char *pBuf );
+ void StrcatToParamCode( const char *pBuf );
+ void StrcatToAttribCode( const char *pBuf );
+
+ // This helps write the token hex codes into the output stream for debugging.
+ void AddTokenHexCodeToBuffer( char *pBuffer, int nSize, int nLastStrlen );
+ void RecordInputAndOutputPositions();
+ void AddTokenHexCode();
+
+ // Utilities for decoding tokens in to strings according to ASM syntax
+ void PrintOpcode( uint32 inst, char* buff, int nBufLen );
+
+ // fSemanticFlags is SEMANTIC_INPUT or SEMANTIC_OUTPUT.
+ void PrintUsageAndIndexToString( uint32 dwToken, char* strUsageUsageIndexName, int nBufLen, int fSemanticFlags );
+ CUtlString GetUsageAndIndexString( uint32 dwToken, int fSemanticFlags );
+ CUtlString GetParameterString( uint32 dwToken, uint32 dwSourceOrDest, bool bForceScalarSource, int *pARLDestReg );
+ const char* GetGLSLOperatorString( uint32 inst );
+
+ void PrintParameterToString ( uint32 dwToken, uint32 dwSourceOrDest, char *pRegisterName, int nBufLen, bool bForceScalarSource, int *pARLDestReg );
+
+ void InsertMoveFromAddressRegister( CUtlBuffer *pCode, int nARLComp0, int nARLComp1, int nARLComp2 = ARL_DEST_NONE );
+ void InsertMoveInstruction( CUtlBuffer *pCode, int nARLComponent );
+ void FlagIndirectRegister( uint32 dwToken, int *pARLDestReg );
+
+ // Utilities for decoding tokens in to strings according to GLSL syntax
+ bool OpenIntrinsic( uint32 inst, char* buff, int nBufLen, uint32 destDimension, uint32 nArgumentDimension );
+ void PrintIndentation( char *pBuf, int nBufLen );
+
+ uint32 MaintainAttributeMap( uint32 dwToken, uint32 dwRegToken );
+
+ CUtlString FixGLSLSwizzle( const char *pDestRegisterName, const char *pSrcRegisterName );
+ void WriteGLSLCmp( const char *pDestReg, const char *pSrc0Reg, const char *pSrc1Reg, const char *pSrc2Reg );
+ void WriteGLSLSamplerDefinitions();
+ void WriteGLSLOutputVariableAssignments();
+ void NoteTangentInputUsed();
+
+ void Handle_DCL();
+ void Handle_DEF();
+ void Handle_MAD( uint32 nInstruction );
+ void Handle_DP2ADD();
+ void Handle_SINCOS();
+ void Handle_LRP( uint32 nInstruction );
+ void Handle_TEX( uint32 dwToken, bool bIsTexLDL );
+ void Handle_TexLDD( uint32 nInstruction );
+ void Handle_TexCoord();
+ void Handle_UnaryOp( uint32 nInstruction );
+ void HandleBinaryOp_GLSL( uint32 nInstruction );
+ void HandleBinaryOp_ASM( uint32 nInstruction );
+ void Handle_CMP();
+ void Handle_NRM();
+ void Handle_DeclarativeNonDclOp( uint32 nInstruction );
+
+public:
+ D3DToGL();
+
+ int TranslateShader( uint32* code, CUtlBuffer *pBufDisassembledCode, bool *bVertexShader, uint32 options, int32 nShadowDepthSampler, uint32 nCentroidMask, char *debugLabel );
+};
+
+
+#endif // DX9_ASM_TO_GL_2_H
diff --git a/My project/sdk/glmgr/dxabstract.cpp b/My project/sdk/glmgr/dxabstract.cpp
new file mode 100644
index 000000000..c3533bbae
--- /dev/null
+++ b/My project/sdk/glmgr/dxabstract.cpp
@@ -0,0 +1,5951 @@
+//================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. =================
+//
+//
+//
+//==================================================================================================
+
+#include "dxabstract.h"
+#include "dx9asmtogl2.h"
+#include "mathlite.h"
+
+#ifdef OSX
+#include "glmgr.h"
+
+#include "../SteamWorksExample/gameengineosx.h"
+
+#if DX9MODE
+ extern CGameEngineGL *g_engine; // so dxabstract (which is C++) can call up to the game engine ObjC object and ask for things..
+#endif
+
+#include
+
+// Debugger - 10.8
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wunused-variable"
+#endif
+
+#ifdef USE_ACTUAL_DX
+
+#pragma comment( lib, "../../dx9sdk/lib/d3d9.lib" )
+#pragma comment( lib, "../../dx9sdk/lib/d3dx9.lib" )
+
+#else
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+bool g_useASMTranslations = true;
+//static D3DToGL_ASM g_D3DToOpenGLTranslatorASM; // old translator retired
+static D3DToGL g_D3DToOpenGLTranslatorASM; // same class as the GLSL one, just invoked with different options
+
+bool g_useGLSLTranslations = true;
+static D3DToGL g_D3DToOpenGLTranslatorGLSL;
+
+bool g_bUseControlFlow = false;
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+void GlobalMemoryStatus( MEMORYSTATUS *pOut )
+{
+ //cheese: return 2GB physical
+ pOut->dwTotalPhys = (1<<31);
+}
+
+void Sleep( unsigned int ms )
+{
+ Assert(0);
+}
+
+bool IsIconic( VD3DHWND hWnd )
+{
+ // FIXME for now just act non-minimized all the time
+ return false;
+}
+
+void GetClientRect( void *hWnd, RECT *destRect )
+{
+ // the only useful answer this call can offer, is the size of the canvas.
+ // actually getting the window bounds is not useful.
+ // so, see if a D3D device is up and running, and if so,
+ // dig in and find out its backbuffer size and use that.
+
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+ uint width, height;
+ g_engine->RenderedSize( width, height, false ); // false = get them, don't set them
+ Assert( width!=0 && height!=0 );
+
+ destRect->left = 0;
+ destRect->top = 0;
+ destRect->right = width;
+ destRect->bottom = height;
+
+ //GLMPRINTF(( "-D- GetClientRect returning rect of (0,0, %d,%d)",width,height ));
+#endif
+
+ return;
+}
+
+BOOL ClientToScreen( VD3DHWND hWnd, LPPOINT pPoint )
+{
+ Assert(0);
+ return true;
+}
+
+void* GetCurrentThread()
+{
+ Assert(0);
+ return 0;
+}
+
+void SetThreadAffinityMask( void *hThread, int nMask )
+{
+ Assert(0);
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#if 0
+#pragma mark ----- D3DXMATRIX operators
+
+D3DXMATRIX D3DXMATRIX::operator*( const D3DXMATRIX &o ) const
+{
+ D3DXMATRIX result;
+
+ D3DXMatrixMultiply( &result, this, &o ); // this = lhs o = rhs result = this * o
+
+ return result;
+}
+
+D3DXMATRIX::operator FLOAT* ()
+{
+ return (float*)this;
+}
+
+float& D3DXMATRIX::operator()( int row, int column )
+{
+ return m[row][column];
+}
+
+const float& D3DXMATRIX::operator()( int row, int column ) const
+{
+ return m[row][column];
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- D3DXPLANE operators
+
+float& D3DXPLANE::operator[]( int i )
+{
+ return ((float*)this)[i];
+}
+
+bool D3DXPLANE::operator==( const D3DXPLANE &o )
+{
+ return a == o.a && b == o.b && c == o.c && d == o.d;
+}
+
+bool D3DXPLANE::operator!=( const D3DXPLANE &o )
+{
+ return !( *this == o );
+}
+
+D3DXPLANE::operator float*()
+{
+ return (float*)this;
+}
+
+D3DXPLANE::operator const float*() const
+{
+ return (const float*)this;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- D3DXVECTOR2 operators
+
+D3DXVECTOR2::operator FLOAT* ()
+{
+ return (float*)this;
+}
+
+D3DXVECTOR2::operator CONST FLOAT* () const
+{
+ return (const float*)this;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- D3DXVECTOR3 operators
+
+D3DXVECTOR3::D3DXVECTOR3( float a, float b, float c )
+{
+ x = a;
+ y = b;
+ z = c;
+}
+
+D3DXVECTOR3::operator FLOAT* ()
+{
+ return (float*)this;
+}
+
+D3DXVECTOR3::operator CONST FLOAT* () const
+{
+ return (const float*)this;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+
+#pragma mark ----- D3DXVECTOR4 operators
+
+D3DXVECTOR4::D3DXVECTOR4( float a, float b, float c, float d )
+{
+ x = a;
+ y = b;
+ z = c;
+ w = d;
+}
+#endif
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+DWORD IDirect3DResource9::SetPriority(DWORD PriorityNew)
+{
+// Debugger();
+// GLMPRINTF(( "-X- SetPriority" ));
+ // no-op city
+ return 0;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- IDirect3DBaseTexture9
+
+IDirect3DBaseTexture9::~IDirect3DBaseTexture9()
+{
+ GLMPRINTF(( ">-A- ~IDirect3DBaseTexture9" ));
+
+ if (m_device)
+ {
+ GLMPRINTF(( "-A- ~IDirect3DBaseTexture9 taking normal delete path on %08x, device is %08x ", this, m_device ));
+ m_device->ReleasedTexture( this );
+
+ if (m_tex)
+ {
+ GLMPRINTF(("-A- ~IDirect3DBaseTexture9 deleted '%s' @ %08x (GLM %08x) %s",m_tex->m_layout->m_layoutSummary, this, m_tex, m_tex->m_debugLabel ? m_tex->m_debugLabel : "" ));
+
+ m_tex->m_ctx->DelTex( m_tex );
+ m_tex = NULL;
+ }
+ else
+ {
+ GLMPRINTF(( "-A- ~IDirect3DBaseTexture9 : whoops, no tex to delete here ?" ));
+ }
+ m_device = NULL; // ** THIS ** is the only place to scrub this. Don't do it in the subclass destructors.
+ }
+ else
+ {
+ GLMPRINTF(( "-A- ~IDirect3DBaseTexture9 taking strange delete path on %08x, device is %08x ", this, m_device ));
+ }
+
+ GLMPRINTF(( "<-A- ~IDirect3DBaseTexture9" ));
+}
+
+D3DRESOURCETYPE IDirect3DBaseTexture9::GetType()
+{
+ return m_restype; //D3DRTYPE_TEXTURE;
+}
+
+DWORD IDirect3DBaseTexture9::GetLevelCount()
+{
+ return m_tex->m_layout->m_mipCount;
+}
+
+HRESULT IDirect3DBaseTexture9::GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc)
+{
+ Assert (Level < m_tex->m_layout->m_mipCount);
+
+ D3DSURFACE_DESC result = m_descZero;
+ // then mutate it for the level of interest
+
+ GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ];
+
+ result.Width = slice->m_xSize;
+ result.Height = slice->m_ySize;
+
+ *pDesc = result;
+
+ return S_OK;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- IDirect3DTexture9
+
+HRESULT IDirect3DDevice9::CreateTexture(UINT Width,UINT Height,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DTexture9** ppTexture,VD3DHANDLE* pSharedHandle, char *debugLabel)
+{
+ GLMPRINTF((">-A-IDirect3DDevice9::CreateTexture"));
+ IDirect3DTexture9 *dxtex = new IDirect3DTexture9;
+ dxtex->m_restype = D3DRTYPE_TEXTURE;
+
+ dxtex->m_device = this;
+
+ dxtex->m_descZero.Format = Format;
+ dxtex->m_descZero.Type = D3DRTYPE_TEXTURE;
+ dxtex->m_descZero.Usage = Usage;
+ dxtex->m_descZero.Pool = Pool;
+
+ dxtex->m_descZero.MultiSampleType = D3DMULTISAMPLE_NONE;
+ dxtex->m_descZero.MultiSampleQuality = 0;
+ dxtex->m_descZero.Width = Width;
+ dxtex->m_descZero.Height = Height;
+
+ GLMTexLayoutKey key;
+ memset( &key, 0, sizeof(key) );
+
+ key.m_texGLTarget = GL_TEXTURE_2D;
+ key.m_texFormat = Format;
+
+ if (Levels>1)
+ {
+ key.m_texFlags |= kGLMTexMipped;
+ }
+
+ // http://msdn.microsoft.com/en-us/library/bb172625(VS.85).aspx
+
+ // complain if any usage bits come down that I don't know.
+ uint knownUsageBits = (D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC | D3DUSAGE_TEXTURE_SRGB | D3DUSAGE_DEPTHSTENCIL);
+ if ( (Usage & knownUsageBits) != Usage )
+ {
+ GLMDebugger();
+ }
+
+ if (Usage & D3DUSAGE_AUTOGENMIPMAP)
+ {
+ key.m_texFlags |= kGLMTexMipped | kGLMTexMippedAuto;
+ }
+
+ if (Usage & D3DUSAGE_DYNAMIC)
+ {
+ // GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME
+ }
+
+ if (Usage & D3DUSAGE_TEXTURE_SRGB)
+ {
+ key.m_texFlags |= kGLMTexSRGB;
+ }
+
+ if (Usage & D3DUSAGE_RENDERTARGET)
+ {
+ Assert( !(Usage & D3DUSAGE_DEPTHSTENCIL) );
+
+ key.m_texFlags |= kGLMTexRenderable;
+ key.m_texFlags |= kGLMTexSRGB; // this catches callers of CreateTexture who set the "renderable" option - they get an SRGB tex
+
+ if (m_ctx->Caps().m_cantAttachSRGB)
+ {
+ // this config can't support SRGB render targets. quietly turn off the sRGB bit.
+ key.m_texFlags &= ~kGLMTexSRGB;
+ }
+ }
+
+ key.m_xSize = Width;
+ key.m_ySize = Height;
+ key.m_zSize = 1;
+
+ CGLMTex *tex = m_ctx->NewTex( &key, debugLabel );
+ if (!tex)
+ {
+ GLMDebugger();
+ }
+ dxtex->m_tex = tex;
+
+ dxtex->m_srgbFlipCount = 0;
+
+ dxtex->m_surfZero = new IDirect3DSurface9;
+ dxtex->m_surfZero->m_restype = (D3DRESOURCETYPE)0; // this is a ref to a tex, not the owner...
+
+ // do not do an AddRef here.
+
+ dxtex->m_surfZero->m_device = this;
+
+ dxtex->m_surfZero->m_desc = dxtex->m_descZero;
+ dxtex->m_surfZero->m_tex = tex;
+ dxtex->m_surfZero->m_face = 0;
+ dxtex->m_surfZero->m_mip = 0;
+
+ GLMPRINTF(("-A- IDirect3DDevice9::CreateTexture created '%s' @ %08x (GLM %08x) %s",tex->m_layout->m_layoutSummary, dxtex, tex, debugLabel ? debugLabel : "" ));
+
+ *ppTexture = dxtex;
+
+ GLMPRINTF(("<-A-IDirect3DDevice9::CreateTexture"));
+ return S_OK;
+}
+
+
+IDirect3DTexture9::~IDirect3DTexture9()
+{
+ GLMPRINTF(( ">-A- IDirect3DTexture9" ));
+
+ // IDirect3DBaseTexture9::~IDirect3DBaseTexture9 frees up m_tex
+ // we take care of surfZero
+
+ if (m_device)
+ {
+ m_device->ReleasedTexture( this );
+
+ if (m_surfZero)
+ {
+ ULONG refc = m_surfZero->Release( 0, "~IDirect3DTexture9 public release (surfZero)" );
+ Assert( !refc );
+ m_surfZero = NULL;
+ }
+ // leave m_device alone!
+ }
+
+ GLMPRINTF(( "<-A- IDirect3DTexture9" ));
+}
+
+HRESULT IDirect3DTexture9::LockRect(UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags)
+{
+ // basically same code as in direct3dsurface9::lockrect
+
+ GLMTexLockParams lockreq;
+ memset( &lockreq, 0, sizeof(lockreq) );
+
+ lockreq.m_tex = this->m_tex;
+ lockreq.m_face = 0; //2D texture, no faces
+ lockreq.m_mip = Level;
+
+ // pRect can be NULL in which case, default to full size of slice
+ lockreq.m_region.xmin = pRect? pRect->left : 0;
+ lockreq.m_region.ymin = pRect ? pRect->top : 0;
+ lockreq.m_region.zmin = 0;
+ lockreq.m_region.xmax = pRect ? pRect->right : m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ].m_xSize;
+ lockreq.m_region.ymax = pRect ? pRect->bottom : m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ].m_ySize;
+ lockreq.m_region.zmax = 1;
+
+ if ((Flags & (D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK)) == (D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK) )
+ {
+ // smells like readback, force texel readout
+ lockreq.m_readback = true;
+ }
+
+ char *lockAddress;
+ int yStride;
+ int zStride;
+
+ lockreq.m_tex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
+
+ pLockedRect->Pitch = yStride;
+ pLockedRect->pBits = lockAddress;
+
+ return S_OK;
+}
+
+HRESULT IDirect3DTexture9::UnlockRect(UINT Level)
+{
+ GLMTexLockParams lockreq;
+ memset( &lockreq, 0, sizeof(lockreq) );
+
+ lockreq.m_tex = this->m_tex;
+ lockreq.m_face = 0; //2D texture, no faces
+ lockreq.m_mip = Level;
+
+ lockreq.m_tex->Unlock( &lockreq );
+
+ return S_OK;
+}
+
+HRESULT IDirect3DTexture9::GetSurfaceLevel(UINT Level,IDirect3DSurface9** ppSurfaceLevel)
+{
+ // we create and pass back a surface, and the client is on the hook to release it. tidy.
+
+ IDirect3DSurface9 *surf = new IDirect3DSurface9;
+ surf->m_restype = (D3DRESOURCETYPE)0; // 0 is special and means this 'surface' does not own its m_tex
+
+ // Dicey...higher level code seems to want this and not want this. Are we missing some AddRef/Release behavior elsewhere?
+ // trying to turn this off - experimental - 26Oct2010 surf->AddRef();
+
+ surf->m_device = this->m_device;
+
+ GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ];
+
+ surf->m_desc = m_descZero;
+ surf->m_desc.Width = slice->m_xSize;
+ surf->m_desc.Height = slice->m_ySize;
+
+ surf->m_tex = m_tex;
+ surf->m_face = 0;
+ surf->m_mip = Level;
+
+ *ppSurfaceLevel = surf;
+
+ return S_OK;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- IDirect3DCubeTexture9
+
+HRESULT IDirect3DDevice9::CreateCubeTexture(UINT EdgeLength,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DCubeTexture9** ppCubeTexture,VD3DHANDLE* pSharedHandle, char *debugLabel)
+{
+ GLMPRINTF((">-A- IDirect3DDevice9::CreateCubeTexture"));
+
+ IDirect3DCubeTexture9 *dxtex = new IDirect3DCubeTexture9;
+ dxtex->m_restype = D3DRTYPE_CUBETEXTURE;
+
+ dxtex->m_device = this;
+
+ dxtex->m_descZero.Format = Format;
+ dxtex->m_descZero.Type = D3DRTYPE_CUBETEXTURE;
+ dxtex->m_descZero.Usage = Usage;
+ dxtex->m_descZero.Pool = Pool;
+
+ dxtex->m_descZero.MultiSampleType = D3DMULTISAMPLE_NONE;
+ dxtex->m_descZero.MultiSampleQuality = 0;
+ dxtex->m_descZero.Width = EdgeLength;
+ dxtex->m_descZero.Height = EdgeLength;
+
+ GLMTexLayoutKey key;
+ memset( &key, 0, sizeof(key) );
+
+ key.m_texGLTarget = GL_TEXTURE_CUBE_MAP;
+ key.m_texFormat = Format;
+
+ if (Levels>1)
+ {
+ key.m_texFlags |= kGLMTexMipped;
+ }
+
+ // http://msdn.microsoft.com/en-us/library/bb172625(VS.85).aspx
+ // complain if any usage bits come down that I don't know.
+ uint knownUsageBits = (D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC | D3DUSAGE_TEXTURE_SRGB);
+ if ( (Usage & knownUsageBits) != Usage )
+ {
+ GLMDebugger();
+ }
+
+ if (Usage & D3DUSAGE_AUTOGENMIPMAP)
+ {
+ key.m_texFlags |= kGLMTexMipped | kGLMTexMippedAuto;
+ }
+
+ if (Usage & D3DUSAGE_RENDERTARGET)
+ {
+ key.m_texFlags |= kGLMTexRenderable;
+ }
+
+ if (Usage & D3DUSAGE_DYNAMIC)
+ {
+ //GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME
+ }
+
+ if (Usage & D3DUSAGE_TEXTURE_SRGB)
+ {
+ key.m_texFlags |= kGLMTexSRGB;
+ }
+
+ key.m_xSize = EdgeLength;
+ key.m_ySize = EdgeLength;
+ key.m_zSize = 1;
+
+ CGLMTex *tex = m_ctx->NewTex( &key, debugLabel );
+ if (!tex)
+ {
+ GLMDebugger();
+ }
+ dxtex->m_tex = tex;
+
+ dxtex->m_srgbFlipCount = 0;
+
+ for( int face = 0; face < 6; face ++)
+ {
+ dxtex->m_surfZero[face] = new IDirect3DSurface9;
+ dxtex->m_surfZero[face]->m_restype = (D3DRESOURCETYPE)0; // 0 is special and means this 'surface' does not own its m_tex
+ // do not do an AddRef here.
+
+ dxtex->m_surfZero[face]->m_device = this;
+
+ dxtex->m_surfZero[face]->m_desc = dxtex->m_descZero;
+ dxtex->m_surfZero[face]->m_tex = tex;
+ dxtex->m_surfZero[face]->m_face = face;
+ dxtex->m_surfZero[face]->m_mip = 0;
+ }
+
+ GLMPRINTF(("-A- IDirect3DDevice9::CreateCubeTexture created '%s' @ %08x (GLM %08x)",tex->m_layout->m_layoutSummary, dxtex, tex ));
+
+ *ppCubeTexture = dxtex;
+
+ GLMPRINTF(("<-A- IDirect3DDevice9::CreateCubeTexture"));
+
+ return S_OK;
+}
+
+IDirect3DCubeTexture9::~IDirect3DCubeTexture9()
+{
+ GLMPRINTF(( ">-A- ~IDirect3DCubeTexture9" ));
+
+ if (m_device)
+ {
+ GLMPRINTF(( "-A- ~IDirect3DCubeTexture9 taking normal delete path on %08x, device is %08x, surfzero[0] is %08x ", this, m_device, m_surfZero[0] ));
+ m_device->ReleasedTexture( this );
+
+ // let IDirect3DBaseTexture9::~IDirect3DBaseTexture9 free up m_tex
+ // we handle the surfZero array for the faces
+
+ for( int face = 0; face < 6; face ++)
+ {
+ if (m_surfZero[face])
+ {
+ Assert( m_surfZero[face]->m_device = m_device );
+ ULONG refc = m_surfZero[face]->Release( 0, "~IDirect3DCubeTexture9 public release (surfZero)");
+ if ( refc!=0 )
+ {
+ GLMPRINTF(( "-A- ~IDirect3DCubeTexture9 seeing non zero refcount on surfzero[%d] => %d ", face, refc ));
+ }
+ m_surfZero[face] = NULL;
+ }
+ }
+ // leave m_device alone!
+ }
+ else
+ {
+ GLMPRINTF(( "-A- ~IDirect3DCubeTexture9 taking strange delete path on %08x, device is %08x, surfzero[0] is %08x ", this, m_device, m_surfZero[0] ));
+ }
+
+ GLMPRINTF(( "<-A- ~IDirect3DCubeTexture9" ));
+}
+
+HRESULT IDirect3DCubeTexture9::GetCubeMapSurface(D3DCUBEMAP_FACES FaceType,UINT Level,IDirect3DSurface9** ppCubeMapSurface)
+{
+ // we create and pass back a surface, and the client is on the hook to release it...
+
+ IDirect3DSurface9 *surf = new IDirect3DSurface9;
+ surf->m_restype = (D3DRESOURCETYPE)0; // 0 is special and means this 'surface' does not own its m_tex
+
+ GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( FaceType, Level ) ];
+
+ surf->m_device = this->m_device;
+
+ surf->m_desc = m_descZero;
+ surf->m_desc.Width = slice->m_xSize;
+ surf->m_desc.Height = slice->m_ySize;
+
+ surf->m_tex = m_tex;
+ surf->m_face = FaceType;
+ surf->m_mip = Level;
+
+ *ppCubeMapSurface = surf;
+
+ return S_OK;
+}
+
+HRESULT IDirect3DCubeTexture9::GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc)
+{
+ Assert (Level < m_tex->m_layout->m_mipCount);
+
+ D3DSURFACE_DESC result = m_descZero;
+ // then mutate it for the level of interest
+
+ GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ];
+
+ result.Width = slice->m_xSize;
+ result.Height = slice->m_ySize;
+
+ *pDesc = result;
+
+ return S_OK;
+}
+
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- IDirect3DVolumeTexture9
+
+HRESULT IDirect3DDevice9::CreateVolumeTexture(UINT Width,UINT Height,UINT Depth,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DVolumeTexture9** ppVolumeTexture,VD3DHANDLE* pSharedHandle, char *debugLabel)
+{
+ GLMPRINTF((">-A- IDirect3DDevice9::CreateVolumeTexture"));
+ // set dxtex->m_restype to D3DRTYPE_VOLUMETEXTURE...
+
+ IDirect3DVolumeTexture9 *dxtex = new IDirect3DVolumeTexture9;
+ dxtex->m_restype = D3DRTYPE_VOLUMETEXTURE;
+
+ dxtex->m_device = this;
+
+ dxtex->m_descZero.Format = Format;
+ dxtex->m_descZero.Type = D3DRTYPE_VOLUMETEXTURE;
+ dxtex->m_descZero.Usage = Usage;
+ dxtex->m_descZero.Pool = Pool;
+
+ dxtex->m_descZero.MultiSampleType = D3DMULTISAMPLE_NONE;
+ dxtex->m_descZero.MultiSampleQuality = 0;
+ dxtex->m_descZero.Width = Width;
+ dxtex->m_descZero.Height = Height;
+
+ // also a volume specific desc
+ dxtex->m_volDescZero.Format = Format;
+ dxtex->m_volDescZero.Type = D3DRTYPE_VOLUMETEXTURE;
+ dxtex->m_volDescZero.Usage = Usage;
+ dxtex->m_volDescZero.Pool = Pool;
+
+ dxtex->m_volDescZero.Width = Width;
+ dxtex->m_volDescZero.Height = Height;
+ dxtex->m_volDescZero.Depth = Depth;
+
+ GLMTexLayoutKey key;
+ memset( &key, 0, sizeof(key) );
+
+ key.m_texGLTarget = GL_TEXTURE_3D;
+ key.m_texFormat = Format;
+
+ if (Levels>1)
+ {
+ key.m_texFlags |= kGLMTexMipped;
+ }
+
+ // http://msdn.microsoft.com/en-us/library/bb172625(VS.85).aspx
+ // complain if any usage bits come down that I don't know.
+ uint knownUsageBits = (D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC | D3DUSAGE_TEXTURE_SRGB);
+ if ( (Usage & knownUsageBits) != Usage )
+ {
+ Debugger();
+ }
+
+ if (Usage & D3DUSAGE_AUTOGENMIPMAP)
+ {
+ key.m_texFlags |= kGLMTexMipped | kGLMTexMippedAuto;
+ }
+
+ if (Usage & D3DUSAGE_RENDERTARGET)
+ {
+ key.m_texFlags |= kGLMTexRenderable;
+ }
+
+ if (Usage & D3DUSAGE_DYNAMIC)
+ {
+ GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME
+ }
+
+ if (Usage & D3DUSAGE_TEXTURE_SRGB)
+ {
+ key.m_texFlags |= kGLMTexSRGB;
+ }
+
+ key.m_xSize = Width;
+ key.m_ySize = Height;
+ key.m_zSize = Depth;
+
+ CGLMTex *tex = m_ctx->NewTex( &key, debugLabel );
+ if (!tex)
+ {
+ Debugger();
+ }
+ dxtex->m_tex = tex;
+
+ dxtex->m_srgbFlipCount = 0;
+
+ dxtex->m_surfZero = new IDirect3DSurface9;
+ dxtex->m_surfZero->m_restype = (D3DRESOURCETYPE)0; // this is a ref to a tex, not the owner...
+ // do not do an AddRef here.
+
+ dxtex->m_surfZero->m_device = this;
+
+ dxtex->m_surfZero->m_desc = dxtex->m_descZero;
+ dxtex->m_surfZero->m_tex = tex;
+ dxtex->m_surfZero->m_face = 0;
+ dxtex->m_surfZero->m_mip = 0;
+
+ GLMPRINTF(("-A- IDirect3DDevice9::CreateVolumeTexture created '%s' @ %08x (GLM %08x)",tex->m_layout->m_layoutSummary, dxtex, tex ));
+
+ *ppVolumeTexture = dxtex;
+
+ GLMPRINTF(("<-A- IDirect3DDevice9::CreateVolumeTexture"));
+
+ return S_OK;
+}
+
+IDirect3DVolumeTexture9::~IDirect3DVolumeTexture9()
+{
+ GLMPRINTF((">-A- ~IDirect3DVolumeTexture9"));
+
+ if (m_device)
+ {
+ m_device->ReleasedTexture( this );
+
+ // let IDirect3DBaseTexture9::~IDirect3DBaseTexture9 free up m_tex
+ // we handle m_surfZero
+
+ if (m_surfZero)
+ {
+ ULONG refc = m_surfZero->Release( 0, "~IDirect3DVolumeTexture9 public release (surfZero)" );
+ Assert( !refc );
+ m_surfZero = NULL;
+ }
+ // leave m_device alone!
+ }
+
+ GLMPRINTF(("<-A- ~IDirect3DVolumeTexture9"));
+}
+
+HRESULT IDirect3DVolumeTexture9::LockBox(UINT Level,D3DLOCKED_BOX* pLockedVolume,CONST D3DBOX* pBox,DWORD Flags)
+{
+ GLMTexLockParams lockreq;
+ memset( &lockreq, 0, sizeof(lockreq) );
+
+ lockreq.m_tex = this->m_tex;
+ lockreq.m_face = 0;
+ lockreq.m_mip = Level;
+
+ lockreq.m_region.xmin = pBox->Left;
+ lockreq.m_region.ymin = pBox->Top;
+ lockreq.m_region.zmin = pBox->Front;
+ lockreq.m_region.xmax = pBox->Right;
+ lockreq.m_region.ymax = pBox->Bottom;
+ lockreq.m_region.zmax = pBox->Back;
+
+ char *lockAddress;
+ int yStride;
+ int zStride;
+
+ lockreq.m_tex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
+
+ pLockedVolume->RowPitch = yStride;
+ pLockedVolume->SlicePitch = yStride;
+ pLockedVolume->pBits = lockAddress;
+
+ return S_OK;
+}
+
+HRESULT IDirect3DVolumeTexture9::UnlockBox(UINT Level)
+{
+ GLMTexLockParams lockreq;
+ memset( &lockreq, 0, sizeof(lockreq) );
+
+ lockreq.m_tex = this->m_tex;
+ lockreq.m_face = 0;
+ lockreq.m_mip = Level;
+
+ this->m_tex->Unlock( &lockreq );
+
+ return S_OK;
+}
+
+HRESULT IDirect3DVolumeTexture9::GetLevelDesc( UINT Level, D3DVOLUME_DESC *pDesc )
+{
+ if (Level > m_tex->m_layout->m_mipCount)
+ {
+ Debugger();
+ }
+
+ D3DVOLUME_DESC result = m_volDescZero;
+ // then mutate it for the level of interest
+
+ GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ];
+
+ result.Width = slice->m_xSize;
+ result.Height = slice->m_ySize;
+ result.Depth = slice->m_zSize;
+
+ *pDesc = result;
+
+ return S_OK;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- IDirect3DSurface9
+
+IDirect3DSurface9::~IDirect3DSurface9()
+{
+ // not much to do here, but good to verify that these things are being freed (and they are)
+ //GLMPRINTF(("-A- ~IDirect3DSurface9 - signpost"));
+
+ if (m_device)
+ {
+ GLMPRINTF(("-A- ~IDirect3DSurface9 - taking real delete path on %08x device %08x", this, m_device));
+ m_device->ReleasedSurface( this );
+
+ memset( &m_desc, 0, sizeof(m_desc) );
+
+ if (m_restype != 0) // signal that we are a surface that owns this tex (render target)
+ {
+ if (m_tex)
+ {
+ GLMPRINTF(("-A- ~IDirect3DSurface9 deleted '%s' @ %08x (GLM %08x) %s",m_tex->m_layout->m_layoutSummary, this, m_tex, m_tex->m_debugLabel ? m_tex->m_debugLabel : "" ));
+
+ m_tex->m_ctx->DelTex( m_tex );
+ m_tex = NULL;
+ }
+ else
+ {
+ GLMPRINTF(( "-A- ~IDirect3DSurface9 : whoops, no tex to delete here ?" ));
+ }
+ }
+ else
+ {
+ m_tex = NULL; // we are just a view on the tex, we don't own the tex, do not delete it
+ }
+
+ m_face = m_mip = 0;
+
+ m_device = NULL;
+ }
+ else
+ {
+ GLMPRINTF(("-A- ~IDirect3DSurface9 - taking strange delete path on %08x device %08x", this, m_device));
+ }
+}
+
+HRESULT IDirect3DSurface9::LockRect(D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags)
+{
+ GLMTexLockParams lockreq;
+ memset( &lockreq, 0, sizeof(lockreq) );
+
+ lockreq.m_tex = this->m_tex;
+ lockreq.m_face = this->m_face;
+ lockreq.m_mip = this->m_mip;
+
+ lockreq.m_region.xmin = pRect->left;
+ lockreq.m_region.ymin = pRect->top;
+ lockreq.m_region.zmin = 0;
+ lockreq.m_region.xmax = pRect->right;
+ lockreq.m_region.ymax = pRect->bottom;
+ lockreq.m_region.zmax = 1;
+
+ if ((Flags & (D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK)) == (D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK) )
+ {
+ // smells like readback, force texel readout
+ lockreq.m_readback = true;
+ }
+
+ char *lockAddress;
+ int yStride;
+ int zStride;
+
+ lockreq.m_tex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
+
+ pLockedRect->Pitch = yStride;
+ pLockedRect->pBits = lockAddress;
+
+ return S_OK;
+}
+
+HRESULT IDirect3DSurface9::UnlockRect()
+{
+ GLMTexLockParams lockreq;
+ memset( &lockreq, 0, sizeof(lockreq) );
+
+ lockreq.m_tex = this->m_tex;
+ lockreq.m_face = this->m_face;
+ lockreq.m_mip = this->m_mip;
+
+ lockreq.m_tex->Unlock( &lockreq );
+
+ return S_OK;
+}
+
+HRESULT IDirect3DSurface9::GetDesc(D3DSURFACE_DESC *pDesc)
+{
+ *pDesc = m_desc;
+ return S_OK;
+}
+
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+
+#pragma mark ----- IDirect3D9 -------------------------------------------------------
+
+IDirect3D9::~IDirect3D9()
+{
+ GLMPRINTF(("-A- ~IDirect3D9 - signpost"));
+}
+
+UINT IDirect3D9::GetAdapterCount()
+{
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+ GLMgr::NewGLMgr(); // init GL manager
+
+ GLMDisplayDB *db = g_engine->GetDisplayDB();
+ int dxAdapterCount = db->GetFakeAdapterCount();
+
+ return dxAdapterCount;
+#else
+ Debugger();
+ return 0;
+#endif
+}
+
+HRESULT IDirect3D9::GetDeviceCaps(UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps)
+{
+ // Generally called from "CShaderDeviceMgrDx8::ComputeCapsFromD3D" in ShaderDeviceDX8.cpp
+
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+ // "Adapter" is used to index amongst the set of fake-adapters maintained in the display DB
+ GLMDisplayDB *db = g_engine->GetDisplayDB();
+ int glmRendererIndex = -1;
+ int glmDisplayIndex = -1;
+
+ GLMRendererInfoFields glmRendererInfo;
+ GLMDisplayInfoFields glmDisplayInfo;
+
+ bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo );
+ Assert (!result);
+ // just leave glmRendererInfo filled out for subsequent code to look at as needed.
+
+ // fill in the pCaps record for adapter... we zero most of it and just fill in the fields that we think the caller wants.
+ V_memset( pCaps, 0, sizeof(*pCaps) );
+
+
+ /* Device Info */
+ pCaps->DeviceType = D3DDEVTYPE_HAL;
+
+ /* Caps from DX7 Draw */
+ pCaps->Caps = 0; // does anyone look at this ?
+
+ pCaps->Caps2 = D3DCAPS2_DYNAMICTEXTURES;
+ /* Cursor Caps */
+ pCaps->CursorCaps = 0; // nobody looks at this
+
+ /* 3D Device Caps */
+ pCaps->DevCaps = D3DDEVCAPS_HWTRANSFORMANDLIGHT;
+
+ pCaps->TextureCaps = D3DPTEXTURECAPS_CUBEMAP | D3DPTEXTURECAPS_MIPCUBEMAP | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PROJECTED;
+ // D3DPTEXTURECAPS_NOPROJECTEDBUMPENV ?
+ // D3DPTEXTURECAPS_POW2 ?
+ // caller looks at POT support like this:
+ // pCaps->m_SupportsNonPow2Textures =
+ // ( !( caps.TextureCaps & D3DPTEXTURECAPS_POW2 ) ||
+ // ( caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL ) );
+ // so we should set D3DPTEXTURECAPS_NONPOW2CONDITIONAL bit ?
+
+
+ pCaps->PrimitiveMiscCaps = 0; //only the HDR setup looks at this for D3DPMISCCAPS_SEPARATEALPHABLEND.
+ // ? D3DPMISCCAPS_SEPARATEALPHABLEND
+ // ? D3DPMISCCAPS_BLENDOP
+ // ? D3DPMISCCAPS_CLIPPLANESCALEDPOINTS
+ // ? D3DPMISCCAPS_CLIPTLVERTS D3DPMISCCAPS_COLORWRITEENABLE D3DPMISCCAPS_MASKZ D3DPMISCCAPS_TSSARGTEMP
+
+
+ pCaps->RasterCaps = D3DPRASTERCAPS_SCISSORTEST
+ | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS // ref'd in CShaderDeviceMgrDx8::ComputeCapsFromD3D
+ | D3DPRASTERCAPS_DEPTHBIAS // ref'd in CShaderDeviceMgrDx8::ComputeCapsFromD3D
+ ;
+
+ pCaps->TextureFilterCaps = D3DPTFILTERCAPS_MINFANISOTROPIC | D3DPTFILTERCAPS_MAGFANISOTROPIC;
+
+ pCaps->MaxTextureWidth = 4096;
+ pCaps->MaxTextureHeight = 4096;
+ pCaps->MaxVolumeExtent = 1024; //guesses
+
+ pCaps->MaxTextureAspectRatio = 0; // imply no limit on AR
+
+ pCaps->MaxAnisotropy = 8; //guess
+
+ pCaps->TextureOpCaps = D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_MODULATE2X; //guess
+ DWORD MaxTextureBlendStages;
+ DWORD MaxSimultaneousTextures;
+
+ pCaps->VertexProcessingCaps = D3DVTXPCAPS_TEXGEN_SPHEREMAP;
+
+ pCaps->MaxActiveLights = 8; // guess
+
+
+ // MaxUserClipPlanes. A bit complicated..
+ // it's difficult to make this fluid without teaching the engine about a cap that could change during run.
+
+ // start it out set to '2'.
+ // turn it off, if we're in GLSL mode but do not have native clip plane capability.
+ pCaps->MaxUserClipPlanes = 2; // assume good news
+
+ // is user asking for it to be off ?
+ if ( 0 /* CommandLine()->CheckParm( "-nouserclip" ) */ )
+ {
+ pCaps->MaxUserClipPlanes = 0;
+ }
+
+ g_bUseControlFlow = false; //CommandLine()->CheckParm( "-glslcontrolflow" );
+
+ // are we ARB mode and not forcing GLSL control flow mode?
+ if ( 0 /* CommandLine()->CheckParm( "-arbmode" ) && !g_bUseControlFlow */ )
+ {
+ pCaps->MaxUserClipPlanes = 0;
+ }
+
+
+ pCaps->MaxVertexBlendMatrices = 0; // see if anyone cares
+ pCaps->MaxVertexBlendMatrixIndex = 0; // see if anyone cares
+
+ pCaps->MaxPrimitiveCount = 32768; // guess
+ pCaps->MaxStreams = 4; // guess
+
+ pCaps->VertexShaderVersion = 0x200; // model 2.0
+ pCaps->MaxVertexShaderConst = DXABSTRACT_VS_PARAM_SLOTS; // number of vertex shader constant registers
+
+ pCaps->PixelShaderVersion = 0x200; // model 2.0
+
+ // Here are the DX9 specific ones
+ pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET;
+
+ pCaps->PS20Caps.NumInstructionSlots = 512; // guess
+ // only examined once:
+ // pCaps->m_SupportsPixelShaders_2_b = ( ( caps.PixelShaderVersion & 0xffff ) >= 0x0200) && (caps.PS20Caps.NumInstructionSlots >= 512);
+ //pCaps->m_SupportsPixelShaders_2_b = 1;
+
+ pCaps->NumSimultaneousRTs = 1; // Will be at least 1
+ pCaps->MaxVertexShader30InstructionSlots = 0;
+ pCaps->MaxPixelShader30InstructionSlots = 0;
+
+ #if POSIX
+ pCaps->FakeSRGBWrite = !glmRendererInfo.m_hasGammaWrites;
+ pCaps->CanDoSRGBReadFromRTs = !glmRendererInfo.m_cantAttachSRGB;
+ pCaps->MixedSizeTargets = glmRendererInfo.m_hasMixedAttachmentSizes;
+ #endif
+
+#endif
+
+ return S_OK;
+}
+
+HRESULT IDirect3D9::GetAdapterIdentifier( UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier )
+{
+ // Generally called from "CShaderDeviceMgrDx8::ComputeCapsFromD3D" in ShaderDeviceDX8.cpp
+
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+
+ Assert( Flags == D3DENUM_WHQL_LEVEL ); // we're not handling any other queries than this yet
+
+ V_memset( pIdentifier, 0, sizeof(*pIdentifier) );
+
+ GLMDisplayDB *db = g_engine->GetDisplayDB();
+ int glmRendererIndex = -1;
+ int glmDisplayIndex = -1;
+
+ GLMRendererInfoFields glmRendererInfo;
+ GLMDisplayInfoFields glmDisplayInfo;
+
+ // the D3D "Adapter" number feeds the fake adapter index
+ bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo );
+ Assert (!result);
+
+ sprintf( pIdentifier->Driver, "OpenGL %s (%08x)",
+ GLMDecode( eGL_RENDERER, glmRendererInfo.m_rendererID & 0x00FFFF00 ),
+ glmRendererInfo.m_rendererID
+ );
+
+ sprintf( pIdentifier->Description, "%s - %dx%d - %dMB VRAM",
+ GLMDecode( eGL_RENDERER, glmRendererInfo.m_rendererID & 0x00FFFF00 ),
+ glmDisplayInfo.m_displayPixelWidth, glmDisplayInfo.m_displayPixelHeight,
+ glmRendererInfo.m_vidMemory >> 20 );
+
+ pIdentifier->VendorId = glmRendererInfo.m_pciVendorID; // 4318;
+ pIdentifier->DeviceId = glmRendererInfo.m_pciDeviceID; // 401;
+ pIdentifier->SubSysId = 0; // 3358668866;
+ pIdentifier->Revision = 0; // 162;
+ pIdentifier->VideoMemory = glmRendererInfo.m_vidMemory; // amount of video memory in bytes
+
+ #if 0
+ // this came from the shaderapigl effort
+ V_strncpy( pIdentifier->Driver, "Fake-Video-Card", MAX_DEVICE_IDENTIFIER_STRING );
+ V_strncpy( pIdentifier->Description, "Fake-Video-Card", MAX_DEVICE_IDENTIFIER_STRING );
+ pIdentifier->VendorId = 4318;
+ pIdentifier->DeviceId = 401;
+ pIdentifier->SubSysId = 3358668866;
+ pIdentifier->Revision = 162;
+ #endif
+
+ return S_OK;
+#else
+ Debugger();
+ return D3DERR_INVALIDCALL;
+#endif
+
+}
+
+HRESULT IDirect3D9::CheckDeviceFormat(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat)
+{
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+
+ if (0) // hush for now, less spew
+ {
+ GLMPRINTF(("-X- ** IDirect3D9::CheckDeviceFormat: \n -- Adapter=%d || DeviceType=%4x:%s || AdapterFormat=%8x:%s\n -- RType %8x: %s\n -- CheckFormat %8x: %s\n -- Usage %8x: %s",
+ Adapter,
+ DeviceType, GLMDecode(eD3D_DEVTYPE, DeviceType),
+ AdapterFormat, GLMDecode(eD3D_FORMAT, AdapterFormat),
+ RType, GLMDecode(eD3D_RTYPE, RType),
+ CheckFormat, GLMDecode(eD3D_FORMAT, CheckFormat),
+ Usage, GLMDecodeMask( eD3D_USAGE, Usage ) ));
+ }
+
+ HRESULT result = D3DERR_NOTAVAILABLE; // failure
+
+ DWORD knownUsageMask = D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP
+ | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING
+ | D3DUSAGE_QUERY_VERTEXTEXTURE;
+
+ // FramebufferSRGB stuff.
+ // basically a format is only allowed to have SRGB usage for writing, if you have the framebuffer SRGB extension.
+ // so, check for that capability with GLM adapter db, and if it's not there, don't mark that bit as usable in any of our formats.
+ GLMDisplayDB *db = g_engine->GetDisplayDB();
+ int glmRendererIndex = -1;
+ int glmDisplayIndex = -1;
+
+ GLMRendererInfoFields glmRendererInfo;
+ GLMDisplayInfoFields glmDisplayInfo;
+
+ bool dbresult = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo );
+ Assert (!dbresult);
+
+ Assert ((Usage & knownUsageMask) == Usage);
+
+ DWORD legalUsage = 0;
+ switch( AdapterFormat )
+ {
+ case D3DFMT_X8R8G8B8:
+ switch( RType )
+ {
+ case D3DRTYPE_TEXTURE:
+ switch( CheckFormat )
+ {
+ case D3DFMT_DXT1:
+ case D3DFMT_DXT3:
+ case D3DFMT_DXT5:
+ legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ legalUsage |= D3DUSAGE_QUERY_SRGBREAD;
+
+ //open question: is auto gen of mipmaps is allowed or attempted on any DXT textures.
+ break;
+
+ case D3DFMT_A8R8G8B8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ legalUsage |= D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
+ break;
+
+ case D3DFMT_R32F: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ legalUsage |= D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
+ break;
+
+ case D3DFMT_A16B16G16R16:
+ legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ legalUsage |= D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
+ break;
+
+ case D3DFMT_A16B16G16R16F: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE;
+
+ if ( !glmRendererInfo.m_atiR5xx )
+ {
+ legalUsage |= D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
+ }
+ break;
+
+ case D3DFMT_A32B32G32R32F: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE;
+
+ if ( !glmRendererInfo.m_atiR5xx && !glmRendererInfo.m_nvG7x )
+ {
+ legalUsage |= D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
+ }
+ break;
+
+ case D3DFMT_R5G6B5: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ break;
+
+ //-----------------------------------------------------------
+ // these come in from TestTextureFormat in ColorFormatDX8.cpp which is being driven by InitializeColorInformation...
+ // which is going to try all 8 combinations of (vertex texturable / render targetable / filterable ) on every image format it knows.
+
+ case D3DFMT_R8G8B8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ legalUsage |= D3DUSAGE_QUERY_SRGBREAD;
+ break;
+
+ case D3DFMT_X8R8G8B8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ legalUsage |= D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE;
+ break;
+
+ // one and two channel textures... we'll have to fake these as four channel tex if we want to support them
+ case D3DFMT_L8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ break;
+
+ case D3DFMT_A8L8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ break;
+
+ case D3DFMT_A8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ break;
+
+ // going to need to go back and double check all of these..
+ case D3DFMT_X1R5G5B5: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ break;
+
+ case D3DFMT_A4R4G4B4: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ break;
+
+ case D3DFMT_A1R5G5B5: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ break;
+
+ case D3DFMT_V8U8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ break;
+
+ case D3DFMT_Q8W8V8U8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ // what the heck is QWVU8 ... ?
+ break;
+
+ case D3DFMT_X8L8V8U8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
+ // what the heck is XLVU8 ... ?
+ break;
+
+ // formats with depth...
+
+ case D3DFMT_D16: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
+ // just a guess on the legal usages
+ break;
+
+ case D3DFMT_D24S8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
+ // just a guess on the legal usages
+ break;
+
+ // vendor formats... try marking these all invalid for now
+ case D3DFMT_NV_INTZ:
+ case D3DFMT_NV_RAWZ:
+ case D3DFMT_NV_NULL:
+ case D3DFMT_ATI_D16:
+ case D3DFMT_ATI_D24S8:
+ case D3DFMT_ATI_2N:
+ case D3DFMT_ATI_1N:
+ legalUsage = 0;
+ break;
+
+ //-----------------------------------------------------------
+
+ default:
+ Assert(!"Unknown check format");
+ result = D3DERR_NOTAVAILABLE;
+ break;
+ }
+
+ if ((Usage & legalUsage) == Usage)
+ {
+ result = S_OK;
+ }
+ else
+ {
+ DWORD unsatBits = Usage & (~legalUsage); // clear the bits of the req that were legal, leaving the illegal ones
+ GLMPRINTF(( "-X- --> NOT OK: flags %8x:%s", unsatBits,GLMDecodeMask( eD3D_USAGE, unsatBits ) ));
+ result = D3DERR_NOTAVAILABLE;
+ }
+ break;
+
+ case D3DRTYPE_SURFACE:
+ switch( CheckFormat )
+ {
+ case 0x434f5441:
+ case 0x41415353:
+ result = D3DERR_NOTAVAILABLE;
+ break;
+
+ case D3DFMT_D24S8:
+ result = S_OK;
+ break;
+ //** IDirect3D9::CheckDeviceFormat adapter=0, DeviceType= 1:D3DDEVTYPE_HAL, AdapterFormat= 5:D3DFMT_X8R8G8B8, RType= 1:D3DRTYPE_SURFACE, CheckFormat=434f5441:UNKNOWN
+ //** IDirect3D9::CheckDeviceFormat adapter=0, DeviceType= 1:D3DDEVTYPE_HAL, AdapterFormat= 5:D3DFMT_X8R8G8B8, RType= 1:D3DRTYPE_SURFACE, CheckFormat=41415353:UNKNOWN
+ //** IDirect3D9::CheckDeviceFormat adapter=0, DeviceType= 1:D3DDEVTYPE_HAL, AdapterFormat= 5:D3DFMT_X8R8G8B8, RType= 1:D3DRTYPE_SURFACE, CheckFormat=434f5441:UNKNOWN
+ //** IDirect3D9::CheckDeviceFormat adapter=0, DeviceType= 1:D3DDEVTYPE_HAL, AdapterFormat= 5:D3DFMT_X8R8G8B8, RType= 1:D3DRTYPE_SURFACE, CheckFormat=41415353:UNKNOWN
+
+ default:
+ Assert(!"Unknown format");
+ result = D3DERR_NOTAVAILABLE;
+ break;
+ }
+ break;
+
+ default:
+ Assert(!"Unknown resource type");
+ result = D3DERR_NOTAVAILABLE;
+ break;
+ }
+ break;
+
+ default:
+ Assert(!"Unknown adapter format");
+ result = D3DERR_NOTAVAILABLE;
+ break;
+ }
+
+ return result;
+#else
+ Debugger();
+ return D3DERR_INVALIDCALL;
+#endif
+}
+
+UINT IDirect3D9::GetAdapterModeCount(UINT Adapter,D3DFORMAT Format)
+{
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+
+ GLMPRINTF(( "-X- IDirect3D9::GetAdapterModeCount: Adapter=%d || Format=%8x:%s", Adapter, Format, GLMDecode(eD3D_FORMAT, Format) ));
+
+ uint modeCount=0;
+
+ GLMDisplayDB *db = g_engine->GetDisplayDB();
+ int glmRendererIndex = -1;
+ int glmDisplayIndex = -1;
+
+ GLMRendererInfoFields glmRendererInfo;
+ GLMDisplayInfoFields glmDisplayInfo;
+
+ // the D3D "Adapter" number feeds the fake adapter index
+ bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo );
+ Assert (!result);
+
+ modeCount = db->GetModeCount( glmRendererIndex, glmDisplayIndex );
+ GLMPRINTF(( "-X- --> result is %d", modeCount ));
+
+ return modeCount;
+#else
+ Debugger();
+ return 0;
+#endif
+}
+
+HRESULT IDirect3D9::EnumAdapterModes(UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode)
+{
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+
+ GLMPRINTF(( "-X- IDirect3D9::EnumAdapterModes: Adapter=%d || Format=%8x:%s || Mode=%d", Adapter, Format, GLMDecode(eD3D_FORMAT, Format), Mode ));
+
+ Assert(Format==D3DFMT_X8R8G8B8);
+
+ GLMDisplayDB *db = g_engine->GetDisplayDB();
+
+ int glmRendererIndex = -1;
+ int glmDisplayIndex = -1;
+
+ GLMRendererInfoFields glmRendererInfo;
+ GLMDisplayInfoFields glmDisplayInfo;
+ GLMDisplayModeInfoFields glmModeInfo;
+
+ // the D3D "Adapter" number feeds the fake adapter index
+ bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo );
+ Assert (!result);
+ if (result) return D3DERR_NOTAVAILABLE;
+
+ bool result2 = db->GetModeInfo( glmRendererIndex, glmDisplayIndex, Mode, &glmModeInfo );
+ Assert( !result2 );
+ if (result2) return D3DERR_NOTAVAILABLE;
+
+ pMode->Width = glmModeInfo.m_modePixelWidth;
+ pMode->Height = glmModeInfo.m_modePixelHeight;
+ pMode->RefreshRate = glmModeInfo.m_modeRefreshHz; // "adapter default"
+ pMode->Format = Format; // whatever you asked for ?
+
+ GLMPRINTF(( "-X- IDirect3D9::EnumAdapterModes returning mode size (%d,%d) and D3DFMT_X8R8G8B8",pMode->Width,pMode->Height ));
+ return S_OK;
+#else
+ Debugger();
+ return D3DERR_INVALIDCALL;
+#endif
+}
+
+HRESULT IDirect3D9::CheckDeviceType(UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed)
+{
+ //FIXME: we just say "OK" on any query
+
+ GLMPRINTF(( "-X- IDirect3D9::CheckDeviceType: Adapter=%d || DevType=%d:%s || AdapterFormat=%d:%s || BackBufferFormat=%d:%s || bWindowed=%d",
+ Adapter,
+ DevType, GLMDecode(eD3D_DEVTYPE,DevType),
+ AdapterFormat, GLMDecode(eD3D_FORMAT, AdapterFormat),
+ BackBufferFormat, GLMDecode(eD3D_FORMAT, BackBufferFormat),
+ (int) bWindowed ));
+
+ return S_OK;
+}
+
+HRESULT IDirect3D9::GetAdapterDisplayMode(UINT Adapter,D3DDISPLAYMODE* pMode)
+{
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+
+ // asking what the current mode is
+ GLMPRINTF(("-X- IDirect3D9::GetAdapterDisplayMode: Adapter=%d", Adapter ));
+
+ GLMDisplayDB *db = g_engine->GetDisplayDB();
+
+ int glmRendererIndex = -1;
+ int glmDisplayIndex = -1;
+
+ GLMRendererInfoFields glmRendererInfo;
+ GLMDisplayInfoFields glmDisplayInfo;
+ GLMDisplayModeInfoFields glmModeInfo;
+
+ // the D3D "Adapter" number feeds the fake adapter index
+ bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo );
+ Assert(!result);
+ if (result) return D3DERR_INVALIDCALL;
+
+ int modeIndex = -1; // pass -1 as a mode index to find out about whatever the current mode is on the selected display
+
+ bool modeResult = db->GetModeInfo( glmRendererIndex, glmDisplayIndex, modeIndex, &glmModeInfo );
+ Assert (!modeResult);
+ if (modeResult) return D3DERR_INVALIDCALL;
+
+ pMode->Width = glmModeInfo.m_modePixelWidth;
+ pMode->Height = glmModeInfo.m_modePixelHeight;
+ pMode->RefreshRate = glmModeInfo.m_modeRefreshHz; // "adapter default"
+ pMode->Format = D3DFMT_X8R8G8B8; //FIXME, this is a SWAG
+
+ return S_OK;
+#else
+ Debugger();
+ return D3DERR_INVALIDCALL;
+#endif
+}
+
+HRESULT IDirect3D9::CheckDepthStencilMatch(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat)
+{
+ GLMPRINTF(("-X- IDirect3D9::CheckDepthStencilMatch: Adapter=%d || DevType=%d:%s || AdapterFormat=%d:%s || RenderTargetFormat=%d:%s || DepthStencilFormat=%d:%s",
+ Adapter,
+ DeviceType, GLMDecode(eD3D_DEVTYPE,DeviceType),
+ AdapterFormat, GLMDecode(eD3D_FORMAT, AdapterFormat),
+ RenderTargetFormat, GLMDecode(eD3D_FORMAT, RenderTargetFormat),
+ DepthStencilFormat, GLMDecode(eD3D_FORMAT, DepthStencilFormat) ));
+
+ // one known request looks like this:
+ // AdapterFormat=5:D3DFMT_X8R8G8B8 || RenderTargetFormat=3:D3DFMT_A8R8G8B8 || DepthStencilFormat=2:D3DFMT_D24S8
+
+ // return S_OK for that one combo, Debugger() on anything else
+ HRESULT result = D3DERR_NOTAVAILABLE; // failure
+
+ switch( AdapterFormat )
+ {
+ case D3DFMT_X8R8G8B8:
+ {
+ if ( (RenderTargetFormat == D3DFMT_A8R8G8B8) && (DepthStencilFormat == D3DFMT_D24S8) )
+ {
+ result = S_OK;
+ }
+ }
+ break;
+
+ default:
+ Assert(!"Unhandled format");
+ result = D3DERR_NOTAVAILABLE;
+ break;
+ }
+
+ Assert( result == S_OK );
+
+ return result;
+}
+
+HRESULT IDirect3D9::CheckDeviceMultiSampleType( UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels )
+{
+#if DX9MODE // can only make these calls if DX9MODE is on, if not, we won't get here
+
+ GLMDisplayDB *db = g_engine->GetDisplayDB();
+
+ int glmRendererIndex = -1;
+ int glmDisplayIndex = -1;
+
+ GLMRendererInfoFields glmRendererInfo;
+ GLMDisplayInfoFields glmDisplayInfo;
+ GLMDisplayModeInfoFields glmModeInfo;
+
+ // the D3D "Adapter" number feeds the fake adapter index
+ bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo );
+ Assert( !result );
+ if ( result )
+ return D3DERR_INVALIDCALL;
+
+
+ if ( 1 /* !CommandLine()->FindParm("-glmenabletrustmsaa") */ )
+ {
+ // These ghetto drivers don't get MSAA
+ if ( ( glmRendererInfo.m_nvG7x || glmRendererInfo.m_atiR5xx ) && ( MultiSampleType > D3DMULTISAMPLE_NONE ) )
+ {
+ if ( pQualityLevels )
+ {
+ *pQualityLevels = 0;
+ }
+ return D3DERR_NOTAVAILABLE;
+ }
+ }
+
+ switch ( MultiSampleType )
+ {
+ case D3DMULTISAMPLE_NONE: // always return true
+ if ( pQualityLevels )
+ {
+ *pQualityLevels = 1;
+ }
+ return S_OK;
+ break;
+
+ case D3DMULTISAMPLE_2_SAMPLES:
+ case D3DMULTISAMPLE_4_SAMPLES:
+ case D3DMULTISAMPLE_6_SAMPLES:
+ case D3DMULTISAMPLE_8_SAMPLES:
+ // note the fact that the d3d enums for 2, 4, 6, 8 samples are equal to 2,4,6,8...
+ if (glmRendererInfo.m_maxSamples >= (int)MultiSampleType )
+ {
+ if ( pQualityLevels )
+ {
+ *pQualityLevels = 1;
+ }
+ return S_OK;
+ }
+ else
+ {
+ return D3DERR_NOTAVAILABLE;
+ }
+ break;
+
+ default:
+ if ( pQualityLevels )
+ {
+ *pQualityLevels = 0;
+ }
+ return D3DERR_NOTAVAILABLE;
+ break;
+ }
+ return D3DERR_NOTAVAILABLE;
+#else
+ Debugger();
+ return D3DERR_NOTAVAILABLE;
+#endif
+
+}
+
+HRESULT IDirect3D9::CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,VD3DHWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface)
+{
+ // constrain these inputs for the time being
+ // BackBufferFormat -> A8R8G8B8
+ // BackBufferCount -> 1;
+ // MultiSampleType -> D3DMULTISAMPLE_NONE
+ // AutoDepthStencilFormat -> D3DFMT_D24S8
+
+ // NULL out the return pointer so if we exit early it is not set
+ *ppReturnedDeviceInterface = NULL;
+
+ // assume success unless something is sour
+ HRESULT result = S_OK;
+
+ // relax this check for now
+ //if (pPresentationParameters->BackBufferFormat != D3DFMT_A8R8G8B8)
+ //{
+ // Debugger();
+ // result = -1;
+ //}
+
+ //rbarris 24Aug10 - relaxing this check - we don't care if the game asks for two backbuffers, it's moot
+ //if ( pPresentationParameters->BackBufferCount != 1 )
+ //{
+ // Debugger();
+ // result = D3DERR_NOTAVAILABLE;
+ //}
+
+ if ( pPresentationParameters->AutoDepthStencilFormat != D3DFMT_D24S8 )
+ {
+ Debugger();
+ result = D3DERR_NOTAVAILABLE;
+ }
+
+ if ( result == S_OK )
+ {
+ // create an IDirect3DDevice9
+ // it will make a GLMContext and set up some drawables
+
+ IDirect3DDevice9Params devparams;
+ memset( &devparams, 0, sizeof(devparams) );
+
+ devparams.m_adapter = Adapter;
+ devparams.m_deviceType = DeviceType;
+ devparams.m_focusWindow = hFocusWindow; // is this meaningful? is this a WindowRef ? follow it up the chain..
+ devparams.m_behaviorFlags = BehaviorFlags;
+ devparams.m_presentationParameters = *pPresentationParameters;
+
+ IDirect3DDevice9 *dev = new IDirect3DDevice9;
+
+ result = dev->Create( &devparams );
+
+ if ( result == S_OK )
+ {
+ *ppReturnedDeviceInterface = dev;
+ }
+ }
+ return result;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- IDirect3DQuery9
+
+HRESULT IDirect3DQuery9::Issue(DWORD dwIssueFlags)
+{
+ // Flags field for Issue
+ // #define D3DISSUE_END (1 << 0) // Tells the runtime to issue the end of a query, changing it's state to "non-signaled".
+ // #define D3DISSUE_BEGIN (1 << 1) // Tells the runtime to issue the beginng of a query.
+
+ if (dwIssueFlags & D3DISSUE_BEGIN)
+ {
+ switch( m_type )
+ {
+ case D3DQUERYTYPE_OCCLUSION:
+ m_query->Start(); // drop "start counter" call into stream
+ break;
+
+ default:
+ Assert(!"Can't use D3DISSUE_BEGIN on this query");
+ break;
+ }
+ }
+
+ if (dwIssueFlags & D3DISSUE_END)
+ {
+ switch( m_type )
+ {
+ case D3DQUERYTYPE_OCCLUSION:
+ m_query->Stop(); // drop "end counter" call into stream
+ break;
+
+ case D3DQUERYTYPE_EVENT:
+ // End is very weird with respect to Events (fences).
+ // DX9 docs say to use End to put the fence in the stream. So we map End to GLM's Start.
+ // http://msdn.microsoft.com/en-us/library/ee422167(VS.85).aspx
+ m_query->Start(); // drop "set fence" into stream
+ break;
+
+ default:
+ break;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT IDirect3DQuery9::GetData(void* pData,DWORD dwSize,DWORD dwGetDataFlags)
+{
+ HRESULT result = -1;
+
+ // GetData is not always called with the flush bit.
+
+ // if an answer is not yet available - return S_FALSE.
+ // if an answer is available - return S_OK and write the answer into *pData.
+ bool done = false;
+ bool flush = (dwGetDataFlags & D3DGETDATA_FLUSH) != 0; // aka spin until done
+
+ // hmmm both of these paths are the same, maybe we could fold them up
+ if ( !m_query->IsStarted() )
+ {
+ Assert(!"Can't GetData before issue/start");
+ printf("\n** IDirect3DQuery9::GetData: can't GetData before issue/start");
+ result = -1;
+ }
+ else if ( !m_query->IsStopped() )
+ {
+ Assert(!"Can't GetData before issue-end/stop");
+ printf("\n** IDirect3DQuery9::GetData: can't GetData before issue-end/stop");
+ result = -1;
+ }
+ else
+ {
+ switch( m_type )
+ {
+ case D3DQUERYTYPE_OCCLUSION:
+ {
+ // expectation - caller already did an issue begin (start) and an issue end (stop).
+ // we can probe using IsDone.
+ if (flush && (!m_ctx->Caps().m_hasPerfPackage1) )
+ {
+ glFlush();
+ }
+ do
+ {
+ done = m_query->IsDone();
+ if (done)
+ {
+ uint oqValue = 0; // or we could just pass pData directly to Complete...
+ m_query->Complete(&oqValue);
+ if (pData)
+ {
+ *(uint*)pData = oqValue;
+ }
+ result = S_OK;
+ }
+ else
+ {
+ result = S_FALSE;
+ }
+ } while( flush && (!done) );
+ }
+ break;
+
+ case D3DQUERYTYPE_EVENT:
+ {
+ // expectation - caller already did an issue end (for fence => start) but has not done anything that would call Stop.
+ // that's ok because Stop is a no-op for fences.
+ if (flush && (!m_ctx->Caps().m_hasPerfPackage1) )
+ {
+ glFlush();
+ }
+
+ done = m_query->IsDone();
+ if (done)
+ {
+ m_query->Complete(NULL); // this will block on pre-SLGU
+ *(uint*)pData = 0;
+ result = S_OK;
+ }
+ else
+ {
+ result = S_FALSE;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return result;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- IDirect3DVertexBuffer9
+
+HRESULT IDirect3DDevice9::CreateVertexBuffer(UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,IDirect3DVertexBuffer9** ppVertexBuffer,VD3DHANDLE* pSharedHandle)
+{
+ GLMPRINTF(( ">-A- IDirect3DDevice9::CreateVertexBuffer" ));
+
+ IDirect3DVertexBuffer9 *newbuff = new IDirect3DVertexBuffer9;
+
+ newbuff->m_device = this;
+
+ newbuff->m_ctx = m_ctx;
+
+ // FIXME need to find home or use for the Usage, FVF, Pool values passed in
+ uint options = 0;
+
+ if (Usage&D3DUSAGE_DYNAMIC)
+ {
+ options |= GLMBufferOptionDynamic;
+ }
+
+ newbuff->m_vtxBuffer = m_ctx->NewBuffer( kGLMVertexBuffer, Length, options ) ;
+
+ newbuff->m_vtxDesc.Type = D3DRTYPE_VERTEXBUFFER;
+ newbuff->m_vtxDesc.Usage = Usage;
+ newbuff->m_vtxDesc.Pool = Pool;
+ newbuff->m_vtxDesc.Size = Length;
+
+ *ppVertexBuffer = newbuff;
+
+ GLMPRINTF(( "<-A- IDirect3DDevice9::CreateVertexBuffer" ));
+
+ return S_OK;
+}
+
+IDirect3DVertexBuffer9::~IDirect3DVertexBuffer9()
+{
+ GLMPRINTF(( ">-A- ~IDirect3DVertexBuffer9" ));
+
+ if (m_device)
+ {
+ m_device->ReleasedVertexBuffer( this );
+
+ if (m_ctx && m_vtxBuffer)
+ {
+ GLMPRINTF(( ">-A- ~IDirect3DVertexBuffer9 deleting m_vtxBuffer" ));
+ m_ctx->DelBuffer( m_vtxBuffer );
+ m_vtxBuffer = NULL;
+ GLMPRINTF(( "<-A- ~IDirect3DVertexBuffer9 deleting m_vtxBuffer - done" ));
+ }
+ m_device = NULL;
+ }
+
+ GLMPRINTF(( "<-A- ~IDirect3DVertexBuffer9" ));
+}
+
+HRESULT IDirect3DVertexBuffer9::Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags)
+{
+ // FIXME would be good to have "can't lock twice" logic
+
+ Assert( !(Flags & D3DLOCK_READONLY) ); // not impl'd
+// Assert( !(Flags & D3DLOCK_NOSYSLOCK) ); // not impl'd - it triggers though
+
+ GLMBuffLockParams lockreq;
+ lockreq.m_offset = OffsetToLock;
+ lockreq.m_size = SizeToLock;
+ lockreq.m_nonblocking = (Flags & D3DLOCK_NOOVERWRITE) != 0;
+ lockreq.m_discard = (Flags & D3DLOCK_DISCARD) != 0;
+
+ m_vtxBuffer->Lock( &lockreq, (char**)ppbData );
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Lock on D3D buf %p (GL name %d) offset %d, size %d => address %p", this, this->m_vtxBuffer->m_name, OffsetToLock, SizeToLock, *ppbData));
+ return S_OK;
+}
+
+HRESULT IDirect3DVertexBuffer9::Unlock()
+{
+ m_vtxBuffer->Unlock();
+ return S_OK;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+
+#pragma mark ----- IDirect3DIndexBuffer9
+
+HRESULT IDirect3DDevice9::CreateIndexBuffer(UINT Length,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DIndexBuffer9** ppIndexBuffer,VD3DHANDLE* pSharedHandle)
+{
+ GLMPRINTF(( ">-A- IDirect3DDevice9::CreateIndexBuffer" ));
+
+ // it is important to save all the create info, since GetDesc could get called later to query it
+
+ IDirect3DIndexBuffer9 *newbuff = new IDirect3DIndexBuffer9;
+
+ newbuff->m_device = this;
+
+ newbuff->m_restype = D3DRTYPE_INDEXBUFFER; // hmmmmmmm why are we not derived from d3dresource..
+
+ newbuff->m_ctx = m_ctx;
+
+ // FIXME need to find home or use for the Usage, Format, Pool values passed in
+ uint options = 0;
+
+ if (Usage&D3DUSAGE_DYNAMIC)
+ {
+ options |= GLMBufferOptionDynamic;
+ }
+
+ newbuff->m_idxBuffer = m_ctx->NewBuffer( kGLMIndexBuffer, Length, options ) ;
+
+ newbuff->m_idxDesc.Format = Format;
+ newbuff->m_idxDesc.Type = D3DRTYPE_INDEXBUFFER;
+ newbuff->m_idxDesc.Usage = Usage;
+ newbuff->m_idxDesc.Pool = Pool;
+ newbuff->m_idxDesc.Size = Length;
+
+ *ppIndexBuffer = newbuff;
+
+ GLMPRINTF(( "<-A- IDirect3DDevice9::CreateIndexBuffer" ));
+
+ return S_OK;
+}
+
+IDirect3DIndexBuffer9::~IDirect3DIndexBuffer9()
+{
+ GLMPRINTF(( ">-A- ~IDirect3DIndexBuffer9" ));
+
+ if (m_device)
+ {
+ m_device->ReleasedIndexBuffer( this );
+
+ if (m_ctx && m_idxBuffer)
+ {
+ GLMPRINTF(( ">-A- ~IDirect3DIndexBuffer9 deleting m_idxBuffer" ));
+ m_ctx->DelBuffer( m_idxBuffer );
+ GLMPRINTF(( "<-A- ~IDirect3DIndexBuffer9 deleting m_idxBuffer - done" ));
+ }
+ m_device = NULL;
+ }
+ else
+ {
+ }
+
+ GLMPRINTF(( "<-A- ~IDirect3DIndexBuffer9" ));
+}
+
+
+HRESULT IDirect3DIndexBuffer9::Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags)
+{
+ // FIXME would be good to have "can't lock twice" logic
+
+ GLMBuffLockParams lockreq;
+ lockreq.m_offset = OffsetToLock;
+ lockreq.m_size = SizeToLock;
+ lockreq.m_nonblocking = (Flags & D3DLOCK_NOOVERWRITE) != 0;
+ lockreq.m_discard = (Flags & D3DLOCK_DISCARD) != 0;
+
+ m_idxBuffer->Lock( &lockreq, (char**)ppbData );
+
+ return S_OK;
+}
+
+HRESULT IDirect3DIndexBuffer9::Unlock()
+{
+ m_idxBuffer->Unlock();
+
+ return S_OK;
+}
+
+HRESULT IDirect3DIndexBuffer9::GetDesc(D3DINDEXBUFFER_DESC *pDesc)
+{
+ *pDesc = m_idxDesc;
+ return S_OK;
+}
+
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+#pragma mark ----- IDirect3DDevice9 -------------------------------------------------
+
+void ConvertPresentationParamsToGLMDisplayParams( D3DPRESENT_PARAMETERS *d3dp, GLMDisplayParams *gldp )
+{
+ memset( gldp, 0, sizeof(*gldp) );
+
+ gldp->m_fsEnable = !d3dp->Windowed;
+
+ // see http://msdn.microsoft.com/en-us/library/ee416515(VS.85).aspx
+ // note that the values below are the only ones mentioned by Source engine; there are many others
+ switch(d3dp->PresentationInterval)
+ {
+ case D3DPRESENT_INTERVAL_ONE:
+ gldp->m_vsyncEnable = true; // "The driver will wait for the vertical retrace period (the runtime will beam-follow to prevent tearing)."
+ break;
+
+ case D3DPRESENT_INTERVAL_IMMEDIATE:
+ gldp->m_vsyncEnable = false; // "The runtime updates the window client area immediately and might do so more than once during the adapter refresh period."
+ break;
+
+ default:
+ gldp->m_vsyncEnable = true; // if I don't know it, you're getting vsync enabled.
+ break;
+ }
+
+ gldp->m_backBufferWidth = d3dp->BackBufferWidth;
+ gldp->m_backBufferHeight = d3dp->BackBufferHeight;
+ gldp->m_backBufferFormat = d3dp->BackBufferFormat;
+ gldp->m_multiSampleCount = d3dp->MultiSampleType; // it's a count really
+
+ gldp->m_enableAutoDepthStencil = d3dp->EnableAutoDepthStencil;
+ gldp->m_autoDepthStencilFormat = d3dp->AutoDepthStencilFormat;
+
+ gldp->m_fsRefreshHz = d3dp->FullScreen_RefreshRateInHz;
+
+ // some fields in d3d PB we're not acting on yet...
+ // UINT BackBufferCount;
+ // DWORD MultiSampleQuality;
+ // D3DSWAPEFFECT SwapEffect;
+ // VD3DHWND hDeviceWindow;
+ // DWORD Flags;
+}
+
+HRESULT IDirect3DDevice9::Create( IDirect3DDevice9Params *params )
+{
+#if DX9MODE
+
+ GLMPRINTF((">-X-IDirect3DDevice9::Create"));
+ HRESULT result = S_OK;
+
+ // create an IDirect3DDevice9
+ // make a GLMContext and set up some drawables
+ m_params = *params;
+
+ m_ctx = NULL;
+ m_drawableFBO = NULL;
+
+ memset( m_rtSurfaces, 0, sizeof(m_rtSurfaces) );
+ m_dsSurface = NULL;
+
+ m_defaultColorSurface = NULL;
+ m_defaultDepthStencilSurface = NULL;
+
+ memset( m_streams, 0, sizeof(m_streams) );
+ memset( m_textures, 0, sizeof(m_textures) );
+ memset( m_samplers, 0, sizeof(m_samplers) );
+
+
+ //============================================================================
+ // param block for GLM context create
+ GLMDisplayParams glmParams;
+ ConvertPresentationParamsToGLMDisplayParams( ¶ms->m_presentationParameters, &glmParams );
+
+ glmParams.m_mtgl = true; // forget this idea -> (params->m_behaviorFlags & D3DCREATE_MULTITHREADED) != 0;
+ // the call above fills in a bunch of things, but doesn't know about anything outside of the presentation params.
+ // those tend to be the things that do not change after create, so we do those here in Create.
+
+ glmParams.m_focusWindow = params->m_focusWindow;
+
+ #if 0 //FIXME-HACK
+ // map the D3D "adapter" to a renderer/display pair
+ // (that GPU will have to stay set as-is for any subsequent mode changes)
+
+ int glmRendererIndex = -1;
+ int glmDisplayIndex = -1;
+
+ GLMRendererInfoFields glmRendererInfo;
+ GLMDisplayInfoFields glmDisplayInfo;
+
+ // the D3D "Adapter" number feeds the fake adapter index
+ bool adaptResult = GLMgr::aGLMgr()->GetDisplayDB()->GetFakeAdapterInfo( params->m_adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo );
+ Assert(!adaptResult);
+
+ glmParams.m_rendererIndex = glmRendererIndex;
+ glmParams.m_displayIndex = glmDisplayIndex;
+ // glmParams.m_modeIndex hmmmmm, client doesn't give us a mode number, just a resolution..
+ #endif
+
+ m_ctx = GLMgr::aGLMgr()->NewContext( &glmParams );
+ if (!m_ctx)
+ {
+ GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)"));
+ return (HRESULT) -1;
+ }
+
+ // make an FBO to draw into and activate it.
+ m_drawableFBO = m_ctx->NewFBO();
+
+ m_ctx->SetDrawingFBO( m_drawableFBO );
+
+ // bind it to context. will receive attachments shortly.
+ m_ctx->BindFBOToCtx( m_drawableFBO, GL_READ_FRAMEBUFFER_EXT );
+ m_ctx->BindFBOToCtx( m_drawableFBO, GL_DRAW_FRAMEBUFFER_EXT );
+
+ // we create two IDirect3DSurface9's. These will be known as the internal render target 0 and the depthstencil.
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Create making color render target..."));
+ // color surface
+ result = this->CreateRenderTarget(
+ m_params.m_presentationParameters.BackBufferWidth, // width
+ m_params.m_presentationParameters.BackBufferHeight, // height
+ m_params.m_presentationParameters.BackBufferFormat, // format
+ m_params.m_presentationParameters.MultiSampleType, // MSAA depth
+ m_params.m_presentationParameters.MultiSampleQuality, // MSAA quality
+ true, // lockable
+ &m_defaultColorSurface, // ppSurface
+ NULL // shared handle
+ );
+
+ if (result != S_OK)
+ {
+ GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)"));
+ return result;
+ }
+ // do not do an AddRef..
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Create making color render target complete -> %08x", m_defaultColorSurface ));
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Create setting color render target..."));
+ result = this->SetRenderTarget(0, m_defaultColorSurface);
+ if (result != S_OK)
+ {
+ GLMPRINTF(("< IDirect3DDevice9::Create (error out)"));
+ return result;
+ }
+ GLMPRINTF(("-X- IDirect3DDevice9::Create setting color render target complete."));
+
+ Assert (m_params.m_presentationParameters.EnableAutoDepthStencil);
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Create making depth-stencil..."));
+ result = CreateDepthStencilSurface(
+ m_params.m_presentationParameters.BackBufferWidth, // width
+ m_params.m_presentationParameters.BackBufferHeight, // height
+ m_params.m_presentationParameters.AutoDepthStencilFormat, // format
+ m_params.m_presentationParameters.MultiSampleType, // MSAA depth
+ m_params.m_presentationParameters.MultiSampleQuality, // MSAA quality
+ TRUE, // enable z-buffer discard ????
+ &m_defaultDepthStencilSurface, // ppSurface
+ NULL // shared handle
+ );
+ if (result != S_OK)
+ {
+ GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)"));
+ return result;
+ }
+ // do not do an AddRef here..
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Create making depth-stencil complete -> %08x", m_defaultDepthStencilSurface));
+ GLMPRINTF(("-X- Direct3DDevice9::Create setting depth-stencil render target..."));
+ result = this->SetDepthStencilSurface(m_defaultDepthStencilSurface);
+ if (result != S_OK)
+ {
+ GLMDebugger();
+ GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)"));
+ return result;
+ }
+ GLMPRINTF(("-X- IDirect3DDevice9::Create setting depth-stencil render target complete."));
+
+ bool ready = m_drawableFBO->IsReady();
+ if (!ready)
+ {
+ GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)"));
+ return (HRESULT)-1;
+ }
+
+ // this next part really needs to be inside GLMContext.. or replaced with D3D style viewport setup calls.
+ m_ctx->GenDebugFontTex();
+
+ // blast the gl state mirror...
+ memset( &this->gl, 0, sizeof( this->gl ) );
+
+ GLScissorEnable_t defScissorEnable = { true };
+ GLScissorBox_t defScissorBox = { 0,0, m_params.m_presentationParameters.BackBufferWidth,m_params.m_presentationParameters.BackBufferHeight };
+ GLViewportBox_t defViewportBox = { 0,0, m_params.m_presentationParameters.BackBufferWidth,m_params.m_presentationParameters.BackBufferHeight };
+ GLViewportDepthRange_t defViewportDepthRange = { 0.1, 1000.0 };
+ GLCullFaceEnable_t defCullFaceEnable = { true };
+ GLCullFrontFace_t defCullFrontFace = { GL_CCW };
+
+ gl.m_ScissorEnable = defScissorEnable;
+ gl.m_ScissorBox = defScissorBox;
+ gl.m_ViewportBox = defViewportBox;
+ gl.m_ViewportDepthRange = defViewportDepthRange;
+ gl.m_CullFaceEnable = defCullFaceEnable;
+ gl.m_CullFrontFace = defCullFrontFace;
+
+ gl.m_stateDirtyMask = (1<RenderedSize( m_params.m_presentationParameters.BackBufferWidth, m_params.m_presentationParameters.BackBufferHeight, true ); // true = set
+
+ return result;
+#else
+ Debugger();
+ return D3DERR_INVALIDCALL;
+#endif
+}
+
+IDirect3DDevice9::~IDirect3DDevice9()
+{
+ GLMPRINTF(( "-D- IDirect3DDevice9::~IDirect3DDevice9 signpost" )); // want to know when this is called, if ever
+}
+
+#pragma mark ----- Basics - (IDirect3DDevice9)
+
+
+HRESULT IDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters)
+{
+#if DX9MODE
+ HRESULT result = S_OK;
+
+ // define the task of reset as:
+ // provide new drawable RT's for the backbuffer (color and depthstencil).
+ // fix up viewport / scissor..
+ // then pass the new presentation parameters through to GLM.
+ // (it will in turn notify appframework on the next present... which may be very soon, as mode changes are usually spotted inside Present() ).
+
+ // so some of this looks a lot like Create - we're just a subset of what it does.
+ // with a little work you could refactor this to be common code.
+
+ //------------------------------------------------------------------------------- absorb new presentation params..
+
+ m_params.m_presentationParameters = *pPresentationParameters;
+
+ //------------------------------------------------------------------------------- color buffer..
+ // release old color surface if it's there..
+ if (m_defaultColorSurface)
+ {
+ ULONG refc = m_defaultColorSurface->Release( 0, "IDirect3DDevice9::Reset public release color surface" );
+ Assert( !refc );
+ m_defaultColorSurface = NULL;
+ }
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Reset making new color render target..."));
+ // color surface
+ result = this->CreateRenderTarget(
+ m_params.m_presentationParameters.BackBufferWidth, // width
+ m_params.m_presentationParameters.BackBufferHeight, // height
+ m_params.m_presentationParameters.BackBufferFormat, // format
+ m_params.m_presentationParameters.MultiSampleType, // MSAA depth
+ m_params.m_presentationParameters.MultiSampleQuality, // MSAA quality
+ true, // lockable
+ &m_defaultColorSurface, // ppSurface
+ NULL // shared handle
+ );
+
+ if (result != S_OK)
+ {
+ GLMPRINTF(("<-X- IDirect3DDevice9::Reset (error out)"));
+ return result;
+ }
+ // do not do an AddRef here..
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Reset making color render target complete -> %08x", m_defaultColorSurface ));
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Reset setting color render target..."));
+ result = this->SetRenderTarget(0, m_defaultColorSurface);
+ if (result != S_OK)
+ {
+ GLMPRINTF(("< IDirect3DDevice9::Reset (error out)"));
+ return result;
+ }
+ GLMPRINTF(("-X- IDirect3DDevice9::Reset setting color render target complete."));
+
+
+ //-------------------------------------------------------------------------------depth stencil buffer
+ // release old depthstencil surface if it's there..
+ if (m_defaultDepthStencilSurface)
+ {
+ ULONG refc = m_defaultDepthStencilSurface->Release( 0, "IDirect3DDevice9::Reset public release depthstencil surface" );
+ Assert(!refc);
+ m_defaultDepthStencilSurface = NULL;
+ }
+
+ Assert (m_params.m_presentationParameters.EnableAutoDepthStencil);
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Reset making depth-stencil..."));
+ result = CreateDepthStencilSurface(
+ m_params.m_presentationParameters.BackBufferWidth, // width
+ m_params.m_presentationParameters.BackBufferHeight, // height
+ m_params.m_presentationParameters.AutoDepthStencilFormat, // format
+ m_params.m_presentationParameters.MultiSampleType, // MSAA depth
+ m_params.m_presentationParameters.MultiSampleQuality, // MSAA quality
+ TRUE, // enable z-buffer discard ????
+ &m_defaultDepthStencilSurface, // ppSurface
+ NULL // shared handle
+ );
+ if (result != S_OK)
+ {
+ GLMPRINTF(("<-X- IDirect3DDevice9::Reset (error out)"));
+ return result;
+ }
+ // do not do an AddRef here..
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Reset making depth-stencil complete -> %08x", m_defaultDepthStencilSurface));
+
+ GLMPRINTF(("-X- IDirect3DDevice9::Reset setting depth-stencil render target..."));
+ result = this->SetDepthStencilSurface(m_defaultDepthStencilSurface);
+ if (result != S_OK)
+ {
+ GLMPRINTF(("<-X- IDirect3DDevice9::Reset (error out)"));
+ return result;
+ }
+ GLMPRINTF(("-X- IDirect3DDevice9::Reset setting depth-stencil render target complete."));
+
+ bool ready = m_drawableFBO->IsReady();
+ if (!ready)
+ {
+ GLMPRINTF(("<-X- IDirect3DDevice9::Reset (error out)"));
+ return D3DERR_DEVICELOST;
+ }
+
+ //-------------------------------------------------------------------------------zap viewport and scissor to new backbuffer size
+
+ GLScissorEnable_t defScissorEnable = { true };
+ GLScissorBox_t defScissorBox = { 0,0, m_params.m_presentationParameters.BackBufferWidth,m_params.m_presentationParameters.BackBufferHeight };
+ GLViewportBox_t defViewportBox = { 0,0, m_params.m_presentationParameters.BackBufferWidth,m_params.m_presentationParameters.BackBufferHeight };
+ GLViewportDepthRange_t defViewportDepthRange = { 0.1, 1000.0 };
+ GLCullFaceEnable_t defCullFaceEnable = { true };
+ GLCullFrontFace_t defCullFrontFace = { GL_CCW };
+
+ gl.m_ScissorEnable = defScissorEnable;
+ gl.m_ScissorBox = defScissorBox;
+ gl.m_ViewportBox = defViewportBox;
+ gl.m_ViewportDepthRange = defViewportDepthRange;
+ gl.m_CullFaceEnable = defCullFaceEnable;
+ gl.m_CullFrontFace = defCullFrontFace;
+
+ gl.m_stateDirtyMask |= (1<m_displayParams.m_focusWindow;
+ Assert( glmParams.m_focusWindow != NULL );
+
+ // so GetClientRect can return sane answers
+ uint width, height;
+ g_engine->RenderedSize( pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight, true ); // true = set
+
+ m_ctx->SetDisplayParams( &glmParams );
+
+ return S_OK;
+#else
+ Debugger();
+ return D3DERR_INVALIDCALL;
+#endif
+}
+
+HRESULT IDirect3DDevice9::SetViewport(CONST D3DVIEWPORT9* pViewport)
+{
+ GLMPRINTF(("-X- IDirect3DDevice9::SetViewport : minZ %f, maxZ %f",pViewport->MinZ, pViewport->MaxZ ));
+
+ gl.m_ViewportBox.x = pViewport->X;
+ gl.m_ViewportBox.width = pViewport->Width;
+
+ gl.m_ViewportBox.y = pViewport->Y;
+ gl.m_ViewportBox.height = pViewport->Height;
+
+ gl.m_stateDirtyMask |= (1<MinZ;
+ gl.m_ViewportDepthRange.far = pViewport->MaxZ;
+
+ gl.m_stateDirtyMask |= (1<BeginFrame();
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::EndScene()
+{
+ m_ctx->EndFrame();
+ return S_OK;
+}
+
+
+// stolen from glmgrbasics.cpp
+
+enum ECarbonModKeyIndex
+{
+ EcmdKeyBit = 8, /* command key down?*/
+ EshiftKeyBit = 9, /* shift key down?*/
+ EalphaLockBit = 10, /* alpha lock down?*/
+ EoptionKeyBit = 11, /* option key down?*/
+ EcontrolKeyBit = 12 /* control key down?*/
+};
+
+enum ECarbonModKeyMask
+{
+ EcmdKey = 1 << EcmdKeyBit,
+ EshiftKey = 1 << EshiftKeyBit,
+ EalphaLock = 1 << EalphaLockBit,
+ EoptionKey = 1 << EoptionKeyBit,
+ EcontrolKey = 1 << EcontrolKeyBit
+};
+
+//ConVar gl_blitmode( "gl_blitmode", "1" );
+int gl_blitmode = 1;
+
+HRESULT IDirect3DDevice9::Present(CONST RECT* pSourceRect,CONST RECT* pDestRect,VD3DHWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion)
+{
+ // before attempting to present a tex, make sure it's been resolved if it was MSAA.
+ // if we push that responsibility down to m_ctx->Present, it could probably do it without an extra copy.
+ // i.e. anticipate the blit from the resolvedtex to GL_BACK, and just do that instead.
+
+ // no explicit ResolveTex call first - that got pushed down into GLMContext::Present
+ m_ctx->Present( m_defaultColorSurface->m_tex );
+
+ return S_OK;
+}
+
+#pragma mark ----- Textures - (IDirect3DDevice9)
+#pragma mark ( create functions for each texture are now adjacent to the rest of the methods for each texture class)
+
+
+HRESULT IDirect3DDevice9::SetTexture(DWORD Stage,IDirect3DBaseTexture9* pTexture)
+{
+ // texture sets are sent through immediately to GLM
+ // but we also latch the value so we know which TMU's are active.
+ // whuch can help FlushSamplers do less work.
+
+ // place new tex
+ m_textures[Stage] = pTexture;
+ if (!pTexture)
+ {
+ m_ctx->SetSamplerTex( Stage, NULL );
+ }
+ else
+ {
+ m_ctx->SetSamplerTex( Stage, pTexture->m_tex );
+ }
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::GetTexture(DWORD Stage,IDirect3DBaseTexture9** ppTexture)
+{
+ // if implemented, should it increase the ref count ??
+ GLMDebugger();
+ return S_OK;
+}
+
+
+#pragma mark ----- RT's and Surfaces - (IDirect3DDevice9)
+
+HRESULT IDirect3DDevice9::CreateRenderTarget(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultisampleQuality,BOOL Lockable,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle, char *debugLabel)
+{
+ HRESULT result = S_OK;
+
+ IDirect3DSurface9 *surf = new IDirect3DSurface9;
+ surf->m_restype = D3DRTYPE_SURFACE;
+
+ surf->m_device = this; // always set device on creations!
+
+ GLMTexLayoutKey rtkey;
+ memset( &rtkey, 0, sizeof(rtkey) );
+
+ rtkey.m_texGLTarget = GL_TEXTURE_2D;
+ rtkey.m_xSize = Width;
+ rtkey.m_ySize = Height;
+ rtkey.m_zSize = 1;
+
+ rtkey.m_texFormat = Format;
+ rtkey.m_texFlags = kGLMTexRenderable;
+
+ rtkey.m_texFlags |= kGLMTexSRGB; // all render target tex are SRGB mode
+ if (m_ctx->Caps().m_cantAttachSRGB)
+ {
+ // this config can't support SRGB render targets. quietly turn off the sRGB bit.
+ rtkey.m_texFlags &= ~kGLMTexSRGB;
+ }
+
+ if ( (MultiSample !=0) && (!m_ctx->Caps().m_nvG7x) )
+ {
+ rtkey.m_texFlags |= kGLMTexMultisampled;
+ rtkey.m_texSamples = MultiSample;
+ // FIXME no support for "MS quality" yet
+ }
+
+ surf->m_tex = m_ctx->NewTex( &rtkey, debugLabel );
+ surf->m_face = 0;
+ surf->m_mip = 0;
+
+ //desc
+ surf->m_desc.Format = Format;
+ surf->m_desc.Type = D3DRTYPE_SURFACE;
+ surf->m_desc.Usage = 0; //FIXME ???????????
+ surf->m_desc.Pool = D3DPOOL_DEFAULT; //FIXME ???????????
+ surf->m_desc.MultiSampleType = MultiSample;
+ surf->m_desc.MultiSampleQuality = MultisampleQuality;
+ surf->m_desc.Width = Width;
+ surf->m_desc.Height = Height;
+
+ *ppSurface = (result==S_OK) ? surf : NULL;
+
+ #if IUNKNOWN_ALLOC_SPEW
+ char scratch[1024];
+ sprintf(scratch,"RT %s", surf->m_tex->m_layout->m_layoutSummary );
+ surf->SetMark( true, scratch );
+ #endif
+
+
+ return result;
+}
+
+HRESULT IDirect3DDevice9::SetRenderTarget(DWORD RenderTargetIndex,IDirect3DSurface9* pRenderTarget)
+{
+ HRESULT result = S_OK;
+
+ GLMPRINTF(("-F- SetRenderTarget index=%d, surface=%8x (tex=%8x %s)",
+ RenderTargetIndex,
+ pRenderTarget,
+ pRenderTarget ? pRenderTarget->m_tex : NULL,
+ pRenderTarget ? pRenderTarget->m_tex->m_layout->m_layoutSummary : ""
+ ));
+
+ // note that it is OK to pass NULL for pRenderTarget, it implies that you would like to detach any color buffer from that target index
+
+ // behaviors...
+ // if new surf is same as old surf, no change in refcount, in fact, it's early exit
+ IDirect3DSurface9 *oldTarget = m_rtSurfaces[RenderTargetIndex];
+
+ if (pRenderTarget == oldTarget)
+ {
+ GLMPRINTF(("-F- --> no change",RenderTargetIndex));
+ return S_OK;
+ }
+
+ // we now know that the new surf is not the same as the old surf.
+ // you can't assume either one is non NULL here though.
+
+ if (m_rtSurfaces[RenderTargetIndex])
+ {
+ m_rtSurfaces[RenderTargetIndex]->Release( 1, "-A SetRenderTarget private release" ); // note this is the private refcount being lowered
+ }
+
+ if (pRenderTarget)
+ {
+ pRenderTarget->AddRef( 1, "+A SetRenderTarget private addref" ); // again, private refcount being raised
+ }
+
+ m_rtSurfaces[RenderTargetIndex] = pRenderTarget; // emplace it whether NULL or not
+
+ if (!pRenderTarget)
+ {
+ GLMPRINTF(("-F- --> Setting NULL render target on index=%d ",RenderTargetIndex));
+ }
+ else
+ {
+ GLMPRINTF(("-F- --> attaching index=%d on drawing FBO (%8x)",RenderTargetIndex, m_drawableFBO));
+ // attach color to FBO
+ GLMFBOTexAttachParams rtParams;
+ memset( &rtParams, 0, sizeof(rtParams) );
+
+ rtParams.m_tex = pRenderTarget->m_tex;
+ rtParams.m_face = pRenderTarget->m_face;
+ rtParams.m_mip = pRenderTarget->m_mip;
+ rtParams.m_zslice = 0; // FIXME if you ever want to be able to render to slices of a 3D tex..
+
+ m_drawableFBO->TexAttach( &rtParams, (EGLMFBOAttachment)(kAttColor0 + RenderTargetIndex) );
+ }
+
+ return result;
+}
+
+HRESULT IDirect3DDevice9::GetRenderTarget(DWORD RenderTargetIndex,IDirect3DSurface9** ppRenderTarget)
+{
+ if ( !m_rtSurfaces[ RenderTargetIndex ] )
+ return D3DERR_NOTFOUND;
+
+ if ( ( RenderTargetIndex > 4 ) || !ppRenderTarget )
+ return D3DERR_INVALIDCALL;
+
+ // safe because of early exit on NULL above
+ m_rtSurfaces[ RenderTargetIndex ]->AddRef(0, "+B GetRenderTarget public addref"); // per http://msdn.microsoft.com/en-us/library/bb174404(VS.85).aspx
+
+ *ppRenderTarget = m_rtSurfaces[ RenderTargetIndex ];
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::CreateOffscreenPlainSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DPOOL Pool,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle)
+{
+ // set surf->m_restype to D3DRTYPE_SURFACE...
+
+ // this is almost identical to CreateRenderTarget..
+
+ HRESULT result = S_OK;
+
+ IDirect3DSurface9 *surf = new IDirect3DSurface9;
+ surf->m_restype = D3DRTYPE_SURFACE;
+
+ surf->m_device = this; // always set device on creations!
+
+ GLMTexLayoutKey rtkey;
+ memset( &rtkey, 0, sizeof(rtkey) );
+
+ rtkey.m_texGLTarget = GL_TEXTURE_2D;
+ rtkey.m_xSize = Width;
+ rtkey.m_ySize = Height;
+ rtkey.m_zSize = 1;
+
+ rtkey.m_texFormat = Format;
+ rtkey.m_texFlags = kGLMTexRenderable;
+
+ surf->m_tex = m_ctx->NewTex( &rtkey, "offscreen plain surface" );
+ surf->m_face = 0;
+ surf->m_mip = 0;
+
+ //desc
+ surf->m_desc.Format = Format;
+ surf->m_desc.Type = D3DRTYPE_SURFACE;
+ surf->m_desc.Usage = 0;
+ surf->m_desc.Pool = D3DPOOL_DEFAULT;
+ surf->m_desc.MultiSampleType = D3DMULTISAMPLE_NONE;
+ surf->m_desc.MultiSampleQuality = 0;
+ surf->m_desc.Width = Width;
+ surf->m_desc.Height = Height;
+
+ *ppSurface = (result==S_OK) ? surf : NULL;
+
+ return result;
+}
+
+HRESULT IDirect3DDevice9::CreateDepthStencilSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultisampleQuality,BOOL Discard,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle)
+{
+ HRESULT result = S_OK;
+
+ IDirect3DSurface9 *surf = new IDirect3DSurface9;
+ surf->m_restype = D3DRTYPE_SURFACE;
+
+ surf->m_device = this; // always set device on creations!
+
+ GLMTexLayoutKey depthkey;
+ memset( &depthkey, 0, sizeof(depthkey) );
+
+ depthkey.m_texGLTarget = GL_TEXTURE_2D;
+ depthkey.m_xSize = Width;
+ depthkey.m_ySize = Height;
+ depthkey.m_zSize = 1;
+
+ depthkey.m_texFormat = Format;
+ depthkey.m_texFlags = kGLMTexRenderable | kGLMTexIsDepth | kGLMTexIsStencil;
+
+ if ( (MultiSample !=0) && (!m_ctx->Caps().m_nvG7x) )
+ {
+ depthkey.m_texFlags |= kGLMTexMultisampled;
+ depthkey.m_texSamples = MultiSample;
+ // FIXME no support for "MS quality" yet
+ }
+
+ surf->m_tex = m_ctx->NewTex( &depthkey, "depth-stencil surface" );
+ surf->m_face = 0;
+ surf->m_mip = 0;
+
+ //desc
+
+ surf->m_desc.Format = Format;
+ surf->m_desc.Type = D3DRTYPE_SURFACE;
+ surf->m_desc.Usage = 0; //FIXME ???????????
+ surf->m_desc.Pool = D3DPOOL_DEFAULT; //FIXME ???????????
+ surf->m_desc.MultiSampleType = MultiSample;
+ surf->m_desc.MultiSampleQuality = MultisampleQuality;
+ surf->m_desc.Width = Width;
+ surf->m_desc.Height = Height;
+
+ *ppSurface = (result==S_OK) ? surf : NULL;
+
+ return result;
+}
+
+HRESULT IDirect3DDevice9::SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil)
+{
+ HRESULT result = S_OK;
+
+ GLMPRINTF(("-F- SetDepthStencilSurface, surface=%8x (tex=%8x %s)",
+ pNewZStencil,
+ pNewZStencil ? pNewZStencil->m_tex : NULL,
+ pNewZStencil ? pNewZStencil->m_tex->m_layout->m_layoutSummary : ""
+ ));
+
+ if (pNewZStencil)
+ {
+ pNewZStencil->AddRef(1, "+A SetDepthStencilSurface private addref");
+ }
+
+ if (m_dsSurface)
+ {
+ m_dsSurface->Release(1, "-A SetDepthStencilSurface private release");
+ // do not do a Release here..
+ }
+
+ if (m_dsSurface != pNewZStencil)
+ {
+ GLMPRINTF(("-F- --> attaching depthstencil %8x on drawing FBO (%8x)", pNewZStencil, m_drawableFBO));
+
+ m_dsSurface = pNewZStencil;
+
+ // aka FBO attach
+
+ GLMFBOTexAttachParams depthParams;
+ memset( &depthParams, 0, sizeof(depthParams) );
+
+ // NULL is OK - it means unbind the depth buffer
+ depthParams.m_tex = (pNewZStencil) ? pNewZStencil->m_tex : NULL;
+ depthParams.m_face = 0;
+ depthParams.m_mip = 0;
+ depthParams.m_zslice= 0;
+
+ // brute force baby
+ // clear old attachments in all D/S categories
+ m_drawableFBO->TexDetach( kAttStencil );
+ m_drawableFBO->TexDetach( kAttDepth );
+ m_drawableFBO->TexDetach( kAttDepthStencil );
+
+ // select dest for new attachment
+
+ if (depthParams.m_tex!=NULL)
+ {
+ EGLMFBOAttachment destAttach = (depthParams.m_tex->m_layout->m_format->m_glDataFormat != 34041) ? kAttDepth : kAttDepthStencil;
+ m_drawableFBO->TexAttach( &depthParams, destAttach ); // attach(NULL) is allowed to mean "detach".
+ }
+ }
+ else
+ {
+ GLMPRINTF(("-F- --> no change"));
+ }
+
+ return result;
+}
+
+HRESULT IDirect3DDevice9::GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface)
+{
+ if ( !ppZStencilSurface )
+ {
+ return D3DERR_INVALIDCALL;
+ }
+
+ if ( !m_dsSurface )
+ {
+ *ppZStencilSurface = NULL;
+ return D3DERR_NOTFOUND;
+ }
+
+ m_dsSurface->AddRef(0, "+B GetDepthStencilSurface public addref"); // per http://msdn.microsoft.com/en-us/library/bb174384(VS.85).aspx
+
+ *ppZStencilSurface = m_dsSurface;
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::GetRenderTargetData(IDirect3DSurface9* pRenderTarget,IDirect3DSurface9* pDestSurface)
+{
+ // is it just a blit ?
+
+ this->StretchRect( pRenderTarget, NULL, pDestSurface, NULL, D3DTEXF_NONE ); // is this good enough ???
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::GetFrontBufferData(UINT iSwapChain,IDirect3DSurface9* pDestSurface)
+{
+ Debugger();
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::StretchRect(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect,IDirect3DSurface9* pDestSurface,CONST RECT* pDestRect,D3DTEXTUREFILTERTYPE Filter)
+{
+ // find relevant slices in GLM tex
+
+ CGLMTex *srcTex = pSourceSurface->m_tex;
+ int srcSliceIndex = srcTex->CalcSliceIndex( pSourceSurface->m_face, pSourceSurface->m_mip );
+ GLMTexLayoutSlice *srcSlice = &srcTex->m_layout->m_slices[ srcSliceIndex ];
+
+ CGLMTex *dstTex = pDestSurface->m_tex;
+ int dstSliceIndex = dstTex->CalcSliceIndex( pDestSurface->m_face, pDestSurface->m_mip );
+ GLMTexLayoutSlice *dstSlice = &dstTex->m_layout->m_slices[ dstSliceIndex ];
+
+ if ( dstTex->m_rboName != 0 )
+ {
+ Assert(!"No path yet for blitting into an MSAA tex");
+ return S_OK;
+ }
+
+ bool useFastBlit = (gl_blitmode != 0);
+
+ if ( !useFastBlit && (srcTex->m_rboName !=0)) // old way, we do a resolve to scratch tex first (necessitating two step blit)
+ {
+ m_ctx->ResolveTex( srcTex, true );
+ }
+
+ // set up source/dest rect in GLM form
+ GLMRect srcRect, dstRect;
+
+ // d3d nomenclature:
+ // Y=0 is the visual top and also aligned with V=0.
+
+ srcRect.xmin = pSourceRect ? pSourceRect->left : 0;
+ srcRect.xmax = pSourceRect ? pSourceRect->right : srcSlice->m_xSize;
+ srcRect.ymin = pSourceRect ? pSourceRect->top : 0;
+ srcRect.ymax = pSourceRect ? pSourceRect->bottom : srcSlice->m_ySize;
+
+ dstRect.xmin = pDestRect ? pDestRect->left : 0;
+ dstRect.xmax = pDestRect ? pDestRect->right : dstSlice->m_xSize;
+ dstRect.ymin = pDestRect ? pDestRect->top : 0;
+ dstRect.ymax = pDestRect ? pDestRect->bottom : dstSlice->m_ySize;
+
+ GLenum filterGL = 0;
+ switch(Filter)
+ {
+ case D3DTEXF_NONE:
+ case D3DTEXF_POINT:
+ filterGL = GL_NEAREST;
+ break;
+
+ case D3DTEXF_LINEAR:
+ filterGL = GL_LINEAR;
+ break;
+
+ default: // D3DTEXF_ANISOTROPIC
+ Assert(!"Impl aniso stretch");
+ break;
+ }
+
+ if (useFastBlit)
+ {
+ m_ctx->Blit2( srcTex, &srcRect, pSourceSurface->m_face, pSourceSurface->m_mip,
+ dstTex, &dstRect, pDestSurface->m_face, pDestSurface->m_mip,
+ filterGL
+ );
+ }
+ else
+ {
+ m_ctx->BlitTex( srcTex, &srcRect, pSourceSurface->m_face, pSourceSurface->m_mip,
+ dstTex, &dstRect, pDestSurface->m_face, pDestSurface->m_mip,
+ filterGL
+ );
+ }
+
+ return S_OK;
+}
+
+
+// This totally sucks, but this information can't be gleaned any
+// other way when translating from D3D to GL at this level
+//
+// This returns a mask, since multiple GLSL "varyings" can be tagged with centroid
+static uint32 CentroidMaskFromName( bool bPixelShader, const char *pName )
+{
+ if ( !pName )
+ return 0;
+
+ if ( bPixelShader )
+ {
+ if ( V_stristr( pName, "lightmappedgeneric_ps" ) || V_strstr( pName, "worldtwotextureblend_ps" ) )
+ {
+ return (0x01 << 2) | (0x01 << 3); // iterators 2 and 3
+ }
+ else if ( V_stristr( pName, "lightmappedreflective_ps" ) || V_stristr( pName, "water_ps" ) )
+ {
+ return (0x01 << 6) | (0x01 << 7); // iterators 6 and 7
+ }
+ else if ( V_stristr( pName, "shadow_ps" ) )
+ {
+ return (0x01 << 0) | (0x01 << 1) | (0x01 << 3) | (0x01 << 3) | (0x01 << 4); // iterators 0 through 4
+ }
+ else if ( V_stristr( pName, "ShaderedGlass_ps" ) )
+ {
+ return (0x01 << 2); // iterator 2
+ }
+ else if ( V_stristr( pName, "WorldVertexAlpha_ps" ) || V_stristr( pName, "WorldVertexTransition_ps" ) )
+ {
+ // These pixel shaders want centroid but shouldn't be used
+ Assert(0);
+ return 0;
+ }
+ }
+ else // vertex shader
+ {
+ // Vertex shaders also
+ if ( V_stristr( pName, "lightmappedgeneric_vs" ) )
+ {
+ return (0x01 << 2) | (0x01 << 3); // iterators 2 and 3
+ }
+ else if ( V_stristr( pName, "lightmappedreflective_vs" ) || V_stristr( pName, "water_vs" ) )
+ {
+ return (0x01 << 6) | (0x01 << 7); // iterators 6 and 7
+ }
+ else if ( V_stristr( pName, "shadow_vs" ) )
+ {
+ return (0x01 << 0) | (0x01 << 1) | (0x01 << 3) | (0x01 << 3) | (0x01 << 4); // iterators 0 through 4
+ }
+ else if ( V_stristr( pName, "ShaderedGlass_vs" ) )
+ {
+ return (0x01 << 2); // iterator 2
+ }
+ }
+
+ // This shader doesn't have any centroid iterators
+ return 0;
+}
+
+
+// This totally sucks, but this information can't be gleaned any
+// other way when translating from D3D to GL at this level
+static int ShadowDepthSamplerFromName( const char *pName )
+{
+ if ( !pName )
+ return -1;
+
+ if ( V_stristr( pName, "water_ps" ) )
+ {
+ return 7;
+ }
+ else if ( V_stristr( pName, "infected_ps" ) )
+ {
+ return 1;
+ }
+ else if ( V_stristr( pName, "phong_ps" ) )
+ {
+ return 4;
+ }
+ else if ( V_stristr( pName, "vertexlit_and_unlit_generic_bump_ps" ) )
+ {
+ return 8;
+ }
+ else if ( V_stristr( pName, "vertexlit_and_unlit_generic_ps" ) )
+ {
+ return 8;
+ }
+ else if ( V_stristr( pName, "eye_refract_ps" ) )
+ {
+ return 6;
+ }
+ else if ( V_stristr( pName, "eyes_flashlight_ps" ) )
+ {
+ return 4;
+ }
+ else if ( V_stristr( pName, "worldtwotextureblend_ps" ) )
+ {
+ return 7;
+ }
+ else if ( V_stristr( pName, "teeth_flashlight_ps" ) )
+ {
+ return 2;
+ }
+ else if ( V_stristr( pName, "flashlight_ps" ) ) // substring of above, make sure this comes last!!
+ {
+ return 7;
+ }
+
+ // This shader doesn't have a shadow depth map sampler
+ return -1;
+}
+
+
+#pragma mark ----- Pixel Shaders - (IDirect3DDevice9)
+
+HRESULT IDirect3DDevice9::CreatePixelShader(CONST DWORD* pFunction,IDirect3DPixelShader9** ppShader, const char *pShaderName, char *debugLabel)
+{
+ HRESULT result = D3DERR_INVALIDCALL;
+ *ppShader = NULL;
+
+ int nShadowDepthSampler = ShadowDepthSamplerFromName( pShaderName );
+ uint32 nCentroidMask = CentroidMaskFromName( true, pShaderName );
+
+ bool passthrough = ( memcmp( pFunction, "//GLSLfp", 8 ) ==0 ); // if we were given GLSL text, pass it through instead of treating it as bytecodes..
+
+ if ( g_bUseControlFlow || !m_ctx->Caps().m_hasDualShaders )
+ {
+ // either having control-flow 'on' or -glmdualshaders 'off' disqualifies ARB assembler mode
+ g_useASMTranslations = false;
+ }
+
+ if ( ! (g_useASMTranslations || g_useGLSLTranslations) )
+ {
+ Assert(!"Must set at least one translation option..");
+ *ppShader = NULL;
+ return -1;
+ }
+ else
+ {
+ int numTranslations = (g_useASMTranslations!=0) + (g_useGLSLTranslations!=0);
+
+ bool bVertexShader = false;
+
+ // we can do one or two translated forms. they go together in a single buffer with some markers to allow GLM to break it up.
+ // this also lets us mirror each set of translations to disk with a single file making it easier to view and edit side by side.
+
+ int maxTranslationSize = 50000; // size of any one translation
+
+ CUtlBuffer transbuf( 3000, numTranslations * maxTranslationSize, CUtlBuffer::TEXT_BUFFER );
+ CUtlBuffer tempbuf( 3000, maxTranslationSize, CUtlBuffer::TEXT_BUFFER );
+
+ if (passthrough)
+ {
+ // no-translation path - copy text to transbuf
+ transbuf.AppendString ( (char*)pFunction );
+ transbuf.AppendString( "\n\n" ); // whitespace
+
+ bVertexShader = false;
+ }
+ else
+ {
+ if ( g_useASMTranslations )
+ {
+ // no extra tag needed for ARBfp, just use the !!ARBfp marker
+
+ tempbuf.EnsureCapacity( maxTranslationSize );
+ g_D3DToOpenGLTranslatorASM.TranslateShader( (uint32 *) pFunction, &tempbuf, &bVertexShader, D3DToGL_OptionUseEnvParams, nShadowDepthSampler, 0, debugLabel );
+
+ // grow to encompass...
+ transbuf.AppendString ( (char*)tempbuf.Base() );
+ transbuf.AppendString( "\n\n" ); // whitespace
+ }
+
+ if ( g_useGLSLTranslations )
+ {
+ transbuf.AppendString( "//GLSLfp\n" ); // this is required so GLM can crack the text apart
+
+ // note the GLSL translator wants its own buffer
+ tempbuf.EnsureCapacity( maxTranslationSize );
+
+ uint glslPixelShaderOptions = D3DToGL_OptionGLSL | D3DToGL_OptionUseEnvParams;
+
+
+ // Fake SRGB mode - needed on R500, probably indefinitely.
+ // Do this stuff if caps show m_needsFakeSRGB=true and the sRGBWrite state is true
+ // (but not if it's engine_post which is special)
+
+ if (!m_ctx->Caps().m_hasGammaWrites)
+ {
+ if ( pShaderName )
+ {
+ if ( !V_stristr( pShaderName, "engine_post" ) )
+ {
+ glslPixelShaderOptions |= D3DToGL_OptionSRGBWriteSuffix;
+ }
+ }
+ }
+
+ if (m_ctx->Caps().m_hasBindableUniforms)
+ {
+ glslPixelShaderOptions |= D3DToGL_OptionUseBindableUniforms;
+ }
+ g_D3DToOpenGLTranslatorGLSL.TranslateShader( (uint32 *) pFunction, &tempbuf, &bVertexShader, glslPixelShaderOptions, nShadowDepthSampler, nCentroidMask, debugLabel );
+
+ transbuf.AppendString( (char*)tempbuf.Base() );
+ transbuf.AppendString( "\n\n" ); // whitespace
+ }
+ }
+
+ if ( bVertexShader )
+ {
+ // don't cross the streams
+ Assert(!"Can't accept vertex shader in CreatePixelShader");
+ result = D3DERR_INVALIDCALL;
+ }
+ else
+ {
+ IDirect3DPixelShader9 *newprog = new IDirect3DPixelShader9;
+
+ newprog->m_pixProgram = m_ctx->NewProgram( kGLMFragmentProgram, (char *)transbuf.Base() ) ;
+
+ newprog->m_device = this;
+
+ //------ find the frag program metadata and extract it.. note this takes place even for passthrough shaders, so they need to supply the needed string too
+
+ // find the highwater mark
+ const char *highWaterPrefix = "//HIGHWATER-"; // try to arrange this so it can work with pure GLSL if needed
+ const char *highWaterStr = strstr( (char *)transbuf.Base(), highWaterPrefix );
+ if (highWaterStr)
+ {
+ const char *highWaterActualData = highWaterStr + strlen( highWaterPrefix );
+
+ int value = -1;
+ sscanf( highWaterActualData, "%d", &value );
+
+ newprog->m_pixHighWater = value;
+ newprog->m_pixProgram->m_descs[kGLMGLSL].m_highWater = value;
+ }
+ else
+ {
+ Assert(!"couldn't find highwater mark in pixel shader");
+ }
+
+ // find the sampler map
+ const char *samplerMaskPrefix = "//SAMPLERMASK-"; // try to arrange this so it can work with pure GLSL if needed
+
+ char *samplerMaskStr = strstr( (char *)transbuf.Base(), samplerMaskPrefix );
+ if (samplerMaskStr)
+ {
+ char *samplerMaskActualData = samplerMaskStr + strlen( samplerMaskPrefix );
+
+ int value = -1;
+ sscanf( samplerMaskActualData, "%04x", &value );
+
+ newprog->m_pixSamplerMask = value;
+ newprog->m_pixProgram->m_samplerMask = value; // helps GLM maintain a better linked pair cache even when SRGB sampler state changes
+ }
+ else
+ {
+ Assert(!"couldn't find sampler map in pixel shader");
+ }
+
+ *ppShader = newprog;
+
+ result = S_OK;
+ }
+ }
+
+
+ return result;
+}
+
+IDirect3DPixelShader9::~IDirect3DPixelShader9()
+{
+ GLMPRINTF(( ">-A- ~IDirect3DPixelShader9" ));
+
+ if (m_device)
+ {
+ m_device->ReleasedPixelShader( this );
+
+ if (m_pixProgram)
+ {
+ m_pixProgram->m_ctx->DelProgram( m_pixProgram );
+ m_pixProgram = NULL;
+ }
+ m_device = NULL;
+ }
+
+ GLMPRINTF(( "<-A- ~IDirect3DPixelShader9" ));
+}
+
+
+HRESULT IDirect3DDevice9::SetPixelShader(IDirect3DPixelShader9* pShader)
+{
+ if (pShader)
+ {
+ m_ctx->SetDrawingProgram( kGLMFragmentProgram, pShader->m_pixProgram );
+ }
+ else
+ {
+ m_ctx->SetDrawingProgram( kGLMFragmentProgram, NULL );
+ }
+ m_pixelShader = pShader;
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetPixelShaderConstantF(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount)
+{
+ m_ctx->SetProgramParametersF( kGLMFragmentProgram, StartRegister, (float *)pConstantData, Vector4fCount );
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetPixelShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount)
+{
+ GLMPRINTF(("-X- Ignoring IDirect3DDevice9::SetPixelShaderConstantB call, count was %d", BoolCount ));
+// actually no way to do this yet.
+// m_ctx->SetProgramParametersB( kGLMFragmentProgram, StartRegister, pConstantData, BoolCount );
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetPixelShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount)
+{
+ GLMPRINTF(("-X- Ignoring IDirect3DDevice9::SetPixelShaderConstantI call, count was %d", Vector4iCount ));
+// m_ctx->SetProgramParametersI( kGLMFragmentProgram, StartRegister, pConstantData, Vector4iCount );
+ return S_OK;
+}
+
+
+#pragma mark ----- Vertex Shaders - (IDirect3DDevice9)
+
+HRESULT IDirect3DDevice9::CreateVertexShader(CONST DWORD* pFunction, IDirect3DVertexShader9** ppShader, const char *pShaderName, char *debugLabel)
+{
+ HRESULT result = D3DERR_INVALIDCALL;
+ *ppShader = NULL;
+
+ uint32 nCentroidMask = CentroidMaskFromName( false, pShaderName );
+
+ bool passthrough = ( memcmp( pFunction, "//GLSLvp", 8 ) ==0 ); // if we were given GLSL text, pass it through instead of treating it as bytecodes..
+
+ if ( ! (g_useASMTranslations || g_useGLSLTranslations) )
+ {
+ Assert(!"Must set at least one translation option..");
+ *ppShader = NULL;
+ return -1;
+ }
+ else
+ {
+ int numTranslations = (g_useASMTranslations!=0) + (g_useGLSLTranslations!=0);
+
+ bool bVertexShader = false;
+
+ // we can do one or two translated forms. they go together in a single buffer with some markers to allow GLM to break it up.
+ // this also lets us mirror each set of translations to disk with a single file making it easier to view and edit side by side.
+
+ int maxTranslationSize = 500000; // size of any one translation
+
+ CUtlBuffer transbuf( 1000, numTranslations * maxTranslationSize, CUtlBuffer::TEXT_BUFFER );
+ CUtlBuffer tempbuf( 1000, maxTranslationSize, CUtlBuffer::TEXT_BUFFER );
+
+ if (passthrough)
+ {
+ // no-translation path - copy text to transbuf
+ transbuf.AppendString ( (char*)pFunction );
+ transbuf.AppendString( "\n\n" ); // whitespace
+
+ char *checktext = transbuf.Base();
+ bVertexShader = true;
+ }
+ else
+ {
+ if ( g_useASMTranslations )
+ {
+ // no extra tag needed for ARBvp, just use the !!ARBvp marker
+
+ tempbuf.EnsureCapacity( maxTranslationSize );
+
+ uint asmTransOptions = D3DToGL_OptionUseEnvParams | D3DToGL_OptionDoFixupZ | D3DToGL_OptionDoFixupY;
+
+ // D3DToGL_OptionDoUserClipPlanes not being set for asm yet, it generates NV VP 2..
+ g_D3DToOpenGLTranslatorASM.TranslateShader( (uint32 *) pFunction, &tempbuf, &bVertexShader, asmTransOptions, -1, 0, debugLabel );
+
+ // grow to encompass...
+ transbuf.AppendString ( (char*)tempbuf.Base() );
+ transbuf.AppendString( "\n\n" ); // whitespace
+ }
+
+ if ( g_useGLSLTranslations )
+ {
+ transbuf.AppendString( "//GLSLvp\n" ); // this is required so GLM can crack the text apart
+
+ // note the GLSL translator wants its own buffer
+ tempbuf.EnsureCapacity( maxTranslationSize );
+
+ uint glslVertexShaderOptions = D3DToGL_OptionGLSL | D3DToGL_OptionUseEnvParams | D3DToGL_OptionDoFixupZ | D3DToGL_OptionDoFixupY;
+
+ if ( g_bUseControlFlow )
+ {
+ glslVertexShaderOptions |= D3DToGL_OptionAllowStaticControlFlow;
+ }
+
+ if ( m_ctx->Caps().m_hasNativeClipVertexMode )
+ {
+ // note the matched trickery over in IDirect3DDevice9::FlushStates -
+ // if on a chipset that does no have native gl_ClipVertex support, then
+ // omit writes to gl_ClipVertex, and instead submit plane equations that have been altered,
+ // and clipping will take place in GL space using gl_Position instead of gl_ClipVertex.
+
+ // note that this is very much a hack to mate up with ATI R5xx hardware constraints, and with older
+ // drivers even for later ATI parts like r6xx/r7xx. And it doesn't work on NV parts, so you really
+ // do have to choose the right way to go.
+
+ glslVertexShaderOptions |= D3DToGL_OptionDoUserClipPlanes;
+ }
+
+ if (m_ctx->Caps().m_hasBindableUniforms)
+ {
+ glslVertexShaderOptions |= D3DToGL_OptionUseBindableUniforms;
+ }
+
+ g_D3DToOpenGLTranslatorGLSL.TranslateShader( (uint32 *) pFunction, &tempbuf, &bVertexShader, glslVertexShaderOptions, -1, nCentroidMask, debugLabel );
+
+ transbuf.AppendString( (char*)tempbuf.Base() );
+ transbuf.AppendString( "\n\n" ); // whitespace
+ }
+ }
+
+ if ( !bVertexShader )
+ {
+ // don't cross the streams
+ Assert(!"Can't accept pixel shader in CreateVertexShader");
+ result = D3DERR_INVALIDCALL;
+ }
+ else
+ {
+ IDirect3DVertexShader9 *newprog = new IDirect3DVertexShader9;
+
+ newprog->m_device = this;
+
+ newprog->m_vtxProgram = m_ctx->NewProgram( kGLMVertexProgram, (char *)transbuf.Base() ) ;
+
+ // find the highwater mark.. note this takes place even for passthrough shaders, so they need to supply the needed string too
+
+ const char *highWaterPrefix = "//HIGHWATER-"; // try to arrange this so it can work with pure GLSL if needed
+ const char *highWaterStr = strstr( (char *)transbuf.Base(), highWaterPrefix );
+ if (highWaterStr)
+ {
+ const char *highWaterActualData = highWaterStr + strlen( highWaterPrefix );
+
+ int value = -1;
+ sscanf( highWaterActualData, "%d", &value );
+
+ newprog->m_vtxHighWater = value;
+ newprog->m_vtxProgram->m_descs[kGLMGLSL].m_highWater = value;
+ }
+ else
+ {
+ Assert(!"couldn't find highwater mark in vertex shader");
+ }
+
+ // find the attrib map..
+ const char *attribMapPrefix = "//ATTRIBMAP-"; // try to arrange this so it can work with pure GLSL if needed
+ const char *textbase = (char *)transbuf.Base();
+
+ const char *attribMapStr = strstr( textbase, attribMapPrefix );
+ if (attribMapStr)
+ {
+ const char *attribMapActualData = attribMapStr + strlen( attribMapPrefix );
+ for( int i=0; i<16; i++)
+ {
+ int value = -1;
+ const char *dataItem = attribMapActualData + (i*3);
+ sscanf( dataItem, "%02x", &value );
+ if (value >=0)
+ {
+ // make sure it's not a terminator
+ if (value == 0xBB)
+ {
+ Debugger();
+ }
+ }
+ else
+ {
+ // probably an 'xx'... check
+ if ( (dataItem[0] != 'x') || (dataItem[1] != 'x') )
+ {
+ Debugger(); // bad news
+ }
+ else
+ {
+ value = 0xBB; // not likely to see one of these... "fog with usage index 11"
+ }
+ }
+ newprog->m_vtxAttribMap[i] = value;
+ }
+ }
+ else
+ {
+ Debugger(); // that's bad...
+ }
+
+ *ppShader = newprog;
+
+ result = S_OK;
+ }
+ }
+
+ return result;
+}
+
+IDirect3DVertexShader9::~IDirect3DVertexShader9()
+{
+ GLMPRINTF(( ">-A- ~IDirect3DVertexShader9" ));
+
+ if (m_device)
+ {
+ m_device->ReleasedVertexShader( this );
+
+ if (m_vtxProgram)
+ {
+ m_vtxProgram->m_ctx->DelProgram( m_vtxProgram );
+ m_vtxProgram = NULL;
+ }
+ m_device = NULL;
+ }
+ else
+ {
+ }
+
+
+ GLMPRINTF(( "<-A- ~IDirect3DVertexShader9" ));
+}
+
+HRESULT IDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9* pShader)
+{
+ if (pShader)
+ {
+ m_ctx->SetDrawingProgram( kGLMVertexProgram, pShader->m_vtxProgram );
+ }
+ else
+ {
+ m_ctx->SetDrawingProgram( kGLMVertexProgram, NULL );
+ }
+ m_vertexShader = pShader;
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetVertexShaderConstantF(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount) // groups of 4 floats!
+{
+ m_ctx->SetProgramParametersF( kGLMVertexProgram, StartRegister, (float *)pConstantData, Vector4fCount );
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetVertexShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount) // individual bool count!
+{
+ m_ctx->SetProgramParametersB( kGLMVertexProgram, StartRegister, (int *)pConstantData, BoolCount );
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetVertexShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount) // groups of 4 ints!
+{
+ m_ctx->SetProgramParametersI( kGLMVertexProgram, StartRegister, (int *)pConstantData, Vector4iCount );
+ return S_OK;
+}
+
+
+#pragma mark ----- Shader Pairs - (IDirect3DDevice9)
+
+// callers need to ifdef POSIX this, because this method does not exist on real DX9
+HRESULT IDirect3DDevice9::LinkShaderPair( IDirect3DVertexShader9* vs, IDirect3DPixelShader9* ps )
+{
+ // these are really GLSL "shaders" not "programs" but the old reference to "program" persists due to the assembler heritage
+ if (vs->m_vtxProgram && ps->m_pixProgram)
+ {
+ m_ctx->LinkShaderPair( vs->m_vtxProgram, ps->m_pixProgram );
+ }
+ return S_OK;
+}
+
+// callers need to ifdef POSIX this, because this method does not exist on real DX9
+//
+HRESULT IDirect3DDevice9::QueryShaderPair( int index, GLMShaderPairInfo *infoOut )
+{
+ // these are really GLSL "shaders" not "programs" ...
+
+ m_ctx->QueryShaderPair( index, infoOut );
+
+ return S_OK;
+}
+
+
+#pragma mark ----- Vertex Buffers and Vertex Declarations - (IDirect3DDevice9)
+
+HRESULT IDirect3DDevice9::CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements,IDirect3DVertexDeclaration9** ppDecl)
+{
+ *ppDecl = NULL;
+
+ // the goal here is to arrive at something which lets us quickly generate GLMVertexSetups.
+
+ // the information we don't have, that must be inferred from the decls, is:
+ // -> how many unique streams (buffers) are used - pure curiosity
+ // -> what the stride and offset is for each decl. Size you can figure out on the spot, stride requires surveying all the components in each stream first.
+ // so init an array of per-stream offsets to 0.
+ // each one is a cursor that gets bumped by decls.
+ uint streamOffsets[ D3D_MAX_STREAMS ];
+ uint streamCount = 0;
+ (void)streamCount;
+
+ uint attribMap[16];
+ uint attribMapIndex = 0;
+ memset( attribMap, 0xFF, sizeof( attribMap ) );
+
+ memset( streamOffsets, 0, sizeof( streamOffsets ) );
+
+ IDirect3DVertexDeclaration9 *decl9 = new IDirect3DVertexDeclaration9;
+
+ decl9->m_elemCount = 0;
+
+ for (const D3DVERTEXELEMENT9 *src = pVertexElements; (src->Stream != 0xFF); src++)
+ {
+ // element
+ D3DVERTEXELEMENT9_GL *elem = &decl9->m_elements[ decl9->m_elemCount++ ];
+
+ // copy the D3D decl wholesale.
+ elem->m_dxdecl = *src;
+
+ // latch current offset in this stream.
+ elem->m_gldecl.m_offset = streamOffsets[ elem->m_dxdecl.Stream ];
+
+ // figure out size of this attr and move the cursor
+ // if cursor was on zero, bump the active stream count
+
+ if (!streamOffsets[ elem->m_dxdecl.Stream ])
+ streamCount++;
+
+ int bytes = 0;
+ switch( elem->m_dxdecl.Type )
+ {
+ case D3DDECLTYPE_FLOAT1: elem->m_gldecl.m_datasize = 1; elem->m_gldecl.m_datatype = GL_FLOAT; elem->m_gldecl.m_normalized=0; bytes = 4; break;
+ case D3DDECLTYPE_FLOAT2: elem->m_gldecl.m_datasize = 2; elem->m_gldecl.m_datatype = GL_FLOAT; elem->m_gldecl.m_normalized=0; bytes = 8; break;
+
+ //case D3DVSDT_FLOAT3:
+ case D3DDECLTYPE_FLOAT3: elem->m_gldecl.m_datasize = 3; elem->m_gldecl.m_datatype = GL_FLOAT; elem->m_gldecl.m_normalized=0; bytes = 12; break;
+
+ //case D3DVSDT_FLOAT4:
+ case D3DDECLTYPE_FLOAT4: elem->m_gldecl.m_datasize = 4; elem->m_gldecl.m_datatype = GL_FLOAT; elem->m_gldecl.m_normalized=0; bytes = 16; break;
+
+ // case D3DVSDT_UBYTE4:
+ case D3DDECLTYPE_D3DCOLOR:
+ case D3DDECLTYPE_UBYTE4:
+
+ // Force this path since we're on 10.6.2 and can't rely on EXT_vertex_array_bgra
+ if ( 1 )
+ {
+ // pass 4 UB's but we know this is out of order compared to D3DCOLOR data
+ elem->m_gldecl.m_datasize = 4; elem->m_gldecl.m_datatype = GL_UNSIGNED_BYTE;
+ }
+ else
+ {
+ // pass a GL BGRA color courtesy of http://www.opengl.org/registry/specs/ARB/vertex_array_bgra.txt
+ elem->m_gldecl.m_datasize = GL_BGRA; elem->m_gldecl.m_datatype = GL_UNSIGNED_BYTE;
+ }
+
+ elem->m_gldecl.m_normalized = (elem->m_dxdecl.Type == D3DDECLTYPE_D3DCOLOR);
+
+ bytes = 4;
+ break;
+
+ case D3DDECLTYPE_SHORT2:
+ // pass 2 US's but we know this is out of order compared to D3DCOLOR data
+ elem->m_gldecl.m_datasize = 2; elem->m_gldecl.m_datatype = GL_UNSIGNED_SHORT;
+
+ elem->m_gldecl.m_normalized = 0;
+
+ bytes = 4;
+ break;
+
+ default: Debugger(); return D3DERR_INVALIDCALL; break;
+
+ /*
+ typedef enum _D3DDECLTYPE
+ {
+ D3DDECLTYPE_FLOAT1 = 0, // 1D float expanded to (value, 0., 0., 1.)
+ D3DDECLTYPE_FLOAT2 = 1, // 2D float expanded to (value, value, 0., 1.)
+ D3DDECLTYPE_FLOAT3 = 2, // 3D float expanded to (value, value, value, 1.)
+ D3DDECLTYPE_FLOAT4 = 3, // 4D float
+ D3DDECLTYPE_D3DCOLOR = 4, // 4D packed unsigned bytes mapped to 0. to 1. range
+ // Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A)
+ D3DDECLTYPE_UBYTE4 = 5, // 4D unsigned byte
+ D3DDECLTYPE_SHORT2 = 6, // 2D signed short expanded to (value, value, 0., 1.)
+ D3DDECLTYPE_SHORT4 = 7, // 4D signed short
+
+ // The following types are valid only with vertex shaders >= 2.0
+
+
+ D3DDECLTYPE_UBYTE4N = 8, // Each of 4 bytes is normalized by dividing to 255.0
+ D3DDECLTYPE_SHORT2N = 9, // 2D signed short normalized (v[0]/32767.0,v[1]/32767.0,0,1)
+ D3DDECLTYPE_SHORT4N = 10, // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0)
+ D3DDECLTYPE_USHORT2N = 11, // 2D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,0,1)
+ D3DDECLTYPE_USHORT4N = 12, // 4D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,v[2]/65535.0,v[3]/65535.0)
+ D3DDECLTYPE_UDEC3 = 13, // 3D unsigned 10 10 10 format expanded to (value, value, value, 1)
+ D3DDECLTYPE_DEC3N = 14, // 3D signed 10 10 10 format normalized and expanded to (v[0]/511.0, v[1]/511.0, v[2]/511.0, 1)
+ D3DDECLTYPE_FLOAT16_2 = 15, // Two 16-bit floating point values, expanded to (value, value, 0, 1)
+ D3DDECLTYPE_FLOAT16_4 = 16, // Four 16-bit floating point values
+ D3DDECLTYPE_UNUSED = 17, // When the type field in a decl is unused.
+ } D3DDECLTYPE;
+ */
+ }
+
+ // write the offset and move the cursor
+ elem->m_gldecl.m_offset = streamOffsets[elem->m_dxdecl.Stream];
+ streamOffsets[ elem->m_dxdecl.Stream ] += bytes;
+
+ // cannot write m_stride yet, so zero it
+ elem->m_gldecl.m_stride = 0;
+
+ elem->m_gldecl.m_buffer = NULL; // must be filled in at draw time..
+
+ // elem count was already bumped.
+
+ // update attrib map
+ attribMap[ attribMapIndex++ ] = (elem->m_dxdecl.Usage << 4) | (elem->m_dxdecl.UsageIndex);
+ }
+ // the loop is done, we now know how many active streams there are, how many atribs are active in the declaration,
+ // and how big each one is in terms of stride.
+
+ // all that is left is to go back and write the strides - the stride comes from the stream offset cursors accumulated earlier.
+ for( int j=0; j< decl9->m_elemCount; j++)
+ {
+ D3DVERTEXELEMENT9_GL *elem = &decl9->m_elements[ j ];
+
+ elem->m_gldecl.m_stride = streamOffsets[ elem->m_dxdecl.Stream ];
+ }
+
+ *ppDecl = decl9;
+
+ return S_OK;
+}
+
+IDirect3DVertexDeclaration9::~IDirect3DVertexDeclaration9()
+{
+ GLMPRINTF(("-A- ~IDirect3DVertexDeclaration9 signpost"));
+}
+
+HRESULT IDirect3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl)
+{
+ // we just latch it. At draw time we combine the current vertex decl with the current stream set and generate a vertex setup for GLM.
+ // GLM can see what the differences are and act accordingly to adjust vert attrib bindings.
+
+ m_vertDecl = pDecl;
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetFVF(DWORD FVF)
+{
+ Debugger();
+ return D3DERR_INVALIDCALL;
+}
+
+HRESULT IDirect3DDevice9::GetFVF(DWORD* pFVF)
+{
+ Debugger();
+ return D3DERR_INVALIDCALL;
+}
+
+
+#pragma mark ----- Vertex Buffers and Streams - (IDirect3DDevice9)
+
+#pragma mark ----- Create function moved to be adjacent to other buffer methods
+
+HRESULT IDirect3DDevice9::SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride)
+{
+ // perfectly legal to see a vertex buffer of NULL get passed in here.
+ // so we need an array to track these.
+ // OK, we are being given the stride, we don't need to calc it..
+
+ GLMPRINTF(("-X- IDirect3DDevice9::SetStreamSource setting stream #%d to D3D buf %p (GL name %d); offset %d, stride %d", StreamNumber, pStreamData, (pStreamData) ? pStreamData->m_vtxBuffer->m_name: -1, OffsetInBytes, Stride));
+
+ if (pStreamData)
+ {
+ m_streams[ StreamNumber ].m_vtxBuffer = pStreamData;
+ m_streams[ StreamNumber ].m_offset = OffsetInBytes;
+ m_streams[ StreamNumber ].m_stride = Stride;
+ }
+ else
+ {
+ m_streams[ StreamNumber ].m_vtxBuffer = NULL;
+ m_streams[ StreamNumber ].m_offset = 0;
+ m_streams[ StreamNumber ].m_stride = 0;
+ }
+
+ return S_OK;
+}
+
+#pragma mark ----- Index Buffers - (IDirect3DDevice9)
+#pragma mark ----- Creatue function relocated to be adjacent to the rest of the index buffer methods
+
+HRESULT IDirect3DDevice9::SetIndices(IDirect3DIndexBuffer9* pIndexData)
+{
+ // just latch it.
+ m_indices.m_idxBuffer = pIndexData;
+ return S_OK;
+}
+
+
+#pragma mark ----- Release Handlers - (IDirect3DDevice9)
+void IDirect3DDevice9::ReleasedTexture( IDirect3DBaseTexture9 *baseTex )
+{
+ // see if this texture is referenced in any of the texture units and scrub it if so.
+ for( int i=0; i<16; i++)
+ {
+ if (m_textures[i] == baseTex)
+ {
+ m_textures[i] = NULL;
+ m_ctx->SetSamplerTex( i, NULL ); // texture sets go straight through to GLM, no dirty bit
+ }
+ }
+}
+
+void IDirect3DDevice9::ReleasedSurface( IDirect3DSurface9 *surface )
+{
+ for( int i=0; i<16; i++)
+ {
+ if (m_rtSurfaces[i]==surface)
+ {
+ // this was a surprise release... scrub it
+ m_rtSurfaces[i] = NULL;
+ GLMPRINTF(( "-A- Scrubbed surface %08x from m_rtSurfaces[%d]", surface, i ));
+ }
+ }
+ if( m_dsSurface == surface )
+ {
+ m_dsSurface = NULL;
+ GLMPRINTF(( "-A- Scrubbed surface %08x from m_dsSurface", surface ));
+ }
+
+ if ( m_defaultColorSurface == surface )
+ {
+ m_defaultColorSurface = NULL;
+ GLMPRINTF(( "-A- Scrubbed surface %08x from m_defaultColorSurface", surface ));
+ }
+
+ if ( m_defaultDepthStencilSurface == surface )
+ {
+ m_defaultDepthStencilSurface = NULL;
+ GLMPRINTF(( "-A- Scrubbed surface %08x from m_defaultDepthStencilSurface", surface ));
+ }
+}
+
+void IDirect3DDevice9::ReleasedPixelShader( IDirect3DPixelShader9 *pixelShader )
+{
+ if ( m_pixelShader == pixelShader )
+ {
+ m_pixelShader = NULL;
+ GLMPRINTF(( "-A- Scrubbed pixel shader %08x from m_pixelShader", pixelShader ));
+ }
+}
+
+void IDirect3DDevice9::ReleasedVertexShader( IDirect3DVertexShader9 *vertexShader )
+{
+ if ( m_vertexShader == vertexShader )
+ {
+ m_vertexShader = NULL;
+ GLMPRINTF(( "-A- Scrubbed vertex shader %08x from m_vertexShader", vertexShader ));
+ }
+}
+
+void IDirect3DDevice9::ReleasedVertexBuffer( IDirect3DVertexBuffer9 *vertexBuffer )
+{
+ for (int i=0; i< D3D_MAX_STREAMS; i++)
+ {
+ if ( m_streams[i].m_vtxBuffer == vertexBuffer )
+ {
+ m_streams[i].m_vtxBuffer = NULL;
+ GLMPRINTF(( "-A- Scrubbed vertex buffer %08x from m_streams[%d]", vertexBuffer, i ));
+ }
+ }
+}
+
+void IDirect3DDevice9::ReleasedIndexBuffer( IDirect3DIndexBuffer9 *indexBuffer )
+{
+ if ( m_indices.m_idxBuffer == indexBuffer )
+ {
+ m_indices.m_idxBuffer = NULL;
+ GLMPRINTF(( "-A- Scrubbed index buffer %08x from m_indices", indexBuffer ));
+ }
+}
+
+
+void IDirect3DDevice9::ReleasedQuery( IDirect3DQuery9 *query )
+{
+ // nothing to do yet..
+}
+
+
+
+
+#pragma mark ----- Queries - (IDirect3DDevice9)
+
+// note that detection of whether queries are supported is done by trying to create one.
+// so for GL, be observant here of whether we have that capability or not.
+// pretty much have this everywhere but i950.
+
+HRESULT IDirect3DDevice9::CreateQuery(D3DQUERYTYPE Type,IDirect3DQuery9** ppQuery)
+{
+ if (m_ctx->Caps().m_hasOcclusionQuery)
+ {
+ IDirect3DQuery9 *newquery = new IDirect3DQuery9;
+
+ newquery->m_device = this;
+
+ newquery->m_type = Type;
+ newquery->m_ctx = m_ctx;
+
+ GLMQueryParams params;
+ memset( ¶ms, 0, sizeof(params) );
+
+ bool known = false;
+ switch(newquery->m_type)
+ {
+ case D3DQUERYTYPE_OCCLUSION: /* D3DISSUE_BEGIN, D3DISSUE_END */
+ // create an occlusion query
+ params.m_type = EOcclusion;
+ break;
+
+ case D3DQUERYTYPE_EVENT: /* D3DISSUE_END */
+ params.m_type = EFence;
+ break;
+
+ case D3DQUERYTYPE_RESOURCEMANAGER: /* D3DISSUE_END */
+ case D3DQUERYTYPE_TIMESTAMP: /* D3DISSUE_END */
+ case D3DQUERYTYPE_TIMESTAMPFREQ: /* D3DISSUE_END */
+ case D3DQUERYTYPE_INTERFACETIMINGS: /* D3DISSUE_BEGIN, D3DISSUE_END */
+ case D3DQUERYTYPE_PIXELTIMINGS: /* D3DISSUE_BEGIN, D3DISSUE_END */
+ case D3DQUERYTYPE_CACHEUTILIZATION: /* D3DISSUE_BEGIN, D3DISSUE_END */
+ Assert( !"Un-implemented query type" );
+ break;
+
+ default:
+ Assert( !"Unknown query type" );
+ break;
+ }
+ newquery->m_query = m_ctx->NewQuery( ¶ms );
+
+ *ppQuery = newquery;
+ return S_OK;
+ }
+ else
+ {
+ *ppQuery = NULL;
+ return -1; // failed
+ }
+
+}
+
+IDirect3DQuery9::~IDirect3DQuery9()
+{
+ GLMPRINTF((">-A- ~IDirect3DQuery9"));
+
+ if (m_device)
+ {
+ m_device->ReleasedQuery( this );
+
+ if (m_query)
+ {
+ GLMPRINTF((">-A- ~IDirect3DQuery9 freeing m_query"));
+
+ m_query->m_ctx->DelQuery( m_query );
+ m_query = NULL;
+
+ GLMPRINTF(("<-A- ~IDirect3DQuery9 freeing m_query done"));
+ }
+ m_device = NULL;
+ }
+
+ GLMPRINTF(("<-A- ~IDirect3DQuery9"));
+}
+
+#pragma mark ----- Render States - (IDirect3DDevice9)
+
+struct D3D_RSINFO
+{
+ int m_class;
+ D3DRENDERSTATETYPE m_state;
+ DWORD m_defval;
+ // m_class runs 0-3.
+ // 3 = must implement - fully general - "obey"
+ // 2 = implement setup to the default value (it has a GL effect but does not change later) "obey once"
+ // 1 = "fake implement" setup to the default value no GL effect, debug break if anything but default value comes through - "ignore"
+ // 0 = game never ever sets this one, break if someone even tries. "complain"
+};
+
+#define D3DRS_VALUE_LIMIT 210
+bool g_D3DRS_INFO_unpacked_ready = false; // set to true after unpack
+D3D_RSINFO g_D3DRS_INFO_unpacked[ D3DRS_VALUE_LIMIT+1 ];
+
+#ifdef D3D_RSI
+ #error macro collision... rename this
+#else
+ #define D3D_RSI(nclass,nstate,ndefval) { nclass, nstate, ndefval }
+#endif
+
+// FP conversions to hex courtesy of http://babbage.cs.qc.cuny.edu/IEEE-754/Decimal.html
+#define CONST_DZERO 0x00000000
+#define CONST_DONE 0x3F800000
+#define CONST_D64 0x42800000
+#define DONT_KNOW_YET 0x31415926
+
+
+// see http://www.toymaker.info/Games/html/render_states.html
+
+D3D_RSINFO g_D3DRS_INFO_packed[] =
+{
+ // these do not have to be in any particular order. they get unpacked into the empty array above for direct indexing.
+
+ D3D_RSI( 3, D3DRS_ZENABLE, DONT_KNOW_YET ), // enable Z test (or W buffering)
+ D3D_RSI( 3, D3DRS_ZWRITEENABLE, DONT_KNOW_YET ), // enable Z write
+ D3D_RSI( 3, D3DRS_ZFUNC, DONT_KNOW_YET ), // select Z func
+
+ D3D_RSI( 3, D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA ), // see transitiontable.cpp "APPLY_RENDER_STATE_FUNC( D3DRS_COLORWRITEENABLE, ColorWriteEnable )"
+
+ D3D_RSI( 3, D3DRS_CULLMODE, D3DCULL_CCW ), // backface cull control
+
+ D3D_RSI( 3, D3DRS_ALPHABLENDENABLE, DONT_KNOW_YET ), // ->CTransitionTable::ApplySeparateAlphaBlend and ApplyAlphaBlend
+ D3D_RSI( 3, D3DRS_BLENDOP, D3DBLENDOP_ADD ),
+ D3D_RSI( 3, D3DRS_SRCBLEND, DONT_KNOW_YET ),
+ D3D_RSI( 3, D3DRS_DESTBLEND, DONT_KNOW_YET ),
+
+ D3D_RSI( 1, D3DRS_SEPARATEALPHABLENDENABLE, FALSE ), // hit in CTransitionTable::ApplySeparateAlphaBlend
+ D3D_RSI( 1, D3DRS_SRCBLENDALPHA, D3DBLEND_ONE ), // going to demote these to class 1 until I figure out if they are implementable
+ D3D_RSI( 1, D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO ),
+ D3D_RSI( 1, D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD ),
+
+ // what is the deal with alpha test... looks like it is inited to off.
+ D3D_RSI( 3, D3DRS_ALPHATESTENABLE, 0 ),
+ D3D_RSI( 3, D3DRS_ALPHAREF, 0 ),
+ D3D_RSI( 3, D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL ),
+
+ D3D_RSI( 3, D3DRS_STENCILENABLE, FALSE ),
+ D3D_RSI( 3, D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP ),
+ D3D_RSI( 3, D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP ),
+ D3D_RSI( 3, D3DRS_STENCILPASS, D3DSTENCILOP_KEEP ),
+ D3D_RSI( 3, D3DRS_STENCILFUNC, D3DCMP_ALWAYS ),
+ D3D_RSI( 3, D3DRS_STENCILREF, 0 ),
+ D3D_RSI( 3, D3DRS_STENCILMASK, 0xFFFFFFFF ),
+ D3D_RSI( 3, D3DRS_STENCILWRITEMASK, 0xFFFFFFFF ),
+
+ D3D_RSI( 3, D3DRS_TWOSIDEDSTENCILMODE, FALSE ),
+ D3D_RSI( 3, D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP ),
+ D3D_RSI( 3, D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP ),
+ D3D_RSI( 3, D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP ),
+ D3D_RSI( 3, D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS ),
+
+ D3D_RSI( 3, D3DRS_FOGENABLE, FALSE ), // see CShaderAPIDx8::FogMode and friends - be ready to do the ARB fog linear option madness
+ D3D_RSI( 3, D3DRS_FOGCOLOR, 0 ),
+ D3D_RSI( 3, D3DRS_FOGTABLEMODE, D3DFOG_NONE ),
+ D3D_RSI( 3, D3DRS_FOGSTART, CONST_DZERO ),
+ D3D_RSI( 3, D3DRS_FOGEND, CONST_DONE ),
+ D3D_RSI( 3, D3DRS_FOGDENSITY, CONST_DZERO ),
+ D3D_RSI( 3, D3DRS_RANGEFOGENABLE, FALSE ),
+ D3D_RSI( 3, D3DRS_FOGVERTEXMODE, D3DFOG_NONE ), // watch out for CShaderAPIDx8::CommitPerPassFogMode....
+
+ D3D_RSI( 3, D3DRS_MULTISAMPLEANTIALIAS, TRUE ),
+ D3D_RSI( 3, D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF ),
+
+ D3D_RSI( 3, D3DRS_SCISSORTESTENABLE, FALSE ), // heed IDirect3DDevice9::SetScissorRect
+
+ D3D_RSI( 3, D3DRS_DEPTHBIAS, CONST_DZERO ),
+ D3D_RSI( 3, D3DRS_SLOPESCALEDEPTHBIAS, CONST_DZERO ),
+
+ D3D_RSI( 3, D3DRS_COLORWRITEENABLE1, 0x0000000f ),
+ D3D_RSI( 3, D3DRS_COLORWRITEENABLE2, 0x0000000f ),
+ D3D_RSI( 3, D3DRS_COLORWRITEENABLE3, 0x0000000f ),
+
+ D3D_RSI( 3, D3DRS_SRGBWRITEENABLE, 0 ), // heeded but ignored..
+
+ D3D_RSI( 2, D3DRS_CLIPPING, TRUE ), // um, yeah, clipping is enabled (?)
+ D3D_RSI( 3, D3DRS_CLIPPLANEENABLE, 0 ), // mask 1<m_class >= 0; packed++ )
+ {
+ if ( (packed->m_state <0) || (packed->m_state >= D3DRS_VALUE_LIMIT) )
+ {
+ // bad
+ Debugger();
+ }
+ else
+ {
+ // dispatch it to the unpacked array
+ g_D3DRS_INFO_unpacked[ packed->m_state ] = *packed;
+ }
+ }
+}
+
+// convenience functions
+
+GLenum D3DCompareFuncToGL( DWORD function )
+{
+ switch ( function )
+ {
+ case D3DCMP_NEVER : return GL_NEVER; // Always fail the test.
+ case D3DCMP_LESS : return GL_LESS; // Accept the new pixel if its value is less than the value of the current pixel.
+ case D3DCMP_EQUAL : return GL_EQUAL; // Accept the new pixel if its value equals the value of the current pixel.
+ case D3DCMP_LESSEQUAL : return GL_LEQUAL; // Accept the new pixel if its value is less than or equal to the value of the current pixel. **
+ case D3DCMP_GREATER : return GL_GREATER; // Accept the new pixel if its value is greater than the value of the current pixel.
+ case D3DCMP_NOTEQUAL : return GL_NOTEQUAL; // Accept the new pixel if its value does not equal the value of the current pixel.
+ case D3DCMP_GREATEREQUAL: return GL_GEQUAL; // Accept the new pixel if its value is greater than or equal to the value of the current pixel.
+ case D3DCMP_ALWAYS : return GL_ALWAYS; // Always pass the test.
+ default : Debugger(); return 0xFFFFFFFF;
+ }
+}
+
+static GLenum D3DStencilOpToGL( DWORD operation )
+{
+ switch( operation )
+ {
+ case D3DSTENCILOP_KEEP : return GL_KEEP;
+ case D3DSTENCILOP_ZERO : return GL_ZERO;
+ case D3DSTENCILOP_REPLACE : return GL_REPLACE;
+ case D3DSTENCILOP_INCRSAT : return GL_INCR;
+ case D3DSTENCILOP_DECRSAT : return GL_DECR;
+ case D3DSTENCILOP_INVERT : return GL_INVERT;
+ case D3DSTENCILOP_INCR : return GL_INCR_WRAP_EXT;
+ case D3DSTENCILOP_DECR : return GL_DECR_WRAP_EXT;
+ default : Debugger(); return 0xFFFFFFFF;
+ }
+}
+
+static GLenum D3DBlendFactorToGL( DWORD equation )
+{
+ switch (equation)
+ {
+ case D3DBLEND_ZERO : return GL_ZERO; // Blend factor is (0, 0, 0, 0).
+ case D3DBLEND_ONE : return GL_ONE; // Blend factor is (1, 1, 1, 1).
+ case D3DBLEND_SRCCOLOR : return GL_SRC_COLOR; // Blend factor is (Rs, Gs, Bs, As).
+ case D3DBLEND_INVSRCCOLOR : return GL_ONE_MINUS_SRC_COLOR; // Blend factor is (1 - Rs, 1 - Gs, 1 - Bs, 1 - As).
+ case D3DBLEND_SRCALPHA : return GL_SRC_ALPHA; // Blend factor is (As, As, As, As).
+ case D3DBLEND_INVSRCALPHA : return GL_ONE_MINUS_SRC_ALPHA; // Blend factor is ( 1 - As, 1 - As, 1 - As, 1 - As).
+ case D3DBLEND_DESTALPHA : return GL_DST_ALPHA; // Blend factor is (Ad Ad Ad Ad).
+ case D3DBLEND_INVDESTALPHA : return GL_ONE_MINUS_DST_ALPHA; // Blend factor is (1 - Ad 1 - Ad 1 - Ad 1 - Ad).
+ case D3DBLEND_DESTCOLOR : return GL_DST_COLOR; // Blend factor is (Rd, Gd, Bd, Ad).
+ case D3DBLEND_INVDESTCOLOR : return GL_ONE_MINUS_DST_COLOR; // Blend factor is (1 - Rd, 1 - Gd, 1 - Bd, 1 - Ad).
+ case D3DBLEND_SRCALPHASAT : return GL_SRC_ALPHA_SATURATE; // Blend factor is (f, f, f, 1); where f = min(As, 1 - Ad).
+
+ /*
+ // these are weird.... break if we hit them
+ case D3DBLEND_BOTHSRCALPHA : Assert(0); return GL_ZERO; // Obsolete. Starting with DirectX 6, you can achieve the same effect by setting the source and destination blend factors to D3DBLEND_SRCALPHA and D3DBLEND_INVSRCALPHA in separate calls.
+ case D3DBLEND_BOTHINVSRCALPHA: Assert(0); return GL_ZERO; // Source blend factor is (1 - As, 1 - As, 1 - As, 1 - As), and destination blend factor is (As, As, As, As); the destination blend selection is overridden. This blend mode is supported only for the D3DRS_SRCBLEND render state.
+ case D3DBLEND_BLENDFACTOR : Assert(0); return GL_ZERO; // Constant color blending factor used by the frame-buffer blender. This blend mode is supported only if D3DPBLENDCAPS_BLENDFACTOR is set in the SrcBlendCaps or DestBlendCaps members of D3DCAPS9.
+
+ dxabstract.h has not heard of these, so let them hit the debugger if they come through
+ case D3DBLEND_INVBLENDFACTOR: //Inverted constant color-blending factor used by the frame-buffer blender. This blend mode is supported only if the D3DPBLENDCAPS_BLENDFACTOR bit is set in the SrcBlendCaps or DestBlendCaps members of D3DCAPS9.
+ case D3DBLEND_SRCCOLOR2: // Blend factor is (PSOutColor[1]r, PSOutColor[1]g, PSOutColor[1]b, not used). This flag is available in Direct3D 9Ex only.
+ case D3DBLEND_INVSRCCOLOR2: // Blend factor is (1 - PSOutColor[1]r, 1 - PSOutColor[1]g, 1 - PSOutColor[1]b, not used)). This flag is available in Direct3D 9Ex only.
+ */
+ default:
+ Debugger();
+ return 0xFFFFFFFF;
+ break;
+ }
+}
+
+static GLenum D3DBlendOperationToGL( DWORD operation )
+{
+ switch (operation)
+ {
+ case D3DBLENDOP_ADD : return GL_FUNC_ADD; // The result is the destination added to the source. Result = Source + Destination
+
+ /* not covered by dxabstract.h..
+ case D3DBLENDOP_SUBTRACT : return GL_FUNC_SUBTRACT; // The result is the destination subtracted from to the source. Result = Source - Destination
+ case D3DBLENDOP_REVSUBTRACT : return GL_FUNC_REVERSE_SUBTRACT; // The result is the source subtracted from the destination. Result = Destination - Source
+ case D3DBLENDOP_MIN : return GL_MIN; // The result is the minimum of the source and destination. Result = MIN(Source, Destination)
+ case D3DBLENDOP_MAX : return GL_MAX; // The result is the maximum of the source and destination. Result = MAX(Source, Destination)
+ */
+
+ default:
+ Debugger();
+ return 0xFFFFFFFF;
+ break;
+
+ }
+}
+
+HRESULT IDirect3DDevice9::SetRenderState( D3DRENDERSTATETYPE State, DWORD Value )
+{
+ char rsSpew = 1;
+ char ignored = 0;
+
+ if (!g_D3DRS_INFO_unpacked_ready)
+ {
+ UnpackD3DRSITable();
+ g_D3DRS_INFO_unpacked_ready = true;
+ }
+
+ if (State >= D3DRS_VALUE_LIMIT)
+ {
+ Debugger(); // bad
+ }
+ else
+ {
+ D3D_RSINFO *info = &g_D3DRS_INFO_unpacked[ State ];
+
+ if (info->m_state != State)
+ {
+ Debugger(); // bad - we never set up that state in our list
+ }
+
+ if (rsSpew)
+ {
+ GLMPRINTF(("-X- IDirect3DDevice9::SetRenderState: set %s(%d) to %d(0x%08x) ( class %d, defval is %d(0x%08x) )", GLMDecode( eD3D_RSTATE,State),State, Value,Value, info->m_class, info->m_defval,info->m_defval ));
+ }
+
+ switch( info->m_class )
+ {
+ case 0: // just ignore quietly. example: D3DRS_LIGHTING
+ ignored = 1;
+ break;
+
+ case 1:
+ {
+ // no GL response - and no error as long as the write value matches the default
+ if (Value != info->m_defval)
+ {
+ static char stop_here_1 = 0;
+ if (stop_here_1)
+ Debugger();
+ }
+ }
+ break;
+
+ case 2:
+
+ // provide GL response, but only support known default value
+ if (Value != info->m_defval)
+ {
+ static char stop_here_2 = 0;
+ if (stop_here_2)
+ Debugger();
+ }
+ // fall through to mode 3
+
+ case 3:
+
+ // full GL response, support any legal value
+ // note we're handling the class-2's as well.
+ switch(State)
+ {
+ case D3DRS_ZENABLE: // kGLDepthTestEnable
+ gl.m_DepthTestEnable.enable = Value;
+ gl.m_stateDirtyMask |= (1< GL blend equation
+ {
+ GLenum equation = D3DBlendOperationToGL( Value );
+ gl.m_BlendEquation.equation = equation;
+ gl.m_stateDirtyMask |= (1< GL blend factor
+ case D3DRS_DESTBLEND: // kGLBlendFactor
+ {
+ GLenum factor = D3DBlendFactorToGL( Value );
+
+ if (State==D3DRS_SRCBLEND)
+ {
+ gl.m_BlendFactor.srcfactor = factor;
+ }
+ else
+ {
+ gl.m_BlendFactor.dstfactor = factor;
+ }
+ gl.m_stateDirtyMask |= (1< GL_STENCIL_TEST_TWO_SIDE_EXT... not yet implemented ?
+ case D3DRS_CCW_STENCILFAIL: // GLStencilOp_t
+ case D3DRS_CCW_STENCILZFAIL: // GLStencilOp_t
+ case D3DRS_CCW_STENCILPASS: // GLStencilOp_t
+ case D3DRS_CCW_STENCILFUNC: // GLStencilFunc_t
+ ignored = 1;
+ break;
+
+ case D3DRS_FOGENABLE: // none of these are implemented yet... erk
+ gl.m_FogEnable = (Value != 0);
+ GLMPRINTF(("-D- fogenable = %d",Value ));
+ //ignored = 1;
+ break;
+
+ case D3DRS_FOGCOLOR:
+ case D3DRS_FOGTABLEMODE:
+ case D3DRS_FOGSTART:
+ case D3DRS_FOGEND:
+ case D3DRS_FOGDENSITY:
+ case D3DRS_RANGEFOGENABLE:
+ case D3DRS_FOGVERTEXMODE:
+ ignored = 1;
+ break;
+
+ case D3DRS_MULTISAMPLEANTIALIAS:
+ case D3DRS_MULTISAMPLEMASK:
+ ignored = 1;
+ break;
+
+ case D3DRS_SCISSORTESTENABLE: // kGLScissorEnable
+ {
+ gl.m_ScissorEnable.enable = Value;
+
+ gl.m_stateDirtyMask |= (1<m_addressModes[ Type - (int)D3DSAMP_ADDRESSU ] = (D3DTEXTUREADDRESS)Value;
+ break;
+
+ case D3DSAMP_BORDERCOLOR:
+ samp->m_borderColor = Value;
+ break;
+
+ case D3DSAMP_MAGFILTER: samp->m_magFilter = (D3DTEXTUREFILTERTYPE)Value; break;
+ case D3DSAMP_MINFILTER: samp->m_minFilter = (D3DTEXTUREFILTERTYPE)Value; break;
+ case D3DSAMP_MIPFILTER: samp->m_mipFilter = (D3DTEXTUREFILTERTYPE)Value; break;
+ case D3DSAMP_MIPMAPLODBIAS: samp->m_mipmapBias = Value; break; // float in sheep's clothing - check this one out
+ case D3DSAMP_MAXMIPLEVEL: samp->m_maxMipLevel = Value; break;
+ case D3DSAMP_MAXANISOTROPY: samp->m_maxAniso = Value; break;
+ case D3DSAMP_SRGBTEXTURE: samp->m_srgb = Value; break;
+ case D3DSAMP_SHADOWFILTER: samp->m_shadowFilter = Value; break;
+
+ default:
+ Assert(!"Unknown sampler parameter");
+ break;
+
+ }
+ gl.m_samplerDirtyMask |= (1<WriteAlphaTestEnable( &gl.m_AlphaTestEnable );
+
+ if ( stateHitMask & (1<WriteAlphaTestFunc( &gl.m_AlphaTestFunc );
+
+ if ( stateHitMask & (1<WriteAlphaToCoverageEnable( &gl.m_AlphaToCoverageEnable );
+
+ if ( stateHitMask & (1<WriteCullFaceEnable( &gl.m_CullFaceEnable );
+
+ if ( stateHitMask & (1<WriteCullFrontFace( &gl.m_CullFrontFace );
+
+ if ( stateHitMask & (1<WritePolygonMode( &gl.m_PolygonMode );
+
+ if ( stateHitMask & (1<WriteDepthBias( &gl.m_DepthBias );
+
+ if ( stateHitMask & (1<WriteScissorEnable( &gl.m_ScissorEnable );
+
+ if ( stateHitMask & (1<WriteScissorBox( &gl.m_ScissorBox );
+
+ if ( stateHitMask & (1<WriteViewportBox( &gl.m_ViewportBox );
+
+ if ( stateHitMask & (1<WriteViewportDepthRange( &gl.m_ViewportDepthRange );
+
+ if ( stateHitMask & (1<WriteClipPlaneEnable( &gl.m_ClipPlaneEnable[x], x );
+ }
+ }
+
+ if ( stateHitMask & (1<Caps().m_hasNativeClipVertexMode )
+ {
+ // hacked coeffs = { src->x, -src->y, 0.5f * src->z, src->w + (0.5f * src->z) };
+ // Antonio's trick - so we can use gl_Position as the clippee, not gl_ClipVertex.
+
+ GLClipPlaneEquation_t *equ = &gl.m_ClipPlaneEquation[x];
+
+ ///////////////// temp1
+ temp1.x = equ->x;
+ temp1.y = equ->y * -1.0;
+ temp1.z = equ->z * 0.5;
+ temp1.w = equ->w + (equ->z * 0.5);
+
+
+ //////////////// temp2
+ VMatrix mat1( 1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 2, -1,
+ 0, 0, 0, 1
+ );
+ //mat1 = mat1.Transpose();
+
+ VMatrix mat2;
+ bool success = mat1.InverseGeneral( mat2 );
+
+ if (success)
+ {
+ VMatrix mat3;
+ mat3 = mat2.Transpose();
+
+ VPlane origPlane( Vector( equ->x, equ->y, equ->z ), equ->w );
+ VPlane newPlane;
+
+ newPlane = mat3 * origPlane /* * mat3 */;
+
+ VPlane finalPlane = newPlane;
+
+ temp2.x = newPlane.m_Normal.x;
+ temp2.y = newPlane.m_Normal.y;
+ temp2.z = newPlane.m_Normal.z;
+ temp2.w = newPlane.m_Dist;
+ }
+ else
+ {
+ temp2.x = 0;
+ temp2.y = 0;
+ temp2.z = 0;
+ temp2.w = 0;
+ }
+ }
+ else
+ {
+ temp1 = temp2 = gl.m_ClipPlaneEquation[x];
+ }
+
+ if (1) //GLMKnob("caps-key",NULL)==0.0)
+ {
+ m_ctx->WriteClipPlaneEquation( &temp1, x ); // no caps lock = Antonio or classic
+
+ /*
+ if (x<1)
+ {
+ GLMPRINTF(( " plane %d √vers1[ %5.2f %5.2f %5.2f %5.2f ] vers2[ %5.2f %5.2f %5.2f %5.2f ]",
+ x,
+ temp1.x,temp1.y,temp1.z,temp1.w,
+ temp2.x,temp2.y,temp2.z,temp2.w
+ ));
+ }
+ */
+ }
+ else
+ {
+ m_ctx->WriteClipPlaneEquation( &temp2, x ); // caps = our way or classic
+
+ /*
+ if (x<1)
+ {
+ GLMPRINTF(( " plane %d vers1[ %5.2f %5.2f %5.2f %5.2f ] √vers2[ %5.2f %5.2f %5.2f %5.2f ]",
+ x,
+ temp1.x,temp1.y,temp1.z,temp1.w,
+ temp2.x,temp2.y,temp2.z,temp2.w
+ ));
+ }
+ */
+ }
+ }
+ }
+
+ if ( stateHitMask & (1<WriteColorMaskSingle( &gl.m_ColorMaskSingle );
+
+// if ( stateHitMask & (1<WriteColorMaskMultiple( &gl.m_ColorMaskMultiple ); // ???????????? hmmmmmmmm
+
+ if ( stateHitMask & (1<WriteBlendEnable( &gl.m_BlendEnable );
+
+ if ( stateHitMask & (1<WriteBlendFactor( &gl.m_BlendFactor );
+
+ if ( stateHitMask & (1<WriteBlendEquation( &gl.m_BlendEquation );
+
+ if ( stateHitMask & (1<WriteBlendColor( &gl.m_BlendColor );
+
+ if ( stateHitMask & (1<WriteBlendEnableSRGB( &gl.m_BlendEnableSRGB );
+
+ if ( stateHitMask & (1<WriteDepthTestEnable( &gl.m_DepthTestEnable );
+
+ if ( stateHitMask & (1<WriteDepthFunc( &gl.m_DepthFunc );
+
+ if ( stateHitMask & (1<WriteDepthMask( &gl.m_DepthMask );
+
+ if ( stateHitMask & (1<WriteStencilTestEnable( &gl.m_StencilTestEnable );
+
+ if ( stateHitMask & (1<WriteStencilFunc( &gl.m_StencilFunc );
+
+ if ( stateHitMask & (1<WriteStencilOp( &gl.m_StencilOp,0 );
+ m_ctx->WriteStencilOp( &gl.m_StencilOp,1 ); // ********* need to recheck this
+ }
+
+ if ( stateHitMask & (1<WriteStencilWriteMask( &gl.m_StencilWriteMask );
+
+ if ( stateHitMask & (1<WriteClearColor( &gl.m_ClearColor );
+
+ if ( stateHitMask & (1<WriteClearDepth( &gl.m_ClearDepth );
+
+ if ( stateHitMask & (1<WriteClearStencil( &gl.m_ClearStencil );
+
+ gl.m_stateDirtyMask &= (~stateHitMask);
+
+ return S_OK;
+}
+
+
+ // addressing modes
+ // 1 D3DTADDRESS_WRAP Tile the texture at every integer junction.
+ // D3DTADDRESS_MIRROR Similar to D3DTADDRESS_WRAP, except that the texture is flipped at every integer junction.
+ // 3 D3DTADDRESS_CLAMP Texture coordinates outside the range [0.0, 1.0] are set to the texture color at 0.0 or 1.0, respectively.
+ // 4 D3DTADDRESS_BORDER Texture coordinates outside the range [0.0, 1.0] are set to the border color.
+ // D3DTADDRESS_MIRRORONCE Similar to D3DTADDRESS_MIRROR and D3DTADDRESS_CLAMP.
+ // Takes the absolute value of the texture coordinate (thus, mirroring around 0),
+ // and then clamps to the maximum value. The most common usage is for volume textures,
+ // where support for the full D3DTADDRESS_MIRRORONCE texture-addressing mode is not
+ // necessary, but the data is symmetric around the one axis.
+static GLenum dxtogl_addressMode[] =
+{
+ GL_REPEAT, // 0 is an invalid sampler addressing mode, if it comes up, just use REPEAT
+ GL_REPEAT, // from D3DTADDRESS_WRAP
+ (GLenum)-1, // no D3DTADDRESS_MIRROR support
+ GL_CLAMP_TO_EDGE, // from D3DTADDRESS_CLAMP
+ GL_CLAMP, // from D3DTADDRESS_BORDER
+ (GLenum)-1, // no D3DTADDRESS_MIRRORONCE support
+};
+
+/*
+ _D3DTEXTUREFILTERTYPE:
+ D3DTEXF_NONE = 0, // filtering disabled (valid for mip filter only)
+ D3DTEXF_POINT = 1, // nearest
+ D3DTEXF_LINEAR = 2, // linear interpolation
+ D3DTEXF_ANISOTROPIC = 3, // anisotropic
+*/
+
+static GLenum dxtogl_magFilter[4] = // indexed by _D3DTEXTUREFILTERTYPE
+{
+ GL_NEAREST, // D3DTEXF_NONE not applicable to mag filter but we handle it like POINT (mat_showmiplevels hits this)
+ GL_NEAREST, // D3DTEXF_POINT
+ GL_LINEAR, // D3DTEXF_LINEAR
+ GL_LINEAR, // D3DTEXF_ANISOTROPIC (aniso will be driven by setting maxAniso, not by a GL filter mode)
+};
+
+static GLenum dxtogl_minFilter[4][4] = // indexed by _D3DTEXTUREFILTERTYPE on both axes: [row is min filter][col is mip filter].
+{
+ // mip filter ---------------> D3DTEXF_NONE D3DTEXF_POINT D3DTEXF_LINEAR (D3DTEXF_ANISOTROPIC not applicable to mip filter)
+ /* min = D3DTEXF_NONE */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, // D3DTEXF_NONE we just treat like POINT
+ /* min = D3DTEXF_POINT */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 },
+ /* min = D3DTEXF_LINEAR */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 },
+ /* min = D3DTEXF_ANISOTROPIC */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, // no diff from prior row, set maxAniso to effect the sampling
+};
+
+HRESULT IDirect3DDevice9::FlushSamplers( uint mask )
+{
+ // a minor optimization we could do here would be to only write sampler state for
+ // TMU's that are active (i.e. consult m_textures)
+ uint activeSamplerMask = m_pixelShader ? m_pixelShader->m_pixSamplerMask : 0; // if no pixel shader bound at time of draw, act like it references no samplers
+ // (and avoid an access violation while yer at it)
+
+ // ho, we're not clearing the dirty mask for samplers as we go... need to do that...
+ uint samplerHitMask = gl.m_samplerDirtyMask & mask;
+ for( int index = 0; (index < 16) && (samplerHitMask !=0); index++)
+ {
+ uint bitMask = 1<m_addressModes[0] = dxtogl_addressMode[ dxsamp->m_addressModes[0] ];
+ glsamp->m_addressModes[1] = dxtogl_addressMode[ dxsamp->m_addressModes[1] ];
+ glsamp->m_addressModes[2] = dxtogl_addressMode[ dxsamp->m_addressModes[2] ];
+
+ // border color
+ uint dxcolor = dxsamp->m_borderColor;
+ glsamp->m_borderColor[0] = ((dxcolor >> 16) & 0xFF) / 255.0f; //R
+ glsamp->m_borderColor[1] = ((dxcolor >> 8) & 0xFF) / 255.0f; //G
+ glsamp->m_borderColor[2] = ((dxcolor ) & 0xFF) / 255.0f; //B
+ glsamp->m_borderColor[3] = ((dxcolor >> 24) & 0xFF) / 255.0f; //A
+
+ // filter state
+
+ // mag filter - pretty easy
+ Assert( dxsamp->m_magFilter <= D3DTEXF_ANISOTROPIC );
+ Assert( dxsamp->m_magFilter >= D3DTEXF_POINT );
+
+ glsamp->m_magFilter = dxtogl_magFilter[ dxsamp->m_magFilter ];
+
+ // min filter - more involved
+ Assert( dxsamp->m_minFilter <= D3DTEXF_ANISOTROPIC );
+ Assert( dxsamp->m_minFilter >= D3DTEXF_POINT );
+ Assert( dxsamp->m_mipFilter <= D3DTEXF_LINEAR );
+ Assert( dxsamp->m_mipFilter >= D3DTEXF_NONE );
+
+ D3DTEXTUREFILTERTYPE mipFilterLimit = D3DTEXF_LINEAR;
+
+ /*
+ if (GLMKnob("caps-key",NULL) > 0.0)
+ {
+ if (dxsamp->m_mipFilter > D3DTEXF_NONE)
+ {
+ // evil hack
+ glsamp->m_magFilter = GL_LINEAR_MIPMAP_NEAREST;
+ }
+ }
+
+ if (GLMKnob("option-key",NULL) > 0.0)
+ {
+ // limit to point
+ mipFilterLimit = D3DTEXF_POINT;
+ }
+
+ if (GLMKnob("control-key",NULL) > 0.0)
+ {
+ // limit to none
+ mipFilterLimit = D3DTEXF_NONE;
+ }
+ */
+
+ D3DTEXTUREFILTERTYPE mipFilterChoice = std::min( dxsamp->m_mipFilter, mipFilterLimit );
+ glsamp->m_minFilter = dxtogl_minFilter[ dxsamp->m_minFilter ][ mipFilterChoice ];
+
+ // should we check for mip filtering being requested on unmipped textures ? does it matter ?
+
+ // mipmap bias
+ glsamp->m_mipmapBias = dxsamp->m_mipmapBias;
+
+ // d3d "MAX MIP LEVEL" means the *largest size* MIP that will be selected. (max size)
+ // this is the same as GL's "MIN LOD level" which means the GL_TEXTURE_MIN_LOD level. (min index)
+
+ int texMipCount = m_textures[index]->m_tex->m_layout->m_mipCount;
+ Assert( texMipCount >=1 );
+
+ glsamp->m_minMipLevel = dxsamp->m_maxMipLevel; // it says gl_minMipLevel because we're setting GL's "GL_TEXTURE_MIN_LOD" aka d3d's "maximum mip size index".
+ if (glsamp->m_minMipLevel >= texMipCount)
+ {
+ // clamp - you can't have the GL base tex level be higher than the index of the last mip
+ glsamp->m_minMipLevel = texMipCount - 1;
+ }
+
+ // d3d has no idea of a "MIN MIP LEVEL" i.e. smallest size allowed.
+ // this would be expressed in GL by setting the GL_TEXTURE_MIN_LOD meaning largest index to select.
+ // for now, just set it to the index of the last mip.
+ glsamp->m_maxMipLevel = texMipCount-1; // d3d has no value for constraining how small we can sample.
+ // however we may need to set this more intelligently if textures are not being fully submitted.
+
+ // aniso, and check for questionable combinations
+ Assert( ((dxsamp->m_minFilter == D3DTEXF_ANISOTROPIC) && (dxsamp->m_maxAniso >= 1)) || ((dxsamp->m_minFilter < D3DTEXF_ANISOTROPIC) && (dxsamp->m_maxAniso >= 1)) );
+ glsamp->m_maxAniso = dxsamp->m_maxAniso;
+
+ // SRGB
+ glsamp->m_srgb = dxsamp->m_srgb != 0;
+
+ // write that sampler.
+ m_ctx->SetSamplerParams( index, glsamp );
+ samplerHitMask ^= mask; //turn bit off
+
+ // finally, if the SRGB state of the sampler does not match the SRGB format of the underlying texture...
+ // ... and the tex is not a renderable...
+ // ... and it is possible to re-submit the tex in an sRGB format...
+
+ // ******** AND THE TEX IS ACTUALLY REFERENCED BY THE ACTIVE PIXEL SHADER *******
+
+ // fix it.
+ // else complain ?
+
+ if (mask & activeSamplerMask) // don't do SRGB check on unreferenced textures.
+ {
+ bool texsrgb = (m_textures[index]->m_tex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0;
+ bool mismatch = (texsrgb != glsamp->m_srgb);
+ bool mismatchFixed = false;
+ bool srgbCapableTex = false; // not yet known
+ bool renderableTex = false; // not yet known.
+
+ if (mismatch)
+ {
+ srgbCapableTex = m_textures[index]->m_tex->m_layout->m_format->m_glIntFormatSRGB != 0;
+ renderableTex = (m_textures[index]->m_tex->m_layout->m_key.m_texFlags & kGLMTexRenderable) != 0;
+ // we can fix it if it's not a renderable, and an sRGB enabled format variation is available.
+
+ if (srgbCapableTex && !renderableTex)
+ {
+ const char *texname = m_textures[index]->m_tex->m_debugLabel;
+ if (!texname) texname = "-";
+
+ m_textures[index]->m_srgbFlipCount++;
+
+ //policy: print the ones that have flipped 1 or N times
+ bool print_allflips = false; //CommandLine()->FindParm("-glmspewallsrgbflips");
+ bool print_firstflips = false; //CommandLine()->FindParm("-glmspewfirstsrgbflips");
+ bool print_freqflips = false; //CommandLine()->FindParm("-glmspewfreqsrgbflips");
+ bool print_crawls = false; //CommandLine()->FindParm("-glmspewsrgbcrawls");
+ bool print_maxcrawls = false; //CommandLine()->FindParm("-glmspewsrgbmaxcrawls");
+ bool print_it = false;
+
+ if (print_allflips)
+ {
+ print_it = true;
+ }
+ if (print_firstflips) // report on first flip
+ {
+ print_it |= m_textures[index]->m_srgbFlipCount==1;
+ }
+ if (print_freqflips) // report on 50th flip
+ {
+ print_it |= m_textures[index]->m_srgbFlipCount==50;
+ }
+
+ if ( print_it )
+ {
+ const char *formatStr = "srgb change (samp=%d): tex '%-30s' %08x %s (srgb=%d, %d times)";
+
+ if (strlen(texname) >= 30)
+ {
+ formatStr = "srgb change (samp=%d): tex '%s' %08x %s (srgb=%d, %d times)";
+ }
+
+ printf( "\n" );
+ printf( formatStr, index, texname, m_textures[index], m_textures[index]->m_tex->m_layout->m_layoutSummary, (int)glsamp->m_srgb, m_textures[index]->m_srgbFlipCount );
+
+ #if 0 // stack crawling not implemented in steamworks example
+ if (print_crawls)
+ {
+ static char *interesting_crawl_substrs[] = { "CShader::OnDrawElements", NULL }; // add more as needed
+
+ CStackCrawlParams cp;
+ memset( &cp, 0, sizeof(cp) );
+ cp.m_frameLimit = 20;
+
+ g_extCocoaMgr->GetStackCrawl(&cp);
+
+ for( int i=0; i< cp.m_frameCount; i++)
+ {
+ // for each row of crawl, decide if name is interesting
+ bool hit = print_maxcrawls;
+
+ for( char **match = interesting_crawl_substrs; (!hit) && (*match != NULL); match++)
+ {
+ if (strstr(cp.m_crawlNames[i], *match))
+ {
+ hit = true;
+ }
+ }
+
+ if (hit)
+ {
+ printf( "\n\t%s", cp.m_crawlNames[i] );
+ }
+ }
+ printf( "\n");
+ }
+ #endif
+ }
+
+ #if GLMDEBUG && 0
+ //"toi" = texture of interest
+ static char s_toi[256] = "colorcorrection";
+ if (strstr( texname, s_toi ))
+ {
+ // breakpoint on this if you like
+ GLMPRINTF(( "srgb change %d for %s", m_textures[index]->m_srgbFlipCount, texname ));
+ }
+ #endif
+
+ // re-submit the tex unless we're stifling it
+ if ( 1 /* !CommandLine()->FindParm( "-glmnosrgbflips" ) */ )
+ {
+ m_textures[index]->m_tex->ResetSRGB( glsamp->m_srgb, false );
+ }
+ }
+ else
+ {
+ //GLMPRINTF(("-Z- srgb sampling conflict: NOT fixing tex %08x [%s] (srgb req: %d) because (tex-srgb-capable=%d tex-renderable=%d)", m_textures[index], m_textures[index]->m_tex->m_layout->m_layoutSummary, (int)glsamp->m_srgb, (int)srgbCapableTex, (int)renderableTex ));
+ // we just leave the sampler state where it is, and that's life
+ }
+ }
+ }
+
+ glsamp->m_compareMode = dxsamp->m_shadowFilter ? GL_COMPARE_R_TO_TEXTURE_ARB : GL_NONE;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::FlushIndexBindings( void )
+{
+ // push index buffer state
+ m_ctx->SetIndexBuffer( m_indices.m_idxBuffer->m_idxBuffer );
+
+ return S_OK;
+}
+
+#if 0
+HRESULT IDirect3DDevice9::FlushVertexBindings( void )
+{
+ // push vertex buffer state for the current vertex decl
+
+ GLMVertexSetup setup;
+ IDirect3DVertexDeclaration9 *vxdecl = m_vertDecl;
+
+ memset( &setup, 0, sizeof( setup ) );
+
+ // see if the elems in the vertex decl match the attrib map of the shader we're about to draw with.
+ // can we do this in a simple style that handles both matched and unmatched orderings?
+ // just pick up each elem from the decl.
+ // visit the same slot in the shader attrib map.
+ // if the usage/usageindex matches, you're good.
+ // if not, hunt through the shader attrib map and find it.
+ // if you can't find it, then the shader is not consuming that attribute - odd but not fatal ?
+ // the serious one is shader trying to consume an attrib that isn't being sourced.
+ // we can check for that though with a little more work (copy the shader attrib map and mark the attribs as each one gets satisfied)
+
+ unsigned char vshAttribMap[ 16 ];
+ uint activeAttribCount = 0;
+ for( int i=0; i<16; i++)
+ {
+ vshAttribMap[i] = m_vertexShader->m_vtxAttribMap[i];
+ if (vshAttribMap[i] != 0xBB)
+ {
+ activeAttribCount++; // this counting could be done at shader creation time, or changed to a mask
+ }
+ }
+
+ for( int elemIndex=0; elemIndexm_elemCount; elemIndex++)
+ {
+ D3DVERTEXELEMENT9_GL *srcelem = &vxdecl->m_elements[elemIndex];
+
+ int matchIndex = elemIndex; // initial guess - will iterate if this does not match
+ int tries = 0; // >16 means done
+ bool matched = false;
+
+ do
+ {
+ if ( ((vshAttribMap[matchIndex] >>4) == srcelem->m_dxdecl.Usage) && ((vshAttribMap[matchIndex] & 0x0F) == srcelem->m_dxdecl.UsageIndex) )
+ {
+ // hit
+ int attribIndex = matchIndex;
+ int streamIndex = srcelem->m_dxdecl.Stream;
+
+ GLMVertexAttributeDesc *dstAttr = &setup.m_attrs[ matchIndex ];
+
+ // copy whole thing
+ *dstAttr = srcelem->m_gldecl;
+
+ // then fix buffer, stride, offset
+ dstAttr->m_buffer = m_streams[ streamIndex ].m_vtxBuffer->m_vtxBuffer;
+ dstAttr->m_stride = m_streams[ streamIndex ].m_stride;
+ dstAttr->m_offset += m_streams[ streamIndex ].m_offset;
+
+ // set mask
+ setup.m_attrMask |= (1<FindParm("-hushasserts") */)
+ {
+ AssertOnce( !"Vertex shader not consuming attribs that are sourced by decl");
+ }
+ }
+ }
+
+ if (activeAttribCount >0)
+ {
+ // this one is more serious
+ if (1 /*!CommandLine()->FindParm("-hushasserts") */)
+ {
+ Assert( !"Vertex shader consuming attribs not sourced by decl");
+ }
+ }
+
+ // pass the whole shebang to GLM
+ m_ctx->SetVertexAttributes( &setup );
+}
+#endif
+
+
+HRESULT IDirect3DDevice9::FlushVertexBindings( uint baseVertexIndex )
+{
+ // push vertex buffer state for the current vertex decl
+ // in this variant we just walk the attrib map in the VS and do a pull for each one.
+ // if we can't find a match in the vertex decl, we may fall back to the secret 'dummy' VBO that GLM maintains
+
+ GLMVertexSetup setup;
+ memset( &setup, 0, sizeof( setup ) );
+
+ IDirect3DVertexDeclaration9 *vxdecl = m_vertDecl;
+ unsigned char *vshAttribMap = m_vertexShader->m_vtxAttribMap;
+
+ // this loop could be tightened if we knew the number of live entries in the shader attrib map.
+ // which of course would be easy to do in the create shader function or even in the translator.
+
+ GLMVertexAttributeDesc *dstAttr = setup.m_attrs;
+ for( int i=0; i<16; i++,dstAttr++ )
+ {
+ unsigned char vshattrib = vshAttribMap[ i ];
+ if (vshattrib != 0xBB)
+ {
+ // try to find the match in the decl.
+ // idea: put some inverse table in the decl which could accelerate this search.
+
+ D3DVERTEXELEMENT9_GL *elem = m_vertDecl->m_elements;
+ for( int j=0; j< m_vertDecl->m_elemCount; j++,elem++)
+ {
+ // if it matches, install it, change vshattrib so the code below does not trigger, then end the loop
+ if ( ((vshattrib>>4) == elem->m_dxdecl.Usage) && ((vshattrib & 0x0F) == elem->m_dxdecl.UsageIndex) )
+ {
+ // targeting attribute #i in the setup with element data #j from the decl
+
+ *dstAttr = elem->m_gldecl;
+
+ // then fix buffer, stride, offset - note that we honor the base vertex index here by fiddling the offset
+ int streamIndex = elem->m_dxdecl.Stream;
+ dstAttr->m_buffer = m_streams[ streamIndex ].m_vtxBuffer->m_vtxBuffer;
+ dstAttr->m_stride = m_streams[ streamIndex ].m_stride;
+ dstAttr->m_offset += m_streams[ streamIndex ].m_offset + (baseVertexIndex * dstAttr->m_stride);
+
+ // set mask
+ setup.m_attrMask |= (1<m_buffer = NULL;
+ dstAttr->m_stride = 0;
+ dstAttr->m_offset = 0;
+
+ // only implement certain usages... if we haven't seen it before, stop.
+ switch( vshattrib >>4 ) // aka usage
+ {
+ case D3DDECLUSAGE_POSITION:
+ case D3DDECLUSAGE_BLENDWEIGHT:
+ case D3DDECLUSAGE_BLENDINDICES:
+ Debugger();
+ break;
+
+ case D3DDECLUSAGE_NORMAL:
+ dstAttr->m_datasize = 3;
+ dstAttr->m_datatype = GL_FLOAT;
+ dstAttr->m_normalized = false;
+ break;
+
+ case D3DDECLUSAGE_PSIZE:
+ Debugger();
+ break;
+
+ case D3DDECLUSAGE_TEXCOORD:
+ dstAttr->m_datasize = 3;
+ dstAttr->m_datatype = GL_FLOAT;
+ dstAttr->m_normalized = false;
+ break;
+
+ case D3DDECLUSAGE_TANGENT:
+ case D3DDECLUSAGE_BINORMAL:
+ case D3DDECLUSAGE_TESSFACTOR:
+ case D3DDECLUSAGE_PLUGH:
+ Debugger();
+ break;
+
+ case D3DDECLUSAGE_COLOR:
+ dstAttr->m_datasize = 4;
+ dstAttr->m_datatype = GL_UNSIGNED_BYTE;
+ dstAttr->m_normalized = true;
+ break;
+
+ case D3DDECLUSAGE_FOG:
+ case D3DDECLUSAGE_DEPTH:
+ case D3DDECLUSAGE_SAMPLE:
+ Debugger();
+ break;
+ }
+ }
+ }
+ }
+
+ // copy active program's vertex attrib map into the vert setup info
+ memcpy( &setup.m_vtxAttribMap, m_vertexShader->m_vtxAttribMap, sizeof( m_vertexShader->m_vtxAttribMap ) );
+
+ m_ctx->SetVertexAttributes( &setup );
+
+ return S_OK;
+}
+
+
+
+HRESULT IDirect3DDevice9::FlushGLM( void )
+{
+ Debugger();// old routine not used now
+ return D3DERR_INVALIDCALL;
+}
+
+HRESULT IDirect3DDevice9::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,UINT StartVertex,UINT PrimitiveCount)
+{
+ this->FlushStates( 0xFFFFFFFF );
+ this->FlushSamplers( 0xFFFFFFFF );
+ //this->FlushIndexBindings( ); //indices not really used..
+ this->FlushVertexBindings( 0 /*StartVertex*/ ); //no stream base offsetting for drawarrays mode
+ m_ctx->FlushDrawStates( true );
+
+ switch(PrimitiveType)
+ {
+ case D3DPT_POINTLIST:
+ m_ctx->DrawArrays( (GLenum)GL_POINTS, StartVertex, (GLsizei)PrimitiveCount );
+ break;
+
+ case D3DPT_LINELIST:
+ m_ctx->DrawArrays( (GLenum)GL_LINES, StartVertex, (GLsizei)PrimitiveCount*2 );
+ break;
+
+ case D3DPT_TRIANGLELIST:
+ m_ctx->DrawArrays( (GLenum)GL_TRIANGLES, StartVertex, (GLsizei)PrimitiveCount*3 );
+ break;
+
+ case D3DPT_TRIANGLESTRIP:
+ m_ctx->DrawArrays( (GLenum)GL_TRIANGLE_STRIP, StartVertex, (GLsizei)PrimitiveCount+2 );
+ break;
+
+ default:
+ break;
+ }
+
+ return S_OK;
+}
+
+// Type
+// [in] Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method. See Remarks.
+
+// BaseVertexIndex
+// [in] Offset from the start of the vertex buffer to the first vertex. See Scenario 4.
+
+// MinIndex
+// [in] Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
+
+// NumVertices
+// [in] Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
+
+// StartIndex
+// [in] Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
+
+// PrimitiveCount
+// [in] Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type. The maximum number of primitives allowed is determined by checking the MaxPrimitiveCount member of the D3DCAPS9 structure.
+
+
+HRESULT IDirect3DDevice9::DrawIndexedPrimitive( D3DPRIMITIVETYPE Type,INT BaseVertexIndex,UINT MinVertexIndex,UINT NumVertices,UINT startIndex,UINT primCount )
+{
+ this->FlushStates( 0xFFFFFFFF );
+
+ this->FlushSamplers( 0xFFFFFFFF );
+
+ this->FlushIndexBindings( );
+ this->FlushVertexBindings( BaseVertexIndex );
+ m_ctx->FlushDrawStates( true );
+
+ if (gl.m_FogEnable)
+ {
+ GLMPRINTF(("-D- IDirect3DDevice9::DrawIndexedPrimitive is seeing enabled fog..."));
+ }
+
+ switch(Type)
+ {
+ case D3DPT_POINTLIST:
+ Debugger();
+ break;
+
+ case D3DPT_LINELIST:
+ GLMPRINTF(("-X- IDirect3DDevice9::DrawIndexedPrimitive( D3DPT_LINELIST ) - ignored."));
+// Debugger();
+ m_ctx->DrawRangeElements( (GLenum)GL_LINES, (GLuint)MinVertexIndex, (GLuint)(MinVertexIndex + NumVertices), (GLsizei)primCount*2, (GLenum)GL_UNSIGNED_SHORT, (const GLvoid *)(startIndex * sizeof(short)) );
+ break;
+
+ case D3DPT_TRIANGLELIST:
+ m_ctx->DrawRangeElements(GL_TRIANGLES, (GLuint)MinVertexIndex, (GLuint)(MinVertexIndex + NumVertices), (GLsizei)primCount*3, (GLenum)GL_UNSIGNED_SHORT, (const GLvoid *)(startIndex * sizeof(short)) );
+ break;
+
+ case D3DPT_TRIANGLESTRIP:
+ // enabled... Debugger();
+ m_ctx->DrawRangeElements(GL_TRIANGLE_STRIP, (GLuint)MinVertexIndex, (GLuint)(MinVertexIndex + NumVertices), (GLsizei)(2+primCount), (GLenum)GL_UNSIGNED_SHORT, (const GLvoid *)(startIndex * sizeof(short)) );
+ break;
+
+ default:
+ break;
+ }
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,UINT MinVertexIndex,UINT NumVertices,UINT PrimitiveCount,CONST void* pIndexData,D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride)
+{
+ this->FlushStates( 0xFFFFFFFF );
+
+ Debugger();
+ return S_OK;
+}
+
+
+
+
+BOOL IDirect3DDevice9::ShowCursor(BOOL bShow)
+{
+ // FIXME NOP
+ //Debugger();
+ return TRUE;
+}
+
+void d3drect_to_glmbox( D3DRECT *src, GLScissorBox_t *dst )
+{
+ // to convert from a d3d rect to a GL rect you have to fix up the vertical axis, since D3D Y=0 is the top, but GL Y=0 is the bottom.
+ // you can't fix it without knowing the height.
+
+ dst->width = src->x2 - src->x1;
+ dst->x = src->x1; // left edge
+
+ dst->height = src->y2 - src->y1;
+ dst->y = src->y1; // bottom edge - take large Y from d3d and subtract from surf height.
+}
+
+HRESULT IDirect3DDevice9::Clear(DWORD Count,CONST D3DRECT* pRects,DWORD Flags,D3DCOLOR Color,float Z,DWORD Stencil)
+{
+
+ this->FlushStates( (1<FlushDrawStates( false );
+
+
+ // for debug Color = (rand() | 0xFF0000FF) & 0xFF3F3FFF;
+ if (!Count)
+ {
+ // run clear with no added rectangle
+ m_ctx->Clear( (Flags&D3DCLEAR_TARGET)!=0, Color,
+ (Flags&D3DCLEAR_ZBUFFER)!=0, Z,
+ (Flags&D3DCLEAR_STENCIL)!=0, Stencil,
+ NULL
+ );
+ }
+ else
+ {
+ GLScissorBox_t tempbox;
+
+ // do the rects one by one and convert each one to GL form
+ for( int i=0; iClear( (Flags&D3DCLEAR_TARGET)!=0, Color,
+ (Flags&D3DCLEAR_ZBUFFER)!=0, Z,
+ (Flags&D3DCLEAR_STENCIL)!=0, Stencil,
+ &tempbox
+ );
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix)
+{
+ Debugger();
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetTextureStageState(DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD Value)
+{
+ Debugger();
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::ValidateDevice(DWORD* pNumPasses)
+{
+ Debugger();
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9* pMaterial)
+{
+ GLMPRINTF(("-X- IDirect3DDevice9::SetMaterial - ignored."));
+// Debugger();
+ return S_OK;
+}
+
+
+HRESULT IDirect3DDevice9::LightEnable(DWORD Index,BOOL Enable)
+{
+ Debugger();
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetScissorRect(CONST RECT* pRect)
+{
+ int nSurfaceHeight = m_drawableFBO->m_attach[ kAttColor0 ].m_tex->m_layout->m_key.m_ySize;
+
+ GLScissorBox_t newScissorBox = { (GLint)pRect->left, (GLint)pRect->top, (GLint)(pRect->right - pRect->left), (GLint)(pRect->bottom - pRect->top) };
+ gl.m_ScissorBox = newScissorBox;
+ gl.m_stateDirtyMask |= (1<SetVertexShaderConstantF( DXABSTRACT_VS_CLIP_PLANE_BASE+Index, pPlane, 1 ); // stash the clip plane values into shader param - translator knows where to look
+ }
+
+ // if GLSL mode... latch it and let FlushStates push it out
+ {
+ GLClipPlaneEquation_t peq;
+ peq.x = pPlane[0];
+ peq.y = pPlane[1];
+ peq.z = pPlane[2];
+ peq.w = pPlane[3];
+
+ gl.m_ClipPlaneEquation[ Index ] = peq;
+ gl.m_stateDirtyMask |= (1<WriteClipPlaneEquation( &peq, Index );
+ }
+
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::EvictManagedResources()
+{
+ GLMPRINTF(("-X- IDirect3DDevice9::EvictManagedResources --> IGNORED"));
+ return S_OK;
+}
+
+HRESULT IDirect3DDevice9::SetLight(DWORD Index,CONST D3DLIGHT9*)
+{
+ Debugger();
+ return S_OK;
+}
+
+void IDirect3DDevice9::SetGammaRamp(UINT iSwapChain,DWORD Flags,CONST D3DGAMMARAMP* pRamp)
+{
+ // just slam it directly for the time being
+ // this code is OS X specific
+
+ CGDisplayErr cgErr;
+ (void)cgErr;
+
+ CGGammaValue redt[256];
+ CGGammaValue grnt[256];
+ CGGammaValue blut[256];
+ for( int i=0; i<256; i++)
+ {
+ redt[i] = ((float)pRamp->red[i]) / 65535.0f;
+ grnt[i] = ((float)pRamp->green[i]) / 65535.0f;
+ blut[i] = ((float)pRamp->blue[i]) / 65535.0f;
+ }
+ cgErr = CGSetDisplayTransferByTable( 0, 256, redt, grnt, blut );
+
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+void* ID3DXBuffer::GetBufferPointer()
+{
+ Debugger();
+ return NULL;
+}
+
+DWORD ID3DXBuffer::GetBufferSize()
+{
+ Debugger();
+ return 0;
+}
+
+
+
+#if 0 //d3dx not provided in steamworks example
+
+#pragma mark ----- More D3DX stuff
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+// D3DX stuff.
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+// matrix stack...
+
+HRESULT D3DXCreateMatrixStack( DWORD Flags, LPD3DXMATRIXSTACK* ppStack)
+{
+
+ *ppStack = new ID3DXMatrixStack;
+
+ (*ppStack)->Create();
+
+ return S_OK;
+}
+
+HRESULT ID3DXMatrixStack::Create()
+{
+ m_stack.EnsureCapacity( 16 ); // 1KB ish
+ m_stack.AddToTail();
+ m_stackTop = 0; // top of stack is at index 0 currently
+
+ LoadIdentity();
+
+ return S_OK;
+}
+
+D3DXMATRIX* ID3DXMatrixStack::GetTop()
+{
+ return (D3DXMATRIX*)&m_stack[ m_stackTop ];
+}
+
+void ID3DXMatrixStack::Push()
+{
+ D3DMATRIX temp = m_stack[ m_stackTop ];
+ m_stack.AddToTail( temp );
+ m_stackTop ++;
+}
+
+void ID3DXMatrixStack::Pop()
+{
+ int elem = m_stackTop--;
+ m_stack.Remove( elem );
+}
+
+void ID3DXMatrixStack::LoadIdentity()
+{
+ D3DXMATRIX *mat = GetTop();
+
+ D3DXMatrixIdentity( mat );
+}
+
+void ID3DXMatrixStack::LoadMatrix( const D3DXMATRIX *pMat )
+{
+ *(GetTop()) = *pMat;
+}
+
+
+void ID3DXMatrixStack::MultMatrix( const D3DXMATRIX *pMat )
+{
+
+ // http://msdn.microsoft.com/en-us/library/bb174057(VS.85).aspx
+ // This method right-multiplies the given matrix to the current matrix
+ // (transformation is about the current world origin).
+ // m_pstack[m_currentPos] = m_pstack[m_currentPos] * (*pMat);
+ // This method does not add an item to the stack, it replaces the current
+ // matrix with the product of the current matrix and the given matrix.
+
+
+ Debugger();
+}
+
+void ID3DXMatrixStack::MultMatrixLocal( const D3DXMATRIX *pMat )
+{
+ // http://msdn.microsoft.com/en-us/library/bb174058(VS.85).aspx
+ // This method left-multiplies the given matrix to the current matrix
+ // (transformation is about the local origin of the object).
+ // m_pstack[m_currentPos] = (*pMat) * m_pstack[m_currentPos];
+ // This method does not add an item to the stack, it replaces the current
+ // matrix with the product of the given matrix and the current matrix.
+
+
+ Debugger();
+}
+
+HRESULT ID3DXMatrixStack::ScaleLocal(FLOAT x, FLOAT y, FLOAT z)
+{
+ // http://msdn.microsoft.com/en-us/library/bb174066(VS.85).aspx
+ // Scale the current matrix about the object origin.
+ // This method left-multiplies the current matrix with the computed
+ // scale matrix. The transformation is about the local origin of the object.
+ //
+ // D3DXMATRIX tmp;
+ // D3DXMatrixScaling(&tmp, x, y, z);
+ // m_stack[m_currentPos] = tmp * m_stack[m_currentPos];
+
+ Debugger();
+}
+
+
+HRESULT ID3DXMatrixStack::RotateAxisLocal(CONST D3DXVECTOR3* pV, FLOAT Angle)
+{
+ // http://msdn.microsoft.com/en-us/library/bb174062(VS.85).aspx
+ // Left multiply the current matrix with the computed rotation
+ // matrix, counterclockwise about the given axis with the given angle.
+ // (rotation is about the local origin of the object)
+
+ // D3DXMATRIX tmp;
+ // D3DXMatrixRotationAxis( &tmp, pV, angle );
+ // m_stack[m_currentPos] = tmp * m_stack[m_currentPos];
+ // Because the rotation is left-multiplied to the matrix stack, the rotation
+ // is relative to the object's local coordinate space.
+
+ Debugger();
+}
+
+HRESULT ID3DXMatrixStack::TranslateLocal(FLOAT x, FLOAT y, FLOAT z)
+{
+ // http://msdn.microsoft.com/en-us/library/bb174068(VS.85).aspx
+ // Left multiply the current matrix with the computed translation
+ // matrix. (transformation is about the local origin of the object)
+
+ // D3DXMATRIX tmp;
+ // D3DXMatrixTranslation( &tmp, x, y, z );
+ // m_stack[m_currentPos] = tmp * m_stack[m_currentPos];
+
+ Debugger();
+}
+
+
+
+
+const char* D3DXGetPixelShaderProfile( IDirect3DDevice9 *pDevice )
+{
+ Debugger();
+ return "";
+}
+
+
+D3DXMATRIX* D3DXMatrixMultiply( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM1, CONST D3DXMATRIX *pM2 )
+{
+ D3DXMATRIX temp;
+
+ for( int i=0; i<4; i++)
+ {
+ for( int j=0; j<4; j++)
+ {
+ temp.m[i][j] = (pM1->m[ i ][ 0 ] * pM2->m[ 0 ][ j ])
+ + (pM1->m[ i ][ 1 ] * pM2->m[ 1 ][ j ])
+ + (pM1->m[ i ][ 2 ] * pM2->m[ 2 ][ j ])
+ + (pM1->m[ i ][ 3 ] * pM2->m[ 3 ][ j ]);
+ }
+ }
+ *pOut = temp;
+ return pOut;
+}
+
+D3DXVECTOR3* D3DXVec3TransformCoord( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, CONST D3DXMATRIX *pM ) // http://msdn.microsoft.com/en-us/library/ee417622(VS.85).aspx
+{
+ // this one is tricky because
+ // "Transforms a 3D vector by a given matrix, projecting the result back into w = 1".
+ // but the vector has no W attached to it coming in, so we have to go through the motions of figuring out what w' would be
+ // assuming the input vector had a W of 1.
+
+ // dot product of [a b c 1] against w column
+ float wp = (pM->m[3][0] * pV->x) + (pM->m[3][1] * pV->y) + (pM->m[3][2] * pV->z) + (pM->m[3][3]);
+
+ if (wp == 0.0f )
+ {
+ // do something to avoid dividing by zero..
+ Debugger();
+ }
+ else
+ {
+ // unclear on whether I should include the fake W in the sum (last term) before dividing by wp... hmmmm
+ // leave it out for now and see how well it works
+ pOut->x = ((pM->m[0][0] * pV->x) + (pM->m[0][1] * pV->y) + (pM->m[0][2] * pV->z) /* + (pM->m[0][3]) */ ) / wp;
+ pOut->y = ((pM->m[1][0] * pV->x) + (pM->m[1][1] * pV->y) + (pM->m[1][2] * pV->z) /* + (pM->m[1][3]) */ ) / wp;
+ pOut->z = ((pM->m[2][0] * pV->x) + (pM->m[2][1] * pV->y) + (pM->m[2][2] * pV->z) /* + (pM->m[2][3]) */ ) / wp;
+ }
+
+ return pOut;
+}
+
+
+void D3DXMatrixIdentity( D3DXMATRIX *mat )
+{
+ for( int i=0; i<4; i++)
+ {
+ for( int j=0; j<4; j++)
+ {
+ mat->m[i][j] = (i==j) ? 1.0f : 0.0f; // 1's on the diagonal.
+ }
+ }
+}
+
+D3DXMATRIX* D3DXMatrixTranslation( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z )
+{
+ D3DXMatrixIdentity( pOut );
+ pOut->m[3][0] = x;
+ pOut->m[3][1] = y;
+ pOut->m[3][2] = z;
+ return pOut;
+}
+
+D3DXMATRIX* D3DXMatrixInverse( D3DXMATRIX *pOut, FLOAT *pDeterminant, CONST D3DXMATRIX *pM )
+{
+ Assert( sizeof( D3DXMATRIX ) == (16 * sizeof(float) ) );
+ Assert( sizeof( VMatrix ) == (16 * sizeof(float) ) );
+ Assert( pDeterminant == NULL ); // homey don't play that
+
+ VMatrix *origM = (VMatrix*)pM;
+ VMatrix *destM = (VMatrix*)pOut;
+
+ bool success = MatrixInverseGeneral( *origM, *destM );
+ Assert( success );
+
+ return pOut;
+}
+
+
+D3DXMATRIX* D3DXMatrixTranspose( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM )
+{
+ if (pOut != pM)
+ {
+ for( int i=0; i<4; i++)
+ {
+ for( int j=0; j<4; j++)
+ {
+ pOut->m[i][j] = pM->m[j][i];
+ }
+ }
+ }
+ else
+ {
+ D3DXMATRIX temp = *pM;
+ D3DXMatrixTranspose( pOut, &temp );
+ }
+
+ return NULL;
+}
+
+
+D3DXPLANE* D3DXPlaneNormalize( D3DXPLANE *pOut, CONST D3DXPLANE *pP)
+{
+ // not very different from normalizing a vector.
+ // figure out the square root of the sum-of-squares of the x,y,z components
+ // make sure that's non zero
+ // then divide all four components by that value
+ // or return some dummy plane like 0,0,1,0 if it fails
+
+ float len = sqrt( (pP->a * pP->a) + (pP->b * pP->b) + (pP->c * pP->c) );
+ if (len > 1e-10) //FIXME need a real epsilon here ?
+ {
+ pOut->a = pP->a / len; pOut->b = pP->b / len; pOut->c = pP->c / len; pOut->d = pP->d / len;
+ }
+ else
+ {
+ pOut->a = 0.0f; pOut->b = 0.0f; pOut->c = 1.0f; pOut->d = 0.0f;
+ }
+ return pOut;
+}
+
+
+D3DXVECTOR4* D3DXVec4Transform( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV, CONST D3DXMATRIX *pM )
+{
+ VMatrix *mat = (VMatrix*)pM;
+ Vector4D *vIn = (Vector4D*)pV;
+ Vector4D *vOut = (Vector4D*)pOut;
+
+ Vector4DMultiplyTranspose( *mat, *vIn, *vOut );
+
+ return pOut;
+}
+
+
+
+D3DXVECTOR4* D3DXVec4Normalize( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV )
+{
+ Vector4D *vIn = (Vector4D*) pV;
+ Vector4D *vOut = (Vector4D*) pOut;
+
+ *vOut = *vIn;
+ Vector4DNormalize( *vOut );
+
+ return pOut;
+}
+
+
+D3DXMATRIX* D3DXMatrixOrthoOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn,FLOAT zf )
+{
+ Debugger();
+ return NULL;
+}
+
+
+D3DXMATRIX* D3DXMatrixPerspectiveRH( D3DXMATRIX *pOut, FLOAT w, FLOAT h, FLOAT zn, FLOAT zf )
+{
+ Debugger();
+ return NULL;
+}
+
+
+D3DXMATRIX* D3DXMatrixPerspectiveOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn, FLOAT zf )
+{
+ Debugger();
+ return NULL;
+}
+
+
+D3DXPLANE* D3DXPlaneTransform( D3DXPLANE *pOut, CONST D3DXPLANE *pP, CONST D3DXMATRIX *pM )
+{
+ float *out = &pOut->a;
+
+ // dot dot dot
+ for( int x=0; x<4; x++ )
+ {
+ out[x] = (pM->m[0][x] * pP->a)
+ + (pM->m[1][x] * pP->b)
+ + (pM->m[2][x] * pP->c)
+ + (pM->m[3][x] * pP->d);
+ }
+
+ return pOut;
+}
+
+void D3DPERF_SetOptions( DWORD dwOptions )
+{
+}
+
+
+HRESULT D3DXCompileShader(
+ LPCSTR pSrcData,
+ UINT SrcDataLen,
+ CONST D3DXMACRO* pDefines,
+ LPD3DXINCLUDE pInclude,
+ LPCSTR pFunctionName,
+ LPCSTR pProfile,
+ DWORD Flags,
+ LPD3DXBUFFER* ppShader,
+ LPD3DXBUFFER* ppErrorMsgs,
+ LPD3DXCONSTANTTABLE* ppConstantTable)
+{
+ Debugger(); // is anyone calling this ?
+ return S_OK;
+}
+
+#endif
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+IDirect3D9 *Direct3DCreate9(UINT SDKVersion)
+{
+ GLMPRINTF(( "-X- Direct3DCreate9: %d", SDKVersion ));
+
+ return new IDirect3D9;
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+
+#endif
+
diff --git a/My project/sdk/glmgr/dxabstract.h b/My project/sdk/glmgr/dxabstract.h
new file mode 100644
index 000000000..ff5058e87
--- /dev/null
+++ b/My project/sdk/glmgr/dxabstract.h
@@ -0,0 +1,2420 @@
+//================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. =================
+//
+//
+//
+//==================================================================================================
+
+#ifndef DXABSTRACT_H
+#define DXABSTRACT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//==================================================================================================
+
+// Source engine only #include "materialsystem/IShader.h"
+// constants below copied from that header
+
+// size of the VS register bank in ARB / GLSL we expose
+// it's not 256, because you can't use all 256 slots in 10.5.x.
+// use this constant everywhere you might normally use "256" in reference to a parameter array size.
+// The highest vertex shader constant is c216, plus we allocate c217 and c218 for two clip planes
+#define DXABSTRACT_VS_PARAM_SLOTS 219
+
+// user clip plane 0 goes in DXABSTRACT_VS_CLIP_PLANE_BASE... plane 1 goes in the slot after that
+// dxabstract uses these constants to check plane index limit and to deliver planes to shader for DP4 -> oCLP[n]
+#define DXABSTRACT_VS_CLIP_PLANE_BASE (DXABSTRACT_VS_PARAM_SLOTS-2)
+
+//==================================================================================================
+
+
+// Uncomment this on Windows if you want to compile the Windows GL version.
+// #undef USE_ACTUAL_DX
+
+#ifdef USE_ACTUAL_DX
+
+#ifndef WIN32
+#error sorry man
+#endif
+#ifdef _X360
+#include "d3d9.h"
+#include "d3dx9.h"
+#else
+#include
+#include "../../dx9sdk/include/d3d9.h"
+#include "../../dx9sdk/include/d3dx9.h"
+#endif
+typedef HWND VD3DHWND;
+
+#else
+
+#ifdef WIN32
+#error Gl on win32?
+#endif
+
+#define DX_TO_GL_ABSTRACTION
+
+#include "imageformat.h"
+#include "glmgr.h"
+
+extern "C" void Debugger(void);
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+// DEFINES
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+typedef void* VD3DHWND;
+typedef void* VD3DHANDLE;
+
+//
+//
+// Stuff that would be in windows.h
+//
+//
+#ifdef _WINNT_
+#error "No interoperability with windows.h!"
+#else
+
+#ifndef __stdcall
+#define __stdcall
+#endif
+
+ typedef int INT;
+ typedef unsigned long ULONG;
+ typedef long LONG;
+ typedef float FLOAT;
+ typedef unsigned int DWORD;
+ typedef unsigned short WORD;
+ typedef long long LONGLONG;
+ typedef unsigned int UINT;
+ typedef long HRESULT;
+ typedef unsigned char BYTE;
+ #define CONST const
+ typedef unsigned long ULONG_PTR;
+ typedef ULONG_PTR SIZE_T;
+ typedef signed char BOOL;
+
+ typedef const char* LPCSTR;
+ typedef char* LPSTR;
+ typedef DWORD* LPDWORD;
+
+ #define ZeroMemory RtlZeroMemory
+ #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
+
+ typedef union _LARGE_INTEGER {
+ struct {
+ DWORD LowPart;
+ LONG HighPart;
+ };
+ struct {
+ DWORD LowPart;
+ LONG HighPart;
+ } u;
+ LONGLONG QuadPart;
+ } LARGE_INTEGER;
+
+ /*
+ typedef struct _GUID {
+
+ bool operator==( const struct _GUID &other ) const;
+
+ unsigned long Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[ 8 ];
+ } GUID;
+ */
+
+#ifndef VALVE_RECT_DEFINED
+#define VALVE_RECT_DEFINED
+
+ typedef struct tagRECT
+ {
+ LONG left;
+ LONG top;
+ LONG right;
+ LONG bottom;
+ } RECT;
+
+ #define _RECT tagRECT
+#endif
+ // turn this on to get refcount logging from IUnknown
+
+ #define IUNKNOWN_ALLOC_SPEW 0
+ #define IUNKNOWN_ALLOC_SPEW_MARK_ALL 0
+
+ struct IUnknown
+ {
+ public:
+ int m_refcount[2];
+ bool m_mark;
+
+ IUnknown( void )
+ {
+ m_refcount[0] = 1;
+ m_refcount[1] = 0;
+ m_mark = (IUNKNOWN_ALLOC_SPEW_MARK_ALL != 0); // either all are marked, or only the ones that have SetMark(true) called on them
+
+ #if IUNKNOWN_ALLOC_SPEW
+ if (m_mark)
+ {
+ GLMPRINTF(("-A- IUnew (%08x) refc -> (%d,%d) ",this,m_refcount[0],m_refcount[1]));
+ }
+ #endif
+ };
+
+ virtual ~IUnknown( void )
+ {
+ #if IUNKNOWN_ALLOC_SPEW
+ if (m_mark)
+ {
+ GLMPRINTF(("-A- IUdel (%08x) ",this ));
+ }
+ #endif
+ };
+
+ void AddRef( int which=0, const char *comment = NULL )
+ {
+ Assert( which >= 0 );
+ Assert( which < 2 );
+ m_refcount[which]++;
+
+ #if IUNKNOWN_ALLOC_SPEW
+ if (m_mark)
+ {
+ GLMPRINTF(("-A- IUAddRef (%08x,%d) refc -> (%d,%d) [%s]",this,which,m_refcount[0],m_refcount[1],comment?comment:"...")) ;
+ if (!comment)
+ {
+ GLMPRINTF(("")) ; // place to hang a breakpoint
+ }
+ }
+ #endif
+ };
+
+ ULONG __stdcall Release( int which=0, const char *comment = NULL )
+ {
+ Assert( which >= 0 );
+ Assert( which < 2 );
+
+ //int oldrefcs[2] = { m_refcount[0], m_refcount[1] };
+ bool deleting = false;
+
+ m_refcount[which]--;
+ if ( (!m_refcount[0]) && (!m_refcount[1]) )
+ {
+ deleting = true;
+ }
+
+ #if IUNKNOWN_ALLOC_SPEW
+ if (m_mark)
+ {
+ GLMPRINTF(("-A- IURelease (%08x,%d) refc -> (%d,%d) [%s] %s",this,which,m_refcount[0],m_refcount[1],comment?comment:"...",deleting?"->DELETING":""));
+ if (!comment)
+ {
+ GLMPRINTF(("")) ; // place to hang a breakpoint
+ }
+ }
+ #endif
+
+ if (deleting)
+ {
+ if (m_mark)
+ {
+ GLMPRINTF(("")) ; // place to hang a breakpoint
+ }
+ delete this;
+ return 0;
+ }
+ else
+ {
+ return m_refcount[0];
+ }
+ };
+ void SetMark( bool markValue, char *comment=NULL )
+ {
+ #if IUNKNOWN_ALLOC_SPEW
+ if (!m_mark && markValue) // leading edge detect
+ {
+ // print the same thing that the constructor would have printed if it had been marked from the beginning
+ // i.e. it's anticipated that callers asking for marking will do so right at create time
+ GLMPRINTF(("-A- IUSetMark (%08x) refc -> (%d,%d) (%s) ",this,m_refcount[0],m_refcount[1],comment?comment:"..."));
+ }
+ #endif
+
+ m_mark = markValue;
+ }
+ };
+
+ typedef struct tagPOINT
+ {
+ LONG x;
+ LONG y;
+ } POINT, *PPOINT, *LPPOINT;
+
+ typedef struct _MEMORYSTATUS {
+ DWORD dwLength;
+ SIZE_T dwTotalPhys;
+ } MEMORYSTATUS, *LPMEMORYSTATUS;
+
+
+ typedef DWORD COLORREF;
+ #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
+
+ #define MAKE_HRESULT(sev,fac,code) \
+ ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
+
+ #define S_FALSE ((HRESULT)0x00000001L)
+ #define S_OK 0
+ #define E_OUTOFMEMORY ((HRESULT)(0x8007000EL))
+
+ #define FAILED(hr) ((HRESULT)(hr) < 0)
+ #define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
+
+ #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
+ ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
+ ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
+
+ struct RGNDATA
+ {
+ public:
+ };
+
+ void Sleep( unsigned int ms );
+ bool IsIconic( VD3DHWND hWnd );
+ void GetClientRect( VD3DHWND hWnd, RECT *destRect );
+ BOOL ClientToScreen( VD3DHWND hWnd, LPPOINT pPoint );
+
+ typedef const void* LPCVOID;
+
+ void* GetCurrentThread();
+ void SetThreadAffinityMask( void *hThread, int nMask );
+ void GlobalMemoryStatus( MEMORYSTATUS *pOut );
+
+#endif
+
+#define D3DSI_OPCODE_MASK 0x0000FFFF
+#define D3DSP_TEXTURETYPE_MASK 0x78000000
+
+#define D3DUSAGE_AUTOGENMIPMAP (0x00000400L)
+#define D3DSP_DCL_USAGE_MASK 0x0000000f
+
+#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000
+#define D3DSP_OPCODESPECIFICCONTROL_SHIFT 16
+
+
+/* Flags to construct D3DRS_COLORWRITEENABLE */
+#define D3DCOLORWRITEENABLE_RED (1L<<0)
+#define D3DCOLORWRITEENABLE_GREEN (1L<<1)
+#define D3DCOLORWRITEENABLE_BLUE (1L<<2)
+#define D3DCOLORWRITEENABLE_ALPHA (1L<<3)
+
+#define D3DSGR_NO_CALIBRATION 0x00000000L
+
+
+#define D3DXINLINE inline
+
+#define D3D_SDK_VERSION 32
+
+#define _FACD3D 0x876
+#define MAKE_D3DHRESULT( code ) MAKE_HRESULT( 1, _FACD3D, code )
+
+
+#define D3DERR_NOTFOUND MAKE_D3DHRESULT(2150)
+#define D3DERR_DEVICELOST MAKE_D3DHRESULT(2152)
+#define D3DERR_NOTAVAILABLE MAKE_D3DHRESULT(2154)
+#define D3DERR_DEVICENOTRESET MAKE_D3DHRESULT(2153)
+#define D3DERR_INVALIDCALL MAKE_D3DHRESULT(2156)
+#define D3DERR_DRIVERINTERNALERROR MAKE_D3DHRESULT(2087)
+#define D3DERR_OUTOFVIDEOMEMORY MAKE_D3DHRESULT(380)
+#define D3D_OK S_OK
+
+#define D3DPRESENT_RATE_DEFAULT 0x00000000
+
+//
+// DevCaps
+//
+ // we need to see who in Source land is interested in these values, as dxabstract is currently reporting zero for the whole Caps word
+#define D3DDEVCAPS_EXECUTESYSTEMMEMORY 0x00000010L /* Device can use execute buffers from system memory */
+#define D3DDEVCAPS_TLVERTEXSYSTEMMEMORY 0x00000040L /* Device can use TL buffers from system memory */
+#define D3DDEVCAPS_TLVERTEXVIDEOMEMORY 0x00000080L /* Device can use TL buffers from video memory */
+#define D3DDEVCAPS_TEXTURESYSTEMMEMORY 0x00000100L /* Device can texture from system memory */
+#define D3DDEVCAPS_TEXTUREVIDEOMEMORY 0x00000200L /* Device can texture from device memory */
+#define D3DDEVCAPS_DRAWPRIMTLVERTEX 0x00000400L /* Device can draw TLVERTEX primitives */
+#define D3DDEVCAPS_CANRENDERAFTERFLIP 0x00000800L /* Device can render without waiting for flip to complete */
+#define D3DDEVCAPS_TEXTURENONLOCALVIDMEM 0x00001000L /* Device can texture from nonlocal video memory */
+#define D3DDEVCAPS_SEPARATETEXTUREMEMORIES 0x00004000L /* Device is texturing from separate memory pools */
+#define D3DDEVCAPS_HWTRANSFORMANDLIGHT 0x00010000L /* Device can support transformation and lighting in hardware and DRAWPRIMITIVES2EX must be also */
+#define D3DDEVCAPS_CANBLTSYSTONONLOCAL 0x00020000L /* Device supports a Tex Blt from system memory to non-local vidmem */
+#define D3DDEVCAPS_HWRASTERIZATION 0x00080000L /* Device has HW acceleration for rasterization */
+#define D3DDEVCAPS_PUREDEVICE 0x00100000L /* Device supports D3DCREATE_PUREDEVICE */
+#define D3DDEVCAPS_QUINTICRTPATCHES 0x00200000L /* Device supports quintic Beziers and BSplines */
+#define D3DDEVCAPS_RTPATCHHANDLEZERO 0x00800000L /* Indicates that RT Patches may be drawn efficiently using handle 0 */
+#define D3DDEVCAPS_NPATCHES 0x01000000L /* Device supports N-Patches */
+
+//
+// PrimitiveMiscCaps
+//
+#define D3DPMISCCAPS_MASKZ 0x00000002L
+#define D3DPMISCCAPS_CULLNONE 0x00000010L
+#define D3DPMISCCAPS_CULLCW 0x00000020L
+#define D3DPMISCCAPS_CULLCCW 0x00000040L
+#define D3DPMISCCAPS_COLORWRITEENABLE 0x00000080L
+#define D3DPMISCCAPS_CLIPPLANESCALEDPOINTS 0x00000100L /* Device correctly clips scaled points to clip planes */
+#define D3DPMISCCAPS_CLIPTLVERTS 0x00000200L /* device will clip post-transformed vertex primitives */
+#define D3DPMISCCAPS_TSSARGTEMP 0x00000400L /* device supports D3DTA_TEMP for temporary register */
+#define D3DPMISCCAPS_BLENDOP 0x00000800L /* device supports D3DRS_BLENDOP */
+#define D3DPMISCCAPS_NULLREFERENCE 0x00001000L /* Reference Device that doesnt render */
+#define D3DPMISCCAPS_PERSTAGECONSTANT 0x00008000L /* Device supports per-stage constants */
+#define D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS 0x00040000L /* Device supports different bit depths for MRT */
+#define D3DPMISCCAPS_FOGVERTEXCLAMPED 0x00100000L /* Device clamps fog blend factor per vertex */
+
+// Flags field for Issue
+#define D3DISSUE_END (1 << 0) // Tells the runtime to issue the end of a query, changing it's state to "non-signaled".
+#define D3DISSUE_BEGIN (1 << 1) // Tells the runtime to issue the beginng of a query.
+
+
+#define D3DPRESENT_INTERVAL_ONE 0x00000001L
+#define D3DPRESENT_INTERVAL_IMMEDIATE 0x80000000L
+
+/*
+ * Options for clearing
+ */
+#define D3DCLEAR_TARGET 0x00000001l /* Clear target surface */
+#define D3DCLEAR_ZBUFFER 0x00000002l /* Clear target z buffer */
+#define D3DCLEAR_STENCIL 0x00000004l /* Clear stencil planes */
+
+
+#define D3DENUM_WHQL_LEVEL 0x00000002L
+
+
+
+
+#define D3DPTEXTURECAPS_NOPROJECTEDBUMPENV 0x00200000L /* Device does not support projected bump env lookup operation
+ in programmable and fixed function pixel shaders */
+#define D3DDEVCAPS2_STREAMOFFSET 0x00000001L /* Device supports offsets in streams. Must be set by DX9 drivers */
+
+#define D3DDEVCAPS_PUREDEVICE 0x00100000L /* Device supports D3DCREATE_PUREDEVICE */
+
+#define D3DCREATE_PUREDEVICE 0x00000010L
+#define D3DCREATE_SOFTWARE_VERTEXPROCESSING 0x00000020L
+#define D3DCREATE_HARDWARE_VERTEXPROCESSING 0x00000040L
+#define D3DCREATE_FPU_PRESERVE 0x00000002L
+#define D3DPRASTERCAPS_FOGRANGE 0x00010000L
+#define D3DPRASTERCAPS_FOGTABLE 0x00000100L
+#define D3DPRASTERCAPS_FOGVERTEX 0x00000080L
+#define D3DPRASTERCAPS_WFOG 0x00100000L
+#define D3DPRASTERCAPS_ZFOG 0x00200000L
+#define D3DPRASTERCAPS_MIPMAPLODBIAS 0x00002000L
+#define D3DPRASTERCAPS_WBUFFER 0x00040000L
+#define D3DPRASTERCAPS_ZTEST 0x00000010L
+
+//
+// Caps2
+//
+#define D3DCAPS2_CANCALIBRATEGAMMA 0x00100000L
+#define D3DPRASTERCAPS_SCISSORTEST 0x01000000L
+#define D3DPTEXTURECAPS_MIPCUBEMAP 0x00010000L /* Device can do mipmapped cube maps */
+#define D3DPTEXTURECAPS_ALPHA 0x00000004L /* Alpha in texture pixels is supported */
+#define D3DPTEXTURECAPS_SQUAREONLY 0x00000020L /* Only square textures are supported */
+#define D3DCREATE_MULTITHREADED 0x00000004L
+#define D3DDEVCAPS_HWTRANSFORMANDLIGHT 0x00010000L /* Device can support transformation and lighting in hardware and DRAWPRIMITIVES2EX must be also */
+#define D3DPTFILTERCAPS_MINFANISOTROPIC 0x00000400L
+#define D3DPTFILTERCAPS_MAGFANISOTROPIC 0x04000000L
+#define D3DPTEXTURECAPS_CUBEMAP 0x00000800L /* Device can do cubemap textures */
+#define D3DPTEXTURECAPS_POW2 0x00000002L /* Power-of-2 texture dimensions are required - applies to non-Cube/Volume textures only. */
+#define D3DPTEXTURECAPS_NONPOW2CONDITIONAL 0x00000100L
+#define D3DPTEXTURECAPS_PROJECTED 0x00000400L /* Device can do D3DTTFF_PROJECTED */
+#define D3DTEXOPCAPS_ADD 0x00000040L
+#define D3DTEXOPCAPS_MODULATE2X 0x00000010L
+#define D3DPRASTERCAPS_DEPTHBIAS 0x04000000L
+#define D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS 0x02000000L
+#define D3DVTXPCAPS_TEXGEN_SPHEREMAP 0x00000100L /* device supports D3DTSS_TCI_SPHEREMAP */
+#define D3DCAPS2_DYNAMICTEXTURES 0x20000000L
+
+// The following usages are valid only for querying CheckDeviceFormat
+#define D3DUSAGE_QUERY_SRGBREAD (0x00010000L)
+#define D3DUSAGE_QUERY_FILTER (0x00020000L)
+#define D3DUSAGE_QUERY_SRGBWRITE (0x00040000L)
+#define D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING (0x00080000L)
+#define D3DUSAGE_QUERY_VERTEXTEXTURE (0x00100000L)
+
+/* Usages for Vertex/Index buffers */
+#define D3DUSAGE_WRITEONLY (0x00000008L)
+#define D3DUSAGE_SOFTWAREPROCESSING (0x00000010L)
+#define D3DUSAGE_DONOTCLIP (0x00000020L)
+#define D3DUSAGE_POINTS (0x00000040L)
+#define D3DUSAGE_RTPATCHES (0x00000080L)
+#define D3DUSAGE_NPATCHES (0x00000100L)
+
+
+// Flags field for GetData
+#define D3DGETDATA_FLUSH (1 << 0) // Tells the runtime to flush if the query is outstanding.
+
+// Flexible vertex format bits
+//
+#define D3DFVF_RESERVED0 0x001
+#define D3DFVF_POSITION_MASK 0x400E
+#define D3DFVF_XYZ 0x002
+#define D3DFVF_XYZRHW 0x004
+#define D3DFVF_XYZB1 0x006
+#define D3DFVF_XYZB2 0x008
+#define D3DFVF_XYZB3 0x00a
+#define D3DFVF_XYZB4 0x00c
+#define D3DFVF_XYZB5 0x00e
+#define D3DFVF_XYZW 0x4002
+#define D3DFVF_NORMAL 0x010
+#define D3DFVF_PSIZE 0x020
+#define D3DFVF_DIFFUSE 0x040
+#define D3DFVF_SPECULAR 0x080
+#define D3DFVF_TEXCOUNT_MASK 0xf00
+#define D3DFVF_TEXCOUNT_SHIFT 8
+#define D3DFVF_TEX0 0x000
+#define D3DFVF_TEX1 0x100
+#define D3DFVF_TEX2 0x200
+#define D3DFVF_TEX3 0x300
+#define D3DFVF_TEX4 0x400
+#define D3DFVF_TEX5 0x500
+#define D3DFVF_TEX6 0x600
+#define D3DFVF_TEX7 0x700
+#define D3DFVF_TEX8 0x800
+#define D3DFVF_LASTBETA_UBYTE4 0x1000
+#define D3DFVF_LASTBETA_D3DCOLOR 0x8000
+#define D3DFVF_RESERVED2 0x6000 // 2 reserved bits
+
+
+#define D3DTA_SELECTMASK 0x0000000f // mask for arg selector
+#define D3DTA_DIFFUSE 0x00000000 // select diffuse color (read only)
+#define D3DTA_CURRENT 0x00000001 // select stage destination register (read/write)
+#define D3DTA_TEXTURE 0x00000002 // select texture color (read only)
+#define D3DTA_TFACTOR 0x00000003 // select D3DRS_TEXTUREFACTOR (read only)
+#define D3DTA_SPECULAR 0x00000004 // select specular color (read only)
+#define D3DTA_TEMP 0x00000005 // select temporary register color (read/write)
+#define D3DTA_CONSTANT 0x00000006 // select texture stage constant
+#define D3DTA_COMPLEMENT 0x00000010 // take 1.0 - x (read modifier)
+#define D3DTA_ALPHAREPLICATE 0x00000020 // replicate alpha to color components (read modifier)
+
+
+#define D3DUSAGE_RENDERTARGET (0x00000001L)
+#define D3DUSAGE_QUERY_VERTEXTEXTURE (0x00100000L)
+#define D3DUSAGE_QUERY_FILTER (0x00020000L)
+#define D3DUSAGE_DEPTHSTENCIL (0x00000002L)
+#define D3DUSAGE_WRITEONLY (0x00000008L)
+#define D3DUSAGE_SOFTWAREPROCESSING (0x00000010L)
+#define D3DUSAGE_DYNAMIC (0x00000200L)
+
+#define D3DSI_INSTLENGTH_MASK 0x0F000000
+#define D3DSI_INSTLENGTH_SHIFT 24
+#define D3DSP_TEXTURETYPE_SHIFT 27
+#define D3DSP_REGTYPE_SHIFT 28
+#define D3DSP_REGTYPE_SHIFT2 8
+#define D3DSP_REGTYPE_MASK 0x70000000
+#define D3DSP_REGTYPE_MASK2 0x00001800
+
+#define D3DSP_REGNUM_MASK 0x000007FF
+
+#define D3DSP_DSTMOD_SHIFT 20
+#define D3DSP_DSTMOD_MASK 0x00F00000
+#define D3DSPDM_MSAMPCENTROID (4<>8)&0xFF)
+#define D3DSHADER_VERSION_MINOR(_Version) (((_Version)>>0)&0xFF)
+
+#define D3DSHADER_ADDRESSMODE_SHIFT 13
+#define D3DSHADER_ADDRESSMODE_MASK (1 << D3DSHADER_ADDRESSMODE_SHIFT)
+
+#define D3DPS_END() 0x0000FFFF
+
+// ps_2_0 texld controls
+#define D3DSI_TEXLD_PROJECT (0x01 << D3DSP_OPCODESPECIFICCONTROL_SHIFT)
+#define D3DSI_TEXLD_BIAS (0x02 << D3DSP_OPCODESPECIFICCONTROL_SHIFT)
+
+
+// destination parameter write mask
+#define D3DSP_WRITEMASK_0 0x00010000 // Component 0 (X;Red)
+#define D3DSP_WRITEMASK_1 0x00020000 // Component 1 (Y;Green)
+#define D3DSP_WRITEMASK_2 0x00040000 // Component 2 (Z;Blue)
+#define D3DSP_WRITEMASK_3 0x00080000 // Component 3 (W;Alpha)
+#define D3DSP_WRITEMASK_ALL 0x000F0000 // All Components
+
+#define D3DVS_SWIZZLE_SHIFT 16
+#define D3DVS_SWIZZLE_MASK 0x00FF0000
+
+// The following bits define where to take component X from:
+
+#define D3DVS_X_X (0 << D3DVS_SWIZZLE_SHIFT)
+#define D3DVS_X_Y (1 << D3DVS_SWIZZLE_SHIFT)
+#define D3DVS_X_Z (2 << D3DVS_SWIZZLE_SHIFT)
+#define D3DVS_X_W (3 << D3DVS_SWIZZLE_SHIFT)
+
+// The following bits define where to take component Y from:
+
+#define D3DVS_Y_X (0 << (D3DVS_SWIZZLE_SHIFT + 2))
+#define D3DVS_Y_Y (1 << (D3DVS_SWIZZLE_SHIFT + 2))
+#define D3DVS_Y_Z (2 << (D3DVS_SWIZZLE_SHIFT + 2))
+#define D3DVS_Y_W (3 << (D3DVS_SWIZZLE_SHIFT + 2))
+
+// The following bits define where to take component Z from:
+
+#define D3DVS_Z_X (0 << (D3DVS_SWIZZLE_SHIFT + 4))
+#define D3DVS_Z_Y (1 << (D3DVS_SWIZZLE_SHIFT + 4))
+#define D3DVS_Z_Z (2 << (D3DVS_SWIZZLE_SHIFT + 4))
+#define D3DVS_Z_W (3 << (D3DVS_SWIZZLE_SHIFT + 4))
+
+// The following bits define where to take component W from:
+
+#define D3DVS_W_X (0 << (D3DVS_SWIZZLE_SHIFT + 6))
+#define D3DVS_W_Y (1 << (D3DVS_SWIZZLE_SHIFT + 6))
+#define D3DVS_W_Z (2 << (D3DVS_SWIZZLE_SHIFT + 6))
+#define D3DVS_W_W (3 << (D3DVS_SWIZZLE_SHIFT + 6))
+
+// source parameter modifiers
+#define D3DSP_SRCMOD_SHIFT 24
+#define D3DSP_SRCMOD_MASK 0x0F000000
+
+
+struct IDirect3DSurface9;
+struct IDirect3DDevice9;
+struct IDirect3DCubeTexture9;
+struct IDirect3DVertexDeclaration9;
+struct IDirect3DQuery9;
+
+
+
+
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+// ENUMS
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+typedef enum _D3DSHADER_PARAM_SRCMOD_TYPE
+{
+ D3DSPSM_NONE = 0<= 2.0
+
+
+ D3DDECLTYPE_UBYTE4N = 8, // Each of 4 bytes is normalized by dividing to 255.0
+ D3DDECLTYPE_SHORT2N = 9, // 2D signed short normalized (v[0]/32767.0,v[1]/32767.0,0,1)
+ D3DDECLTYPE_SHORT4N = 10, // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0)
+ D3DDECLTYPE_USHORT2N = 11, // 2D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,0,1)
+ D3DDECLTYPE_USHORT4N = 12, // 4D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,v[2]/65535.0,v[3]/65535.0)
+ D3DDECLTYPE_UDEC3 = 13, // 3D unsigned 10 10 10 format expanded to (value, value, value, 1)
+ D3DDECLTYPE_DEC3N = 14, // 3D signed 10 10 10 format normalized and expanded to (v[0]/511.0, v[1]/511.0, v[2]/511.0, 1)
+ D3DDECLTYPE_FLOAT16_2 = 15, // Two 16-bit floating point values, expanded to (value, value, 0, 1)
+ D3DDECLTYPE_FLOAT16_4 = 16, // Four 16-bit floating point values
+ D3DDECLTYPE_UNUSED = 17, // When the type field in a decl is unused.
+} D3DDECLTYPE;
+
+typedef enum _D3DDECLMETHOD
+{
+ D3DDECLMETHOD_DEFAULT = 0,
+ D3DDECLMETHOD_PARTIALU,
+ D3DDECLMETHOD_PARTIALV,
+ D3DDECLMETHOD_CROSSUV, // Normal
+ D3DDECLMETHOD_UV,
+ D3DDECLMETHOD_LOOKUP, // Lookup a displacement map
+ D3DDECLMETHOD_LOOKUPPRESAMPLED, // Lookup a pre-sampled displacement map
+} D3DDECLMETHOD;
+
+typedef enum _D3DDECLUSAGE
+{
+ D3DDECLUSAGE_POSITION = 0,
+ D3DDECLUSAGE_BLENDWEIGHT = 1,
+ D3DDECLUSAGE_BLENDINDICES = 2,
+ D3DDECLUSAGE_NORMAL = 3,
+ D3DDECLUSAGE_PSIZE = 4,
+ D3DDECLUSAGE_TEXCOORD = 5,
+ D3DDECLUSAGE_TANGENT = 6,
+ D3DDECLUSAGE_BINORMAL = 7,
+ D3DDECLUSAGE_TESSFACTOR = 8,
+ D3DDECLUSAGE_PLUGH = 9, // mystery value
+ D3DDECLUSAGE_COLOR = 10,
+ D3DDECLUSAGE_FOG = 11,
+ D3DDECLUSAGE_DEPTH = 12,
+ D3DDECLUSAGE_SAMPLE = 13,
+} D3DDECLUSAGE;
+
+typedef enum _D3DPRIMITIVETYPE {
+ D3DPT_POINTLIST = 1,
+ D3DPT_LINELIST = 2,
+ D3DPT_TRIANGLELIST = 4,
+ D3DPT_TRIANGLESTRIP = 5,
+ D3DPT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */
+} D3DPRIMITIVETYPE;
+
+
+
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+// STRUCTURES
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+typedef struct D3DXPLANE
+{
+ float& operator[]( int i );
+ bool operator==( const D3DXPLANE &o );
+ bool operator!=( const D3DXPLANE &o );
+ operator float*();
+ operator const float*() const;
+
+ float a, b, c, d;
+} D3DXPLANE;
+
+typedef enum _D3DVERTEXBLENDFLAGS
+{
+ D3DVBF_DISABLE = 0, // Disable vertex blending
+ D3DVBF_1WEIGHTS = 1, // 2 matrix blending
+ D3DVBF_2WEIGHTS = 2, // 3 matrix blending
+ D3DVBF_3WEIGHTS = 3, // 4 matrix blending
+ D3DVBF_TWEENING = 255, // blending using D3DRS_TWEENFACTOR
+ D3DVBF_0WEIGHTS = 256, // one matrix is used with weight 1.0
+ D3DVBF_FORCE_DWORD = 0x7fffffff, // force 32-bit size enum
+} D3DVERTEXBLENDFLAGS;
+
+typedef struct _D3DINDEXBUFFER_DESC
+{
+ D3DFORMAT Format;
+ D3DRESOURCETYPE Type;
+ DWORD Usage;
+ D3DPOOL Pool;
+ UINT Size;
+} D3DINDEXBUFFER_DESC;
+
+typedef struct _D3DVERTEXELEMENT9
+{
+ WORD Stream; // Stream index
+ WORD Offset; // Offset in the stream in bytes
+ BYTE Type; // Data type
+ BYTE Method; // Processing method
+ BYTE Usage; // Semantics
+ BYTE UsageIndex; // Semantic index
+} D3DVERTEXELEMENT9, *LPD3DVERTEXELEMENT9;
+
+
+#define MAX_DEVICE_IDENTIFIER_STRING 512
+typedef struct _D3DADAPTER_IDENTIFIER9
+{
+ char Driver[MAX_DEVICE_IDENTIFIER_STRING];
+ char Description[MAX_DEVICE_IDENTIFIER_STRING];
+ char DeviceName[32]; /* Device name for GDI (ex. \\.\DISPLAY1) */
+
+ LARGE_INTEGER DriverVersion; /* Defined for 32 bit components */
+
+ DWORD VendorId;
+ DWORD DeviceId;
+ DWORD SubSysId;
+ DWORD Revision;
+ DWORD VideoMemory;
+
+} D3DADAPTER_IDENTIFIER9;
+
+
+typedef struct _D3DCOLORVALUE {
+ float r;
+ float g;
+ float b;
+ float a;
+} D3DCOLORVALUE;
+
+typedef struct _D3DMATERIAL9 {
+ D3DCOLORVALUE Diffuse; /* Diffuse color RGBA */
+ D3DCOLORVALUE Ambient; /* Ambient color RGB */
+ D3DCOLORVALUE Specular; /* Specular 'shininess' */
+ D3DCOLORVALUE Emissive; /* Emissive color RGB */
+ float Power; /* Sharpness if specular highlight */
+} D3DMATERIAL9;
+
+typedef struct _D3DVOLUME_DESC
+{
+ D3DFORMAT Format;
+ D3DRESOURCETYPE Type;
+ DWORD Usage;
+ D3DPOOL Pool;
+
+ UINT Width;
+ UINT Height;
+ UINT Depth;
+} D3DVOLUME_DESC;
+
+typedef struct _D3DVIEWPORT9 {
+ DWORD X;
+ DWORD Y; /* Viewport Top left */
+ DWORD Width;
+ DWORD Height; /* Viewport Dimensions */
+ float MinZ; /* Min/max of clip Volume */
+ float MaxZ;
+} D3DVIEWPORT9;
+
+typedef struct _D3DPSHADERCAPS2_0
+{
+ DWORD Caps;
+ INT DynamicFlowControlDepth;
+ INT NumTemps;
+ INT StaticFlowControlDepth;
+ INT NumInstructionSlots;
+} D3DPSHADERCAPS2_0;
+
+typedef struct _D3DCAPS9
+{
+ /* Device Info */
+ D3DDEVTYPE DeviceType;
+
+ /* Caps from DX7 Draw */
+ DWORD Caps;
+ DWORD Caps2;
+
+ /* Cursor Caps */
+ DWORD CursorCaps;
+
+ /* 3D Device Caps */
+ DWORD DevCaps;
+
+ DWORD PrimitiveMiscCaps;
+ DWORD RasterCaps;
+ DWORD TextureCaps;
+ DWORD TextureFilterCaps; // D3DPTFILTERCAPS for IDirect3DTexture9's
+
+ DWORD MaxTextureWidth, MaxTextureHeight;
+ DWORD MaxVolumeExtent;
+
+ DWORD MaxTextureAspectRatio;
+ DWORD MaxAnisotropy;
+
+ DWORD TextureOpCaps;
+ DWORD MaxTextureBlendStages;
+ DWORD MaxSimultaneousTextures;
+
+ DWORD VertexProcessingCaps;
+ DWORD MaxActiveLights;
+ DWORD MaxUserClipPlanes;
+ DWORD MaxVertexBlendMatrices;
+ DWORD MaxVertexBlendMatrixIndex;
+
+ DWORD MaxPrimitiveCount; // max number of primitives per DrawPrimitive call
+ DWORD MaxStreams;
+
+ DWORD VertexShaderVersion;
+ DWORD MaxVertexShaderConst; // number of vertex shader constant registers
+
+ DWORD PixelShaderVersion;
+
+ // Here are the DX9 specific ones
+ DWORD DevCaps2;
+ D3DPSHADERCAPS2_0 PS20Caps;
+
+ DWORD NumSimultaneousRTs; // Will be at least 1
+ DWORD MaxVertexShader30InstructionSlots;
+ DWORD MaxPixelShader30InstructionSlots;
+
+ // only on Posix/GL
+ #if POSIX
+ DWORD FakeSRGBWrite; // 1 for parts which can't support SRGB writes due to driver issues - 0 for others
+ DWORD MixedSizeTargets; // 1 for parts which can mix attachment sizes (RT's color vs depth)
+ DWORD CanDoSRGBReadFromRTs; // 0 when we're on Leopard, 1 when on Snow Leopard
+ #endif
+} D3DCAPS9;
+
+typedef struct _D3DDISPLAYMODE
+{
+ UINT Width;
+ UINT Height;
+ UINT RefreshRate;
+ D3DFORMAT Format;
+} D3DDISPLAYMODE;
+
+typedef struct _D3DGAMMARAMP
+{
+ WORD red [256];
+ WORD green[256];
+ WORD blue [256];
+} D3DGAMMARAMP;
+
+
+/* Resize Optional Parameters */
+typedef struct _D3DPRESENT_PARAMETERS_
+{
+ UINT BackBufferWidth;
+ UINT BackBufferHeight;
+ D3DFORMAT BackBufferFormat;
+ UINT BackBufferCount;
+
+ D3DMULTISAMPLE_TYPE MultiSampleType;
+ DWORD MultiSampleQuality;
+
+ D3DSWAPEFFECT SwapEffect;
+ VD3DHWND hDeviceWindow;
+ BOOL Windowed;
+ BOOL EnableAutoDepthStencil;
+ D3DFORMAT AutoDepthStencilFormat;
+ DWORD Flags;
+
+ /* FullScreen_RefreshRateInHz must be zero for Windowed mode */
+ UINT FullScreen_RefreshRateInHz;
+ UINT PresentationInterval;
+} D3DPRESENT_PARAMETERS;
+
+typedef struct _D3DDEVICE_CREATION_PARAMETERS
+{
+ UINT AdapterOrdinal;
+ D3DDEVTYPE DeviceType;
+ VD3DHWND hFocusWindow;
+ DWORD BehaviorFlags;
+} D3DDEVICE_CREATION_PARAMETERS;
+
+/* Structures for LockBox */
+typedef struct _D3DBOX
+{
+ UINT Left;
+ UINT Top;
+ UINT Right;
+ UINT Bottom;
+ UINT Front;
+ UINT Back;
+} D3DBOX;
+
+typedef struct _D3DLOCKED_BOX
+{
+ INT RowPitch;
+ INT SlicePitch;
+ void* pBits;
+} D3DLOCKED_BOX;
+
+typedef struct _D3DSURFACE_DESC
+{
+ D3DFORMAT Format;
+ D3DRESOURCETYPE Type;
+ DWORD Usage;
+ D3DPOOL Pool;
+
+ D3DMULTISAMPLE_TYPE MultiSampleType;
+ DWORD MultiSampleQuality;
+ UINT Width;
+ UINT Height;
+} D3DSURFACE_DESC;
+
+
+typedef struct _D3DLOCKED_RECT
+{
+ INT Pitch;
+ void* pBits;
+} D3DLOCKED_RECT;
+
+
+typedef struct _D3DRASTER_STATUS
+{
+ BOOL InVBlank;
+ UINT ScanLine;
+} D3DRASTER_STATUS;
+
+typedef enum _D3DLIGHTTYPE {
+ D3DLIGHT_POINT = 1,
+ D3DLIGHT_SPOT = 2,
+ D3DLIGHT_DIRECTIONAL = 3,
+ D3DLIGHT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */
+} D3DLIGHTTYPE;
+
+typedef struct _D3DVECTOR {
+ float x;
+ float y;
+ float z;
+} D3DVECTOR;
+
+class D3DXVECTOR2
+{
+public:
+ operator FLOAT* ();
+ operator CONST FLOAT* () const;
+
+ float x,y;
+};
+
+class D3DXVECTOR3 : public D3DVECTOR
+{
+public:
+ D3DXVECTOR3() {}
+ D3DXVECTOR3( float a, float b, float c );
+ operator FLOAT* ();
+ operator CONST FLOAT* () const;
+};
+
+typedef enum _D3DXINCLUDE_TYPE
+{
+ D3DXINC_LOCAL,
+
+ // force 32-bit size enum
+ D3DXINC_FORCE_DWORD = 0x7fffffff
+
+} D3DXINCLUDE_TYPE;
+
+typedef struct _D3DLIGHT9 {
+ D3DLIGHTTYPE Type; /* Type of light source */
+ D3DCOLORVALUE Diffuse; /* Diffuse color of light */
+ D3DCOLORVALUE Specular; /* Specular color of light */
+ D3DCOLORVALUE Ambient; /* Ambient color of light */
+ D3DVECTOR Position; /* Position in world space */
+ D3DVECTOR Direction; /* Direction in world space */
+ float Range; /* Cutoff range */
+ float Falloff; /* Falloff */
+ float Attenuation0; /* Constant attenuation */
+ float Attenuation1; /* Linear attenuation */
+ float Attenuation2; /* Quadratic attenuation */
+ float Theta; /* Inner angle of spotlight cone */
+ float Phi; /* Outer angle of spotlight cone */
+} D3DLIGHT9;
+
+class D3DXVECTOR4
+{
+public:
+ D3DXVECTOR4() {}
+ D3DXVECTOR4( float a, float b, float c, float d );
+
+ float x,y,z,w;
+};
+
+//----------------------------------------------------------------------------
+// D3DXMACRO:
+// ----------
+// Preprocessor macro definition. The application pass in a NULL-terminated
+// array of this structure to various D3DX APIs. This enables the application
+// to #define tokens at runtime, before the file is parsed.
+//----------------------------------------------------------------------------
+
+typedef struct _D3DXMACRO
+{
+ LPCSTR Name;
+ LPCSTR Definition;
+
+} D3DXMACRO, *LPD3DXMACRO;
+
+
+
+
+
+
+
+
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+// ------------------------------------------------------------------------------------------------------------------------------ //
+// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL.
+//
+// Also look for any functions marked with "**** FIXED FUNCTION STUFF"
+//
+// It's only laying around here so we don't have to chop up the shader system a lot to strip out the fixed function code paths.
+// ------------------------------------------------------------------------------------------------------------------------------ //
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL.
+typedef enum _D3DTRANSFORMSTATETYPE {
+ D3DTS_VIEW = 2,
+ D3DTS_PROJECTION = 3,
+ D3DTS_TEXTURE0 = 16,
+ D3DTS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */
+} D3DTRANSFORMSTATETYPE;
+
+// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL.
+typedef enum _D3DTEXTUREOP
+{
+ // Control
+ D3DTOP_DISABLE = 1, // disables stage
+ D3DTOP_SELECTARG1 = 2, // the default
+ D3DTOP_SELECTARG2 = 3,
+
+ // Modulate
+ D3DTOP_MODULATE = 4, // multiply args together
+ D3DTOP_MODULATE2X = 5, // multiply and 1 bit
+ D3DTOP_MODULATE4X = 6, // multiply and 2 bits
+
+ // Add
+ D3DTOP_ADD = 7, // add arguments together
+ D3DTOP_ADDSIGNED = 8, // add with -0.5 bias
+ D3DTOP_ADDSIGNED2X = 9, // as above but left 1 bit
+ D3DTOP_SUBTRACT = 10, // Arg1 - Arg2, with no saturation
+ D3DTOP_ADDSMOOTH = 11, // add 2 args, subtract product
+ // Arg1 + Arg2 - Arg1*Arg2
+ // = Arg1 + (1-Arg1)*Arg2
+
+ // Linear alpha blend: Arg1*(Alpha) + Arg2*(1-Alpha)
+ D3DTOP_BLENDDIFFUSEALPHA = 12, // iterated alpha
+ D3DTOP_BLENDTEXTUREALPHA = 13, // texture alpha
+ D3DTOP_BLENDFACTORALPHA = 14, // alpha from D3DRS_TEXTUREFACTOR
+
+ // Linear alpha blend with pre-multiplied arg1 input: Arg1 + Arg2*(1-Alpha)
+ D3DTOP_BLENDTEXTUREALPHAPM = 15, // texture alpha
+ D3DTOP_BLENDCURRENTALPHA = 16, // by alpha of current color
+
+ // Specular mapping
+ D3DTOP_PREMODULATE = 17, // modulate with next texture before use
+ D3DTOP_MODULATEALPHA_ADDCOLOR = 18, // Arg1.RGB + Arg1.A*Arg2.RGB
+ // COLOROP only
+ D3DTOP_MODULATECOLOR_ADDALPHA = 19, // Arg1.RGB*Arg2.RGB + Arg1.A
+ // COLOROP only
+ D3DTOP_MODULATEINVALPHA_ADDCOLOR = 20, // (1-Arg1.A)*Arg2.RGB + Arg1.RGB
+ // COLOROP only
+ D3DTOP_MODULATEINVCOLOR_ADDALPHA = 21, // (1-Arg1.RGB)*Arg2.RGB + Arg1.A
+ // COLOROP only
+
+ // Bump mapping
+ D3DTOP_BUMPENVMAP = 22, // per pixel env map perturbation
+ D3DTOP_BUMPENVMAPLUMINANCE = 23, // with luminance channel
+
+ // This can do either diffuse or specular bump mapping with correct input.
+ // Performs the function (Arg1.R*Arg2.R + Arg1.G*Arg2.G + Arg1.B*Arg2.B)
+ // where each component has been scaled and offset to make it signed.
+ // The result is replicated into all four (including alpha) channels.
+ // This is a valid COLOROP only.
+ D3DTOP_DOTPRODUCT3 = 24,
+
+ // Triadic ops
+ D3DTOP_MULTIPLYADD = 25, // Arg0 + Arg1*Arg2
+ D3DTOP_LERP = 26, // (Arg0)*Arg1 + (1-Arg0)*Arg2
+
+ D3DTOP_FORCE_DWORD = 0x7fffffff,
+} D3DTEXTUREOP;
+
+// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL.
+typedef enum _D3DTEXTURESTAGESTATETYPE
+{
+ D3DTSS_COLOROP = 1, /* D3DTEXTUREOP - per-stage blending controls for color channels */
+ D3DTSS_COLORARG1 = 2, /* D3DTA_* (texture arg) */
+ D3DTSS_COLORARG2 = 3, /* D3DTA_* (texture arg) */
+ D3DTSS_ALPHAOP = 4, /* D3DTEXTUREOP - per-stage blending controls for alpha channel */
+ D3DTSS_ALPHAARG1 = 5, /* D3DTA_* (texture arg) */
+ D3DTSS_ALPHAARG2 = 6, /* D3DTA_* (texture arg) */
+ D3DTSS_BUMPENVMAT00 = 7, /* float (bump mapping matrix) */
+ D3DTSS_BUMPENVMAT01 = 8, /* float (bump mapping matrix) */
+ D3DTSS_BUMPENVMAT10 = 9, /* float (bump mapping matrix) */
+ D3DTSS_BUMPENVMAT11 = 10, /* float (bump mapping matrix) */
+ D3DTSS_TEXCOORDINDEX = 11, /* identifies which set of texture coordinates index this texture */
+ D3DTSS_BUMPENVLOFFSET = 23, /* float offset for bump map luminance */
+ D3DTSS_TEXTURETRANSFORMFLAGS = 24, /* D3DTEXTURETRANSFORMFLAGS controls texture transform */
+ D3DTSS_COLORARG0 = 26, /* D3DTA_* third arg for triadic ops */
+ D3DTSS_RESULTARG = 28, /* D3DTA_* arg for result (CURRENT or TEMP) */
+
+
+ D3DTSS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */
+} D3DTEXTURESTAGESTATETYPE;
+
+
+
+
+
+
+
+// ------------------------------------------------------------------------------------------------------------------------------ //
+// INTERFACES
+// ------------------------------------------------------------------------------------------------------------------------------ //
+
+struct IDirect3DResource9 : public IUnknown
+{
+ IDirect3DDevice9 *m_device; // parent device
+ D3DRESOURCETYPE m_restype;
+
+ DWORD SetPriority(DWORD PriorityNew);
+};
+
+struct IDirect3DBaseTexture9 : public IDirect3DResource9 // "A Texture.."
+{
+ D3DSURFACE_DESC m_descZero; // desc of top level.
+ CGLMTex *m_tex; // a CGLMTex can represent all forms of tex
+ int m_srgbFlipCount;
+
+ virtual ~IDirect3DBaseTexture9();
+ D3DRESOURCETYPE GetType();
+ DWORD GetLevelCount();
+ HRESULT GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc);
+};
+
+struct IDirect3DTexture9 : public IDirect3DBaseTexture9 // "Texture 2D"
+{
+ IDirect3DSurface9 *m_surfZero; // surf of top level.
+
+ virtual ~IDirect3DTexture9();
+
+ HRESULT LockRect(UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags);
+ HRESULT UnlockRect(UINT Level);
+ HRESULT GetSurfaceLevel(UINT Level,IDirect3DSurface9** ppSurfaceLevel);
+};
+
+typedef struct IDirect3DTexture9 *LPDIRECT3DTEXTURE9, *PDIRECT3DTEXTURE9;
+
+struct IDirect3DCubeTexture9 : public IDirect3DBaseTexture9 // "Texture Cube Map"
+{
+ IDirect3DSurface9 *m_surfZero[6]; // surfs of top level.
+
+ virtual ~IDirect3DCubeTexture9();
+
+ HRESULT GetCubeMapSurface(D3DCUBEMAP_FACES FaceType,UINT Level,IDirect3DSurface9** ppCubeMapSurface);
+ HRESULT GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc);
+};
+
+struct IDirect3DVolumeTexture9 : public IDirect3DBaseTexture9 // "Texture 3D"
+{
+ IDirect3DSurface9 *m_surfZero; // surf of top level.
+ D3DVOLUME_DESC m_volDescZero; // volume desc top level
+
+ virtual ~IDirect3DVolumeTexture9();
+
+ HRESULT LockBox(UINT Level,D3DLOCKED_BOX* pLockedVolume,CONST D3DBOX* pBox,DWORD Flags);
+ HRESULT UnlockBox(UINT Level);
+ HRESULT GetLevelDesc( UINT level, D3DVOLUME_DESC *pDesc );
+};
+
+
+// for the moment, a "D3D surface" is modeled as a GLM tex, a face, and a mip.
+// no Create method, these are filled in by the various create surface methods.
+
+struct IDirect3DSurface9 : public IDirect3DResource9
+{
+ virtual ~IDirect3DSurface9();
+
+ HRESULT LockRect(D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags);
+ HRESULT UnlockRect();
+ HRESULT GetDesc(D3DSURFACE_DESC *pDesc);
+
+ D3DSURFACE_DESC m_desc;
+ CGLMTex *m_tex;
+ int m_face;
+ int m_mip;
+};
+
+
+
+struct IDirect3D9 : public IUnknown
+{
+public:
+ virtual ~IDirect3D9();
+
+ UINT GetAdapterCount(); //cheese: returns 1
+
+ HRESULT GetDeviceCaps (UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps);
+ HRESULT GetAdapterIdentifier (UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier);
+ HRESULT CheckDeviceFormat (UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat);
+ UINT GetAdapterModeCount (UINT Adapter,D3DFORMAT Format);
+ HRESULT EnumAdapterModes (UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode);
+ HRESULT CheckDeviceType (UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed);
+ HRESULT GetAdapterDisplayMode (UINT Adapter,D3DDISPLAYMODE* pMode);
+ HRESULT CheckDepthStencilMatch (UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat);
+ HRESULT CheckDeviceMultiSampleType (UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels);
+
+ HRESULT CreateDevice (UINT Adapter,D3DDEVTYPE DeviceType,VD3DHWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface);
+};
+
+struct IDirect3DSwapChain9 : public IUnknown
+{
+};
+
+
+
+ // typedef enum D3DDECLUSAGE
+ // {
+ // D3DDECLUSAGE_POSITION = 0,
+ // D3DDECLUSAGE_BLENDWEIGHT = 1,
+ // D3DDECLUSAGE_BLENDINDICES = 2,
+ // D3DDECLUSAGE_NORMAL = 3,
+ // D3DDECLUSAGE_PSIZE = 4,
+ // D3DDECLUSAGE_TEXCOORD = 5,
+ // D3DDECLUSAGE_TANGENT = 6,
+ // D3DDECLUSAGE_BINORMAL = 7,
+ // D3DDECLUSAGE_TESSFACTOR = 8,
+ // D3DDECLUSAGE_POSITIONT = 9,
+ // D3DDECLUSAGE_COLOR = 10,
+ // D3DDECLUSAGE_FOG = 11,
+ // D3DDECLUSAGE_DEPTH = 12,
+ // D3DDECLUSAGE_SAMPLE = 13,
+ // } D3DDECLUSAGE, *LPD3DDECLUSAGE;
+ // Constants
+ //
+ // D3DDECLUSAGE_POSITION
+ // Position data ranging from (-1,-1) to (1,1). Use D3DDECLUSAGE_POSITION with
+ // a usage index of 0 to specify untransformed position for fixed function
+ // vertex processing and the n-patch tessellator. Use D3DDECLUSAGE_POSITION
+ // with a usage index of 1 to specify untransformed position in the fixed
+ // function vertex shader for vertex tweening.
+ //
+ // D3DDECLUSAGE_BLENDWEIGHT
+ // Blending weight data. Use D3DDECLUSAGE_BLENDWEIGHT with a usage index of 0
+ // to specify the blend weights used in indexed and nonindexed vertex
+ // blending.
+ //
+ // D3DDECLUSAGE_BLENDINDICES
+ // Blending indices data. Use D3DDECLUSAGE_BLENDINDICES with a usage index of
+ // 0 to specify matrix indices for indexed paletted skinning.
+ //
+ // D3DDECLUSAGE_NORMAL
+ // Vertex normal data. Use D3DDECLUSAGE_NORMAL with a usage index of 0 to
+ // specify vertex normals for fixed function vertex processing and the n-patch
+ // tessellator. Use D3DDECLUSAGE_NORMAL with a usage index of 1 to specify
+ // vertex normals for fixed function vertex processing for vertex tweening.
+ //
+ // D3DDECLUSAGE_PSIZE
+ // Point size data. Use D3DDECLUSAGE_PSIZE with a usage index of 0 to specify
+ // the point-size attribute used by the setup engine of the rasterizer to
+ // expand a point into a quad for the point-sprite functionality.
+ //
+ // D3DDECLUSAGE_TEXCOORD
+ // Texture coordinate data. Use D3DDECLUSAGE_TEXCOORD, n to specify texture
+ // coordinates in fixed function vertex processing and in pixel shaders prior
+ // to ps_3_0. These can be used to pass user defined data.
+ //
+ // D3DDECLUSAGE_TANGENT
+ // Vertex tangent data.
+ //
+ // D3DDECLUSAGE_BINORMAL
+ // Vertex binormal data.
+ //
+ // D3DDECLUSAGE_TESSFACTOR
+ // Single positive floating point value. Use D3DDECLUSAGE_TESSFACTOR with a
+ // usage index of 0 to specify a tessellation factor used in the tessellation
+ // unit to control the rate of tessellation. For more information about the
+ // data type, see D3DDECLTYPE_FLOAT1.
+ //
+ // D3DDECLUSAGE_POSITIONT
+ // Vertex data contains transformed position data ranging from (0,0) to
+ // (viewport width, viewport height). Use D3DDECLUSAGE_POSITIONT with a usage
+ // index of 0 to specify transformed position. When a declaration containing
+ // this is set, the pipeline does not perform vertex processing.
+ //
+ // D3DDECLUSAGE_COLOR
+ // Vertex data contains diffuse or specular color. Use D3DDECLUSAGE_COLOR with
+ // a usage index of 0 to specify the diffuse color in the fixed function
+ // vertex shader and pixel shaders prior to ps_3_0. Use D3DDECLUSAGE_COLOR
+ // with a usage index of 1 to specify the specular color in the fixed function
+ // vertex shader and pixel shaders prior to ps_3_0.
+ //
+ // D3DDECLUSAGE_FOG
+ // Vertex data contains fog data. Use D3DDECLUSAGE_FOG with a usage index of 0
+ // to specify a fog blend value used after pixel shading finishes. This
+ // applies to pixel shaders prior to version ps_3_0.
+ //
+ // D3DDECLUSAGE_DEPTH
+ // Vertex data contains depth data.
+ //
+ // D3DDECLUSAGE_SAMPLE
+ // Vertex data contains sampler data. Use D3DDECLUSAGE_SAMPLE with a usage
+ // index of 0 to specify the displacement value to look up. It can be used
+ // only with D3DDECLUSAGE_LOOKUPPRESAMPLED or D3DDECLUSAGE_LOOKUP.
+
+ //note the form of the list terminator..
+
+ // #define D3DDECL_END() {0xFF,0,D3DDECLTYPE_UNUSED,0,0,0}
+ // typedef struct _D3DVERTEXELEMENT9
+ // {
+ // WORD Stream; // Stream index
+ // WORD Offset; // Offset in the stream in bytes
+ // BYTE Type; // Data type
+ // BYTE Method; // Processing method
+ // BYTE Usage; // Semantics
+ // BYTE UsageIndex; // Semantic index
+ // } D3DVERTEXELEMENT9, *LPD3DVERTEXELEMENT9;
+
+#define MAX_D3DVERTEXELEMENTS 16
+
+struct D3DVERTEXELEMENT9_GL
+{
+ // fields right out of the original decl element (copied)
+ D3DVERTEXELEMENT9 m_dxdecl; // d3d info
+ // WORD Stream; // Stream index
+ // WORD Offset; // Offset in the stream in bytes
+ // BYTE Type; // Data type
+ // BYTE Method; // Processing method
+ // BYTE Usage; // Semantics
+ // BYTE UsageIndex; // Semantic index
+
+ GLMVertexAttributeDesc m_gldecl;
+ // CGLMBuffer *m_buffer; // late-dropped from selected stream desc (left NULL, will replace with stream source buffer at sync time)
+ // GLuint m_datasize; // component count (1,2,3,4) of the attrib
+ // GLenum m_datatype; // data type of the attribute (GL_FLOAT et al)
+ // GLuint m_stride; // late-dropped from stream desc
+ // GLuint m_offset; // net offset to attribute 'zero' within the stream data. Add the stream offset before passing to GL.
+ // GLuint m_normalized; // net offset to attribute 'zero' within the stream data. Add the stream offset before passing to GL.
+};
+
+struct IDirect3DVertexDeclaration9 : public IUnknown
+{
+//public:
+ uint m_elemCount;
+ D3DVERTEXELEMENT9_GL m_elements[ MAX_D3DVERTEXELEMENTS ];
+
+ virtual ~IDirect3DVertexDeclaration9();
+};
+
+struct IDirect3DQuery9 : public IDirect3DResource9 //was IUnknown
+{
+//public:
+ D3DQUERYTYPE m_type; // D3DQUERYTYPE_OCCLUSION or D3DQUERYTYPE_EVENT
+ GLMContext *m_ctx;
+ CGLMQuery *m_query;
+
+ virtual ~IDirect3DQuery9();
+
+ HRESULT Issue(DWORD dwIssueFlags);
+ HRESULT GetData(void* pData,DWORD dwSize,DWORD dwGetDataFlags);
+};
+
+struct IDirect3DVertexBuffer9 : public IDirect3DResource9 //was IUnknown
+{
+//public:
+ GLMContext *m_ctx;
+ CGLMBuffer *m_vtxBuffer;
+ D3DVERTEXBUFFER_DESC m_vtxDesc; // to satisfy GetDesc
+
+ virtual ~IDirect3DVertexBuffer9();
+ HRESULT Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags);
+ HRESULT Unlock();
+
+};
+
+struct IDirect3DIndexBuffer9 : public IDirect3DResource9 //was IUnknown
+{
+//public:
+ GLMContext *m_ctx;
+ CGLMBuffer *m_idxBuffer;
+ D3DINDEXBUFFER_DESC m_idxDesc; // to satisfy GetDesc
+
+ virtual ~IDirect3DIndexBuffer9();
+
+ HRESULT Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags);
+ HRESULT Unlock();
+ HRESULT GetDesc(D3DINDEXBUFFER_DESC *pDesc);
+};
+
+struct IDirect3DPixelShader9 : public IDirect3DResource9 //was IUnknown
+{
+//public:
+ CGLMProgram *m_pixProgram;
+ uint m_pixHighWater; // count of active constant slots referenced by shader.
+ uint m_pixSamplerMask; // (1< m_stack;
+ int m_stackTop; // top of stack is at the highest index, this is that index. push increases, pop decreases.
+
+ HRESULT Create( void );
+
+ D3DXMATRIX* GetTop();
+ void Push();
+ void Pop();
+ void LoadIdentity();
+ void LoadMatrix( const D3DXMATRIX *pMat );
+ void MultMatrix( const D3DXMATRIX *pMat );
+ void MultMatrixLocal( const D3DXMATRIX *pMat );
+ HRESULT ScaleLocal(FLOAT x, FLOAT y, FLOAT z);
+
+ // Left multiply the current matrix with the computed rotation
+ // matrix, counterclockwise about the given axis with the given angle.
+ // (rotation is about the local origin of the object)
+ HRESULT RotateAxisLocal(CONST D3DXVECTOR3* pV, FLOAT Angle);
+
+ // Left multiply the current matrix with the computed translation
+ // matrix. (transformation is about the local origin of the object)
+ HRESULT TranslateLocal(FLOAT x, FLOAT y, FLOAT z);
+};
+typedef ID3DXMatrixStack* LPD3DXMATRIXSTACK;
+
+struct IDirect3DDevice9Params
+{
+ UINT m_adapter;
+ D3DDEVTYPE m_deviceType;
+ VD3DHWND m_focusWindow;
+ DWORD m_behaviorFlags;
+ D3DPRESENT_PARAMETERS m_presentationParameters;
+};
+
+#define D3D_MAX_STREAMS 4
+struct D3DStreamDesc
+{
+ IDirect3DVertexBuffer9 *m_vtxBuffer;
+ uint m_offset;
+ uint m_stride;
+};
+
+struct D3DIndexDesc
+{
+ IDirect3DIndexBuffer9 *m_idxBuffer;
+};
+
+// we latch sampler values until draw time and then convert them all to GL form
+// note these are similar in name to the fields of a GLMTexSamplingParams but contents are not
+// particularly in the texture filtering area
+
+struct D3DSamplerDesc
+{
+ D3DTEXTUREADDRESS m_addressModes[3]; // D3DTEXTUREADDRESS modes for S,T,R
+ DWORD m_borderColor; // DWORD bordercolor
+ D3DTEXTUREFILTERTYPE m_magFilter; // mag filter
+ D3DTEXTUREFILTERTYPE m_minFilter; // min filter
+ D3DTEXTUREFILTERTYPE m_mipFilter; // mip filter
+ float m_mipmapBias; // float: mipmap bias
+ DWORD m_maxMipLevel; // DWORD 0..(n-1) LOD index of largest map to use (0 == largest)
+ DWORD m_maxAniso; // D3DSAMP_MAXANISOTROPY max aniso
+ DWORD m_srgb; // D3DSAMP_SRGBTEXTURE 0 = no SRGB sampling
+ DWORD m_shadowFilter; // D3DSAMP_SHADOWFILTER
+};
+
+struct IDirect3DDevice9 : public IUnknown
+{
+public:
+ // members
+
+ IDirect3DDevice9Params m_params; // mirror of the creation inputs
+
+ // D3D flavor stuff
+ IDirect3DSurface9 *m_rtSurfaces[16]; // current color RT surfaces. [0] is initially == m_defaultColorSurface
+ IDirect3DSurface9 *m_dsSurface; // current DS RT surface. can be changed!
+
+ IDirect3DSurface9 *m_defaultColorSurface; // default color surface.
+ IDirect3DSurface9 *m_defaultDepthStencilSurface; // queried by GetDepthStencilSurface.
+
+ IDirect3DVertexDeclaration9 *m_vertDecl; // Set by SetVertexDeclaration...
+ D3DStreamDesc m_streams[ D3D_MAX_STREAMS ]; // Set by SetStreamSource..
+ D3DIndexDesc m_indices; // Set by SetIndices..
+
+ IDirect3DVertexShader9 *m_vertexShader; // Set by SetVertexShader...
+ IDirect3DPixelShader9 *m_pixelShader; // Set by SetPixelShader...
+
+ IDirect3DBaseTexture9 *m_textures[16]; // set by SetTexture... NULL if stage inactive
+ D3DSamplerDesc m_samplers[16]; // set by SetSamplerState..
+ // GLM flavor stuff
+ GLMContext *m_ctx;
+ CGLMFBO *m_drawableFBO; // this FBO should have all the attachments set to match m_rtSurfaces and m_dsSurface.
+
+ // GL state
+ struct
+ {
+ // render state buckets
+ GLAlphaTestEnable_t m_AlphaTestEnable;
+ GLAlphaTestFunc_t m_AlphaTestFunc;
+
+ GLAlphaToCoverageEnable_t m_AlphaToCoverageEnable;
+
+ GLDepthTestEnable_t m_DepthTestEnable;
+ GLDepthMask_t m_DepthMask;
+ GLDepthFunc_t m_DepthFunc;
+
+ GLClipPlaneEnable_t m_ClipPlaneEnable[kGLMUserClipPlanes];
+ GLClipPlaneEquation_t m_ClipPlaneEquation[kGLMUserClipPlanes];
+
+ GLColorMaskSingle_t m_ColorMaskSingle;
+ GLColorMaskMultiple_t m_ColorMaskMultiple;
+
+ GLCullFaceEnable_t m_CullFaceEnable;
+ GLCullFrontFace_t m_CullFrontFace;
+ GLPolygonMode_t m_PolygonMode;
+ GLDepthBias_t m_DepthBias;
+ GLScissorEnable_t m_ScissorEnable;
+ GLScissorBox_t m_ScissorBox;
+ GLViewportBox_t m_ViewportBox;
+ GLViewportDepthRange_t m_ViewportDepthRange;
+
+ GLBlendEnable_t m_BlendEnable;
+ GLBlendFactor_t m_BlendFactor;
+ GLBlendEquation_t m_BlendEquation;
+ GLBlendColor_t m_BlendColor;
+ GLBlendEnableSRGB_t m_BlendEnableSRGB;
+
+ GLStencilTestEnable_t m_StencilTestEnable;
+ GLStencilFunc_t m_StencilFunc;
+ GLStencilOp_t m_StencilOp;
+ GLStencilWriteMask_t m_StencilWriteMask;
+
+ GLClearColor_t m_ClearColor;
+ GLClearDepth_t m_ClearDepth;
+ GLClearStencil_t m_ClearStencil;
+
+ bool m_FogEnable; // not really pushed to GL, just latched here
+
+ // samplers
+ GLMTexSamplingParams m_samplers[ 16 ];
+
+ // bindings...hmmm...
+
+ // dirty-bits
+ uint m_stateDirtyMask; // covers the state blocks, indexed by 1<x = pV1->x - pV2->x;
+ pOut->y = pV1->y - pV2->y;
+ pOut->z = pV1->z - pV2->z;
+ return pOut;
+}
+
+D3DXINLINE D3DXVECTOR3* D3DXVec3Cross( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 )
+{
+ D3DXVECTOR3 v;
+
+ v.x = pV1->y * pV2->z - pV1->z * pV2->y;
+ v.y = pV1->z * pV2->x - pV1->x * pV2->z;
+ v.z = pV1->x * pV2->y - pV1->y * pV2->x;
+
+ *pOut = v;
+ return pOut;
+}
+
+D3DXINLINE FLOAT D3DXVec3Dot( CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 )
+{
+ return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z;
+}
+
+D3DXMATRIX* D3DXMatrixInverse( D3DXMATRIX *pOut, FLOAT *pDeterminant, CONST D3DXMATRIX *pM );
+
+D3DXMATRIX* D3DXMatrixTranspose( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM );
+
+D3DXPLANE* D3DXPlaneNormalize( D3DXPLANE *pOut, CONST D3DXPLANE *pP);
+
+D3DXVECTOR4* D3DXVec4Transform( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV, CONST D3DXMATRIX *pM );
+
+
+D3DXVECTOR4* D3DXVec4Normalize( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV );
+
+D3DXMATRIX* D3DXMatrixTranslation( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z );
+
+// Build an ortho projection matrix. (right-handed)
+D3DXMATRIX* D3DXMatrixOrthoOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn,FLOAT zf );
+
+D3DXMATRIX* D3DXMatrixPerspectiveRH( D3DXMATRIX *pOut, FLOAT w, FLOAT h, FLOAT zn, FLOAT zf );
+
+D3DXMATRIX* D3DXMatrixPerspectiveOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn, FLOAT zf );
+
+// Transform a plane by a matrix. The vector (a,b,c) must be normal.
+// M should be the inverse transpose of the transformation desired.
+D3DXPLANE* D3DXPlaneTransform( D3DXPLANE *pOut, CONST D3DXPLANE *pP, CONST D3DXMATRIX *pM );
+
+IDirect3D9 *Direct3DCreate9(UINT SDKVersion);
+
+void D3DPERF_SetOptions( DWORD dwOptions );
+
+HRESULT D3DXCompileShader(
+ LPCSTR pSrcData,
+ UINT SrcDataLen,
+ CONST D3DXMACRO* pDefines,
+ LPD3DXINCLUDE pInclude,
+ LPCSTR pFunctionName,
+ LPCSTR pProfile,
+ DWORD Flags,
+ LPD3DXBUFFER* ppShader,
+ LPD3DXBUFFER* ppErrorMsgs,
+ LPD3DXCONSTANTTABLE* ppConstantTable);
+
+#endif // USE_ACTUAL_DX
+
+// fake D3D usage constant for SRGB tex creation
+#define D3DUSAGE_TEXTURE_SRGB (0x80000000L)
+
+#endif // DXABSTRACT_H
+
diff --git a/My project/sdk/glmgr/glmdebug.h b/My project/sdk/glmgr/glmdebug.h
new file mode 100644
index 000000000..eb59c26fa
--- /dev/null
+++ b/My project/sdk/glmgr/glmdebug.h
@@ -0,0 +1,45 @@
+#ifndef GLMDEBUG_H
+#define GLMDEBUG_H
+
+// include this anywhere you need to be able to compile-out code related specifically to GLM debugging.
+
+// we expect DEBUG to be driven by the build system so you can include this header anywhere.
+// when we come out, GLMDEBUG will be defined to a value - 0, 1, or 2
+// 0 means no GLM debugging is possible
+// 1 means it's possible and resulted from being a debug build
+// 2 means it's possible and resulted from being manually forced on for a release build
+
+#ifdef POSIX
+ #ifndef GLMDEBUG
+ #ifdef DEBUG
+ #define GLMDEBUG 1 // normally 1 here, testing
+ #else
+ // #define GLMDEBUG 2 // don't check this in enabled..
+ #endif
+
+ #ifndef GLMDEBUG
+ #define GLMDEBUG 0
+ #endif
+ #endif
+#else
+ #ifndef GLMDEBUG
+ #define GLMDEBUG 0
+ #endif
+#endif
+
+// helpful macro if you are in a position to call GLM functions directly (i.e. you live in materialsystem / shaderapidx9)
+#if GLMDEBUG
+ #define GLMPRINTF(args) GLMPrintf args
+ #define GLMPRINTSTR(args) GLMPrintStr args
+ #define GLMPRINTTEXT(args) GLMPrintText args
+ #define GLMBEGINPIXEVENT(args) GLMBeginPIXEvent args
+ #define GLMENDPIXEVENT(args) GLMEndPIXEvent args
+#else
+ #define GLMPRINTF(args)
+ #define GLMPRINTSTR(args)
+ #define GLMPRINTTEXT(args)
+ #define GLMBEGINPIXEVENT(args)
+ #define GLMENDPIXEVENT(args)
+#endif
+
+#endif
diff --git a/My project/sdk/glmgr/glmdisplay.h b/My project/sdk/glmgr/glmdisplay.h
new file mode 100644
index 000000000..9bfe2e4ce
--- /dev/null
+++ b/My project/sdk/glmgr/glmdisplay.h
@@ -0,0 +1,275 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// glmdisplay.h
+// display related stuff - used by both GLMgr and the CocoaMgr
+//
+//===============================================================================
+
+#ifndef GLMDISPLAY_H
+#define GLMDISPLAY_H
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "glmgrbasics.h"
+
+typedef void _PseudoNSGLContext; // aka NSOpenGLContext
+typedef _PseudoNSGLContext *PseudoNSGLContextPtr;
+
+struct GLMDisplayModeInfoFields
+{
+ uint m_modePixelWidth;
+ uint m_modePixelHeight;
+ uint m_modeRefreshHz;
+ // are we even going to talk about bit depth... not yet
+};
+
+struct GLMDisplayInfoFields
+{
+ CGDirectDisplayID m_cgDisplayID;
+ CGOpenGLDisplayMask m_glDisplayMask; // result of CGDisplayIDToOpenGLDisplayMask on the cg_displayID.
+
+ uint m_displayPixelWidth;
+ uint m_displayPixelHeight;
+};
+
+struct GLMRendererInfoFields
+{
+ /*properties of interest and their desired values.
+
+ kCGLRPFullScreen = 54, true
+ kCGLRPAccelerated = 73, true
+ kCGLRPWindow = 80, true
+
+ kCGLRPRendererID = 70, informational
+ kCGLRPDisplayMask = 84, informational
+ kCGLRPBufferModes = 100, informational
+ kCGLRPColorModes = 103, informational
+ kCGLRPAccumModes = 104, informational
+ kCGLRPDepthModes = 105, informational
+ kCGLRPStencilModes = 106, informational
+ kCGLRPMaxAuxBuffers = 107, informational
+ kCGLRPMaxSampleBuffers = 108, informational
+ kCGLRPMaxSamples = 109, informational
+ kCGLRPSampleModes = 110, informational
+ kCGLRPSampleAlpha = 111, informational
+ kCGLRPVideoMemory = 120, informational
+ kCGLRPTextureMemory = 121, informational
+ kCGLRPRendererCount = 128 number of renderers in the CGLRendererInfoObj under examination
+
+ kCGLRPOffScreen = 53, D/C
+ kCGLRPRobust = 75, FALSE or D/C - aka we're asking for no-fallback
+ kCGLRPBackingStore = 76, D/C
+ kCGLRPMPSafe = 78, D/C
+ kCGLRPMultiScreen = 81, D/C
+ kCGLRPCompliant = 83, D/C
+ */
+
+
+ //--------------------------- info we have from CGL renderer queries, IOKit, Gestalt
+ //--------------------------- these are set up in the displayDB by CocoaMgr
+ GLint m_fullscreen;
+ GLint m_accelerated;
+ GLint m_windowed;
+
+ GLint m_rendererID;
+ GLint m_displayMask;
+ GLint m_bufferModes;
+ GLint m_colorModes;
+ GLint m_accumModes;
+ GLint m_depthModes;
+ GLint m_stencilModes;
+
+ GLint m_maxAuxBuffers;
+ GLint m_maxSampleBuffers;
+ GLint m_maxSamples;
+ GLint m_sampleModes;
+ GLint m_sampleAlpha;
+
+ GLint m_vidMemory;
+ GLint m_texMemory;
+
+ uint m_pciVendorID;
+ uint m_pciDeviceID;
+ char m_pciModelString[64];
+ char m_driverInfoString[64];
+
+ //--------------------------- OS version related - set up by CocoaMgr
+
+ // OS version found
+ uint m_osComboVersion; // 0x00XXYYZZ : XX major, YY minor, ZZ minor minor : 10.6.3 --> 0x000A0603. 10.5.8 --> 0x000A0508.
+
+ //--------------------------- shorthands - also set up by CocoaMgr - driven by vendorid / deviceid
+
+ bool m_ati;
+ bool m_atiR5xx;
+ bool m_atiR6xx;
+ bool m_atiR7xx;
+ bool m_atiR8xx;
+ bool m_atiNewer;
+
+ bool m_intel;
+ bool m_intel95x;
+ bool m_intel3100;
+ bool m_intelNewer;
+
+ bool m_nv;
+ bool m_nvG7x;
+ bool m_nvG8x;
+ bool m_nvNewer;
+
+ //--------------------------- context query results - left blank in the display DB - but valid in a GLMContext (call ctx->Caps() to get a const ref)
+
+ // booleans
+ bool m_hasGammaWrites; // aka glGetBooleanv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT) / glEnable(GL_FRAMEBUFFER_SRGB_EXT)
+ bool m_hasMixedAttachmentSizes; // aka ARB_fbo in 10.6.3 - test for min OS vers, then exported ext string
+ bool m_hasBGRA; // aka GL_BGRA vertex attribs in 10.6.3 - - test for min OS vers, then exported ext string
+ bool m_hasNewFullscreenMode; // aka 10.6.x "big window" fullscreen mode
+ bool m_hasNativeClipVertexMode; // aka GLSL gl_ClipVertex does not fall back to SW- OS version and folklore-based
+ bool m_hasOcclusionQuery; // occlusion query: do you speak it ?!
+ bool m_hasFramebufferBlit; // framebuffer blit: know what I'm sayin?!
+ bool m_hasPerfPackage1; // means new MTGL, fast OQ, fast uniform upload, NV can resolve flipped (late summer 2010 post 10.6.4 update)
+
+ // counts
+ int m_maxAniso; // aniso limit - context query
+
+ // other exts
+ bool m_hasBindableUniforms;
+ bool m_hasUniformBuffers;
+
+ // runtime options that aren't negotiable once set
+ bool m_hasDualShaders; // must supply CLI arg "-glmdualshaders" or we go GLSL only
+
+ //--------------------------- " can'ts " - specific problems that need to be worked around
+
+ bool m_cantBlitReliably; // Intel chipsets have problems blitting sRGB sometimes
+ bool m_cantAttachSRGB; // NV G8x on 10.5.8 can't have srgb tex on FBO color - separate issue from hasGammaWrites
+ bool m_cantResolveFlipped; // happens on NV in 10.6.4 and prior - console variable "gl_can_resolve_flipped" can overrule
+ bool m_cantResolveScaled; // happens everywhere per GL spec but may be relaxed some day - console variable "gl_can_resolve_scaled" can overrule
+ bool m_costlyGammaFlips; // this means that sRGB sampling state affects shader code gen, resulting in state-dependent code regen
+
+
+ //--------------------------- " bads " - known bad drivers
+ bool m_badDriver1064NV; // this is the bad NVIDIA driver on 10.6.4 - stutter, tex corruption, black screen issues
+};
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+
+// this stuff is all sitting in glmgrcocoa.mm since it needs to make ObjC calls.
+
+//===============================================================================
+
+// modes, displays, and renderers
+// think of renderers as being at the top of a tree.
+// each renderer has displays hanging off of it.
+// each display has modes hanging off of it.
+// the tree is populated on demand and then queried as needed.
+
+//===============================================================================
+
+// GLMDisplayModeInfoFields is in glmdisplay.h
+
+class GLMDisplayMode
+{
+public:
+ GLMDisplayModeInfoFields m_info;
+
+ GLMDisplayMode( uint width, uint height, uint refreshHz );
+ ~GLMDisplayMode( void );
+
+ void Dump( int which );
+};
+
+//===============================================================================
+
+// GLMDisplayInfoFields is in glmdisplay.h
+
+class GLMDisplayInfo
+{
+public:
+ GLMDisplayInfoFields m_info;
+ std::vector< GLMDisplayMode* > *m_modes; // starts out NULL, set by PopulateModes
+
+ GLMDisplayInfo( CGDirectDisplayID displayID, CGOpenGLDisplayMask displayMask );
+ ~GLMDisplayInfo( void );
+
+ void PopulateModes( void );
+
+ void Dump( int which );
+};
+
+//===============================================================================
+
+// GLMRendererInfoFields is in glmdisplay.h
+
+class GLMRendererInfo
+{
+public:
+ GLMRendererInfoFields m_info;
+ std::vector< GLMDisplayInfo* > *m_displays; // starts out NULL, set by PopulateDisplays
+
+ GLMRendererInfo ( GLMRendererInfoFields *info );
+ ~GLMRendererInfo ( void );
+
+ void PopulateDisplays( void );
+ void Dump( int which );
+};
+
+//===============================================================================
+
+// this is just a tuple describing fake adapters which are really renderer/display pairings.
+// dxabstract bridges the gap between the d3d adapter-centric world and the GL renderer+display world.
+// this makes it straightforward to handle cases like two video cards with two displays on one, and one on the other -
+// you get three fake adapters which represent each useful screen.
+
+// the constraint that dxa will have to follow though, is that if the user wants to change their
+// display selection for full screen, they would only be able to pick on that has the same underlying renderer.
+// can't change fakeAdapter from one to another with different GL renderer under it. Screen hop but no card hop.
+
+struct GLMFakeAdapter
+{
+ int m_rendererIndex;
+ int m_displayIndex;
+};
+
+class GLMDisplayDB
+{
+public:
+ std::vector< GLMRendererInfo* > *m_renderers; // starts out NULL, set by PopulateRenderers
+
+ std::vector< GLMFakeAdapter > m_fakeAdapters;
+
+ GLMDisplayDB ( void );
+ ~GLMDisplayDB ( void );
+
+ virtual void PopulateRenderers( void );
+ virtual void PopulateFakeAdapters( uint realRendererIndex ); // fake adapters = one real adapter times however many displays are on it
+ virtual void Populate( void );
+
+ // The info-get functions return false on success.
+ virtual int GetFakeAdapterCount( void );
+ virtual bool GetFakeAdapterInfo( int fakeAdapterIndex, int *rendererOut, int *displayOut, GLMRendererInfoFields *rendererInfoOut, GLMDisplayInfoFields *displayInfoOut );
+
+ virtual int GetRendererCount( void );
+ virtual bool GetRendererInfo( int rendererIndex, GLMRendererInfoFields *infoOut );
+
+ virtual int GetDisplayCount( int rendererIndex );
+ virtual bool GetDisplayInfo( int rendererIndex, int displayIndex, GLMDisplayInfoFields *infoOut );
+
+ virtual int GetModeCount( int rendererIndex, int displayIndex );
+ virtual bool GetModeInfo( int rendererIndex, int displayIndex, int modeIndex, GLMDisplayModeInfoFields *infoOut );
+
+ virtual void Dump( void );
+};
+
+
+
+#endif
diff --git a/My project/sdk/glmgr/glmgr.cpp b/My project/sdk/glmgr/glmgr.cpp
new file mode 100644
index 000000000..699fd9a0d
--- /dev/null
+++ b/My project/sdk/glmgr/glmgr.cpp
@@ -0,0 +1,7113 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// glmgr.cpp
+//
+//===============================================================================
+
+#include "glmgr.h"
+#include "glmdisplay.h"
+#include "dxabstract.h" // need to be able to see D3D enums
+#include "../SteamWorksExample/gameengineosx.h"
+
+extern CGameEngineGL *g_engine; // so glmgr (which is C++) can call up to the game engine ObjC object and ask for things..
+
+#ifdef __clang__
+#pragma clang diagnostic warning "-Wint-to-pointer-cast"
+#pragma clang diagnostic ignored "-Wunused-variable"
+#endif
+
+#ifdef OSX
+// Debugger - 10.8
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+
+//===============================================================================
+
+char g_nullFragmentProgramText [] =
+{
+ "!!ARBfp1.0 \n"
+ "PARAM black = { 0.0, 0.0, 0.0, 1.0 }; \n" // opaque black
+ "MOV result.color, black; \n"
+ "END \n\n\n"
+ "//GLSLfp\n"
+ "void main()\n"
+ "{\n"
+ "gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n"
+ "}\n"
+
+};
+
+
+
+ // make dummy programs for doing texture preload via dummy draw
+char g_preloadTexVertexProgramText[] =
+{
+ "//GLSLvp \n"
+ "#version 120 \n"
+ "varying vec4 otex; \n"
+ "void main() \n"
+ "{ \n"
+ "vec4 pos = ftransform(); // vec4( 0.1, 0.1, 0.1, 0.1 ); \n"
+ "vec4 tex = vec4( 0.0, 0.0, 0.0, 0.0 ); \n"
+ " \n"
+ "gl_Position = pos; \n"
+ "otex = tex; \n"
+ "} \n"
+};
+
+char g_preload2DTexFragmentProgramText[] =
+{
+ "//GLSLfp \n"
+ "#version 120 \n"
+ "varying vec4 otex; \n"
+ "//SAMPLERMASK-8000 // may not be needed \n"
+ "//HIGHWATER-30 // may not be needed \n"
+ " \n"
+ "uniform vec4 pc[31]; \n"
+ "uniform sampler2D sampler15; \n"
+ " \n"
+ "void main() \n"
+ "{ \n"
+ "vec4 r0; \n"
+ "r0 = texture2D( sampler15, otex.xy ); \n"
+ "gl_FragColor = r0; //discard; \n"
+ "} \n"
+};
+
+char g_preload3DTexFragmentProgramText[] =
+{
+ "//GLSLfp \n"
+ "#version 120 \n"
+ "varying vec4 otex; \n"
+ "//SAMPLERMASK-8000 // may not be needed \n"
+ "//HIGHWATER-30 // may not be needed \n"
+ " \n"
+ "uniform vec4 pc[31]; \n"
+ "uniform sampler3D sampler15; \n"
+ " \n"
+ "void main() \n"
+ "{ \n"
+ "vec4 r0; \n"
+ "r0 = texture3D( sampler15, otex.xyz ); \n"
+ "gl_FragColor = r0; //discard; \n"
+ "} \n"
+};
+
+char g_preloadCubeTexFragmentProgramText[] =
+{
+ "//GLSLfp \n"
+ "#version 120 \n"
+ "varying vec4 otex; \n"
+ "//SAMPLERMASK-8000 // may not be needed \n"
+ "//HIGHWATER-30 // may not be needed \n"
+ " \n"
+ "uniform vec4 pc[31]; \n"
+ "uniform samplerCube sampler15; \n"
+ " \n"
+ "void main() \n"
+ "{ \n"
+ "vec4 r0; \n"
+ "r0 = textureCube( sampler15, otex.xyz ); \n"
+ "gl_FragColor = r0; //discard; \n"
+ "} \n"
+};
+
+
+
+
+
+
+
+//===============================================================================
+// helper routines for debug
+
+static bool hasnonzeros( float *values, int count )
+{
+ for( int i=0; i [ %10.5f %10.5f %10.5f %10.5f ]",
+ baseSlotNumber+islot,
+ row[0],row[1],row[2],row[3],
+ col[0],col[1],col[2],col[3]
+ ));
+ }
+ else
+ {
+ if (islot<3)
+ {
+ GLMPRINTF(( "-D- %03d: [ %10.5f %10.5f %10.5f %10.5f ] T=> [ %10.5f %10.5f %10.5f ]",
+ baseSlotNumber+islot,
+ row[0],row[1],row[2],row[3],
+ col[0],col[1],col[2]
+ ));
+ }
+ else
+ {
+ GLMPRINTF(( "-D- %03d: T=> [ %10.5f %10.5f %10.5f ]",
+ baseSlotNumber+islot,
+ col[0],col[1],col[2]
+ ));
+ }
+ }
+ }
+ GLMPRINTSTR(("-D-"));
+ }
+ else
+ {
+ GLMPRINTF(("-D- %s - (all 0.0)", label ));
+ }
+
+}
+
+
+static void transform_dp4( float *in4, float *m00, int slots, float *out4 )
+{
+ // m00 points to a column.
+ // each DP is one column of the matrix ( m00[4*n]
+ // if we are passed a three slot matrix, this is three columns, the source W plays into all three columns, but we must set the final output W to 1 ?
+ for( int n=0; nm_ctx );
+ if (cgl_err)
+ {
+ // give up
+ GLMStop();
+ }
+}
+
+GLMContext *GLMgr::GetCurrentContext( void )
+{
+ CGLContextObj ctx = CGLGetCurrentContext();
+
+ GLint glm_context_link = 0;
+
+ CGLGetParameter( ctx, kCGLCPClientStorage, &glm_context_link );
+
+ if ( glm_context_link )
+ {
+ return (GLMContext*)(uintptr_t)glm_context_link;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+//===============================================================================
+// GLMContext public methods
+void GLMContext::MakeCurrent( void )
+{
+// GLM_FUNC;
+
+ CGLSetCurrentContext( m_ctx );
+}
+
+void GLMContext::CheckCurrent( void )
+{
+ #if 1
+// GLM_FUNC;
+
+ // probably want to make this a no-op for release builds
+ // but we can't, because someone is messing with current context and not sure where yet
+ CGLContextObj curr = CGLGetCurrentContext();
+ if (curr != m_ctx)
+ {
+ if (1 /*!CommandLine()->FindParm("-hushasserts") */)
+ {
+ Assert( !"Current context mismatch");
+
+ #if GLMDEBUG
+ Debugger();
+ #endif
+ }
+ MakeCurrent(); // you're welcome
+ }
+ #endif
+}
+
+
+const GLMRendererInfoFields& GLMContext::Caps( void )
+{
+ return m_caps;
+}
+
+void GLMContext::DumpCaps( void )
+{
+ /*
+ #define dumpfield( fff ) printf( "\n "#fff" : %d", (int) m_caps.fff )
+ #define dumpfield_hex( fff ) printf( "\n "#fff" : 0x%08x", (int) m_caps.fff )
+ #define dumpfield_str( fff ) printf( "\n "#fff" : %s", m_caps.fff )
+ */
+
+ #define dumpfield( fff ) printf( "\n %-30s : %d", #fff, (int) m_caps.fff )
+ #define dumpfield_hex( fff ) printf( "\n %-30s : 0x%08x", #fff, (int) m_caps.fff )
+ #define dumpfield_str( fff ) printf( "\n %-30s : %s", #fff, m_caps.fff )
+
+ printf("\n-------------------------------- context caps for context %p", this);
+
+ dumpfield( m_fullscreen );
+ dumpfield( m_accelerated );
+ dumpfield( m_windowed );
+ dumpfield_hex( m_rendererID );
+ dumpfield( m_displayMask );
+ dumpfield( m_bufferModes );
+ dumpfield( m_colorModes );
+ dumpfield( m_accumModes );
+ dumpfield( m_depthModes );
+ dumpfield( m_stencilModes );
+ dumpfield( m_maxAuxBuffers );
+ dumpfield( m_maxSampleBuffers );
+ dumpfield( m_maxSamples );
+ dumpfield( m_sampleModes );
+ dumpfield( m_sampleAlpha );
+ dumpfield_hex( m_vidMemory );
+ dumpfield_hex( m_texMemory );
+
+ dumpfield_hex( m_pciVendorID );
+ dumpfield_hex( m_pciDeviceID );
+ dumpfield_str( m_pciModelString );
+ dumpfield_str( m_driverInfoString );
+
+ printf( "\n m_osComboVersion: 0x%08x (%d.%d.%d)", m_caps.m_osComboVersion, (m_caps.m_osComboVersion>>16)&0xFF, (m_caps.m_osComboVersion>>8)&0xFF, (m_caps.m_osComboVersion)&0xFF );
+
+ dumpfield( m_ati );
+ if (m_caps.m_ati)
+ {
+ dumpfield( m_atiR5xx );
+ dumpfield( m_atiR6xx );
+ dumpfield( m_atiR7xx );
+ dumpfield( m_atiR8xx );
+ dumpfield( m_atiNewer );
+ }
+
+ dumpfield( m_intel );
+ if (m_caps.m_intel)
+ {
+ dumpfield( m_intel95x );
+ dumpfield( m_intel3100 );
+ dumpfield( m_intelNewer );
+ }
+
+ dumpfield( m_nv );
+ if (m_caps.m_nv)
+ {
+ //dumpfield( m_nvG7x );
+ dumpfield( m_nvG8x );
+ dumpfield( m_nvNewer );
+ }
+
+ dumpfield( m_hasGammaWrites );
+ dumpfield( m_hasMixedAttachmentSizes );
+ dumpfield( m_hasBGRA );
+ dumpfield( m_hasNewFullscreenMode );
+ dumpfield( m_hasNativeClipVertexMode );
+ dumpfield( m_maxAniso );
+ dumpfield( m_hasBindableUniforms );
+ dumpfield( m_hasUniformBuffers );
+ dumpfield( m_hasPerfPackage1 );
+
+ dumpfield( m_cantBlitReliably );
+ dumpfield( m_cantAttachSRGB );
+ dumpfield( m_cantResolveFlipped );
+ dumpfield( m_cantResolveScaled );
+ dumpfield( m_costlyGammaFlips );
+ dumpfield( m_badDriver1064NV );
+
+ printf("\n--------------------------------");
+
+ #undef dumpfield
+ #undef dumpfield_hex
+ #undef dumpfield_str
+}
+
+void DefaultSamplingParams( GLMTexSamplingParams *samp, GLMTexLayoutKey *key )
+{
+ memset( samp, 0, sizeof(*samp) );
+
+ // Default to black, it may make drivers happier
+ samp->m_borderColor[0] = 0.0f;
+ samp->m_borderColor[0] = 0.0f;
+ samp->m_borderColor[0] = 0.0f;
+ samp->m_borderColor[0] = 1.0f;
+
+ // generally speaking..
+ // if it's a render target, default it to GL_CLAMP_TO_BORDER, else GL_REPEAT
+ // if it has mipmaps, default the min filter to GL_LINEAR_MIPMAP_LINEAR, else GL_LINEAR
+
+ // ** none of these really matter all that much because the first time we go to render, the d3d sampler state will be consulted
+ // and applied directly to the tex object without regard to any previous values..
+
+ GLenum rtclamp = GL_CLAMP_TO_EDGE; //GL_CLAMP_TO_BORDER
+
+ switch( key->m_texFlags & (kGLMTexRenderable|kGLMTexMipped) )
+ {
+ case 0:
+ // -- mipped, -- renderable
+ samp->m_addressModes[0] = GL_REPEAT;
+ samp->m_addressModes[1] = GL_REPEAT;
+ samp->m_addressModes[2] = GL_REPEAT;
+
+ samp->m_magFilter = GL_LINEAR;
+ samp->m_minFilter = GL_LINEAR;
+ break;
+
+ case kGLMTexRenderable:
+ // -- mipped, ++ renderable
+ samp->m_addressModes[0] = rtclamp;
+ samp->m_addressModes[1] = rtclamp;
+ samp->m_addressModes[2] = rtclamp;
+
+ samp->m_magFilter = GL_LINEAR;
+ samp->m_minFilter = GL_LINEAR;
+ break;
+
+ case kGLMTexMipped:
+ // ++ mipped, -- renderable
+ samp->m_addressModes[0] = GL_REPEAT;
+ samp->m_addressModes[1] = GL_REPEAT;
+ samp->m_addressModes[2] = GL_REPEAT;
+
+ samp->m_magFilter = GL_LINEAR;
+ samp->m_minFilter = GL_LINEAR_MIPMAP_LINEAR; // was GL_NEAREST_MIPMAP_LINEAR;
+ break;
+
+ case kGLMTexRenderable | kGLMTexMipped:
+ // ++ mipped, ++ renderable
+ samp->m_addressModes[0] = rtclamp;
+ samp->m_addressModes[1] = rtclamp;
+ samp->m_addressModes[2] = rtclamp;
+
+ samp->m_magFilter = GL_LINEAR;
+ samp->m_minFilter = GL_LINEAR_MIPMAP_LINEAR; // was GL_NEAREST_MIPMAP_LINEAR;
+ break;
+
+ }
+
+ samp->m_mipmapBias = 0.0f;
+
+ samp->m_minMipLevel = 0; // this drives GL_TEXTURE_MIN_LOD - i.e. lowest MIP selection index clamp (largest size), not "slice defined" boundary
+ samp->m_maxMipLevel = 16; // this drives GL_TEXTURE_MAX_LOD - i.e. highest MIP selection clamp (smallest size), not "slice defined" boundary
+
+ samp->m_maxAniso = 1;
+ samp->m_compareMode = GL_NONE; // only for depth or stencil tex
+
+ samp->m_srgb = false;
+}
+
+CGLMTex *GLMContext::NewTex( GLMTexLayoutKey *key, const char *debugLabel )
+{
+ //hushed GLM_FUNC;
+ MakeCurrent();
+
+ // get a layout based on the key
+ GLMTexLayout *layout = m_texLayoutTable->NewLayoutRef( key );
+
+ GLMTexSamplingParams defsamp;
+ DefaultSamplingParams( &defsamp, key );
+
+ CGLMTex *tex = new CGLMTex( this, layout, &defsamp, debugLabel );
+
+ return tex;
+}
+
+void GLMContext::DelTex( CGLMTex *tex )
+{
+ //hushed GLM_FUNC;
+ MakeCurrent();
+
+ for( int i=0; iBindTexToTMU( NULL, i );
+ m_samplers[i].m_boundTex = NULL; // for clarity
+
+ tex->m_bindPoints &= ~(1<m_rtAttachCount !=0)
+ {
+ // leak it and complain - we may have to implement a deferred-delete system for tex like these
+
+ GLMPRINTF(("-D- ################## Leaking tex %08x [ %s ] - was attached for drawing at time of delete",tex, tex->m_layout->m_layoutSummary ));
+
+ #if 0
+ // can't actually do this yet as the draw calls will tank
+ FOR_EACH_VEC( m_fboTable, i )
+ {
+ CGLMFBO *fbo = m_fboTable[i];
+ fbo->TexScrub( tex );
+ }
+ tex->m_rtAttachCount = 0;
+ #endif
+ }
+ else
+ {
+ delete tex;
+ }
+}
+
+
+
+ // push and pop attrib when blit has mixed srgb source and dest?
+//ConVar gl_radar7954721_workaround_mixed ( "gl_radar7954721_workaround_mixed", "1" );
+int gl_radar7954721_workaround_mixed = 1;
+
+ // push and pop attrib on any blit?
+//ConVar gl_radar7954721_workaround_all ( "gl_radar7954721_workaround_all", "0" );
+int gl_radar7954721_workaround_all = 0;
+
+ // what attrib mask to use ?
+//ConVar gl_radar7954721_workaround_maskval ( "gl_radar7954721_workaround_maskval", "0" );
+int gl_radar7954721_workaround_maskval = 0;
+
+enum eBlitFormatClass
+{
+ eColor,
+ eDepth, // may not get used. not sure..
+ eDepthStencil
+};
+
+uint glAttachFromClass[ 3 ] = { GL_COLOR_ATTACHMENT0_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_STENCIL_ATTACHMENT_EXT };
+
+void glScrubFBO ( GLenum target )
+{
+ glFramebufferRenderbufferEXT ( target, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0); GLMCheckError();
+ glFramebufferRenderbufferEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); GLMCheckError();
+ glFramebufferRenderbufferEXT ( target, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); GLMCheckError();
+
+ glFramebufferTexture2DEXT ( target, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0 ); GLMCheckError();
+ glFramebufferTexture2DEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0 ); GLMCheckError();
+ glFramebufferTexture2DEXT ( target, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0 ); GLMCheckError();
+}
+
+void glAttachRBOtoFBO ( GLenum target, eBlitFormatClass formatClass, uint rboName )
+{
+ switch( formatClass )
+ {
+ case eColor:
+ glFramebufferRenderbufferEXT ( target, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, rboName); GLMCheckError();
+ break;
+
+ case eDepth:
+ glFramebufferRenderbufferEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboName); GLMCheckError();
+ break;
+
+ case eDepthStencil:
+ glFramebufferRenderbufferEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboName); GLMCheckError();
+ glFramebufferRenderbufferEXT ( target, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboName); GLMCheckError();
+ break;
+ }
+}
+
+void glAttachTex2DtoFBO ( GLenum target, eBlitFormatClass formatClass, uint texName, uint texMip )
+{
+ switch( formatClass )
+ {
+ case eColor:
+ glFramebufferTexture2DEXT ( target, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texName, texMip ); GLMCheckError();
+ break;
+
+ case eDepth:
+ glFramebufferTexture2DEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texName, texMip ); GLMCheckError();
+ break;
+
+ case eDepthStencil:
+ glFramebufferTexture2DEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texName, texMip ); GLMCheckError();
+ glFramebufferTexture2DEXT ( target, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texName, texMip ); GLMCheckError();
+ break;
+ }
+}
+
+//ConVar gl_can_resolve_flipped("gl_can_resolve_flipped", "0" );
+int gl_can_resolve_flipped = 0;
+
+//ConVar gl_cannot_resolve_flipped("gl_cannot_resolve_flipped", "0" );
+int gl_cannot_resolve_flipped = 0;
+
+
+// these are only consulted if the m_cant_resolve_scaled cap bool is false.
+
+//ConVar gl_minify_resolve_mode("gl_minify_resolve_mode", "1" ); // if scaled resolve available, for downscaled resolve blits only (i.e. internal blits)
+int gl_minify_resolve_mode = 1;
+
+//ConVar gl_magnify_resolve_mode("gl_magnify_resolve_mode", "2" ); // if scaled resolve available, for upscaled resolve blits only
+int gl_magnify_resolve_mode = 2;
+
+
+ // 0 == old style, two steps
+ // 1 == faster, one step blit aka XGL_SCALED_RESOLVE_FASTEST_EXT - if available.
+ // 2 == faster, one step blit aka XGL_SCALED_RESOLVE_NICEST_EXT - if available.
+
+unsigned short foo[4];
+
+void GLMContext::Blit2( CGLMTex *srcTex, GLMRect *srcRect, int srcFace, int srcMip, CGLMTex *dstTex, GLMRect *dstRect, int dstFace, int dstMip, uint filter )
+{
+ Assert( srcFace == 0 );
+ Assert( dstFace == 0 );
+
+// glColor4usv( foo );
+
+ //----------------------------------------------------------------- format assessment
+
+ eBlitFormatClass formatClass;
+ uint blitMask= 0;
+
+ switch( srcTex->m_layout->m_format->m_glDataFormat )
+ {
+ case GL_BGRA: case GL_RGB: case GL_RGBA: case GL_ALPHA: case GL_LUMINANCE: case GL_LUMINANCE_ALPHA:
+ formatClass = eColor;
+ blitMask = GL_COLOR_BUFFER_BIT;
+ break;
+
+ case GL_DEPTH_COMPONENT:
+ formatClass = eDepth;
+ blitMask = GL_DEPTH_BUFFER_BIT;
+ break;
+
+ case GL_DEPTH_STENCIL_EXT:
+ formatClass = eDepthStencil;
+ blitMask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
+ break;
+
+ default:
+ Assert(!"Unsupported format for blit" );
+ GLMStop();
+ break;
+ }
+
+ //----------------------------------------------------------------- blit assessment
+
+
+ bool blitResolves = srcTex->m_rboName != 0;
+ bool blitScales = ((srcRect->xmax - srcRect->xmin) != (dstRect->xmax - dstRect->xmin)) || ((srcRect->ymax - srcRect->ymin) != (dstRect->ymax - dstRect->ymin));
+
+ bool blitToBack = (dstTex == NULL);
+ bool blitFlips = blitToBack; // implicit y-flip upon blit to GL_BACK supplied
+
+ //should we support blitFromBack ?
+
+ bool srcGamma = srcTex && ((srcTex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0);
+ bool dstGamma = dstTex && ((dstTex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0);
+
+ bool doPushPop = (srcGamma != dstGamma) && gl_radar7954721_workaround_mixed/*.GetInt()*/ && m_caps.m_nv; // workaround for cross gamma blit problems on NV
+ // ^^ need to re-check this on some post-10.6.3 build on NV to see if it was fixed
+
+ if (doPushPop)
+ {
+ glPushAttrib( 0 );
+ }
+
+ //----------------------------------------------------------------- figure out the plan
+
+ bool blitTwoStep = false; // think positive
+
+ // each subsequent segment here can only set blitTwoStep, not clear it.
+ // the common case where these get hit is resolve out to presentation
+ // there may be GL extensions or driver revisions which start doing these safely.
+ // ideally many blits internally resolve without scaling and can thus go direct without using the scratch tex.
+
+ if (blitResolves && (blitFlips||blitToBack)) // flips, blit to back, same thing (for now)
+ {
+ if( gl_cannot_resolve_flipped/*.GetInt()*/ )
+ {
+ blitTwoStep = true;
+ }
+ else if (!gl_can_resolve_flipped/*.GetInt()*/)
+ {
+ blitTwoStep = blitTwoStep || m_caps.m_cantResolveFlipped; // if neither convar renders an opinion, fall back to the caps to decide if we have to two-step.
+ }
+ }
+
+ // only consider trying to use the scaling resolve filter,
+ // if we are confident we are not headed for two step mode already.
+ if (!blitTwoStep)
+ {
+ if (blitResolves && blitScales)
+ {
+ if (m_caps.m_cantResolveScaled)
+ {
+ // filter is unchanged, two step mode switches on
+ blitTwoStep = true;
+ }
+ else
+ {
+ bool blitScalesDown = ((srcRect->xmax - srcRect->xmin) > (dstRect->xmax - dstRect->xmin)) || ((srcRect->ymax - srcRect->ymin) > (dstRect->ymax - dstRect->ymin));
+ int mode = (blitScalesDown) ? gl_minify_resolve_mode/*.GetInt()*/ : gl_magnify_resolve_mode/*.GetInt()*/;
+
+ // roughly speaking, resolve blits that minify represent setup for special effects ("copy framebuffer to me")
+ // resolve blits that magnify are almost always on the final present in the case where remder size < display size
+
+ switch( mode )
+ {
+ case 0:
+ default:
+ // filter is unchanged, two step mode
+ blitTwoStep = true;
+ break;
+
+ case 1:
+ // filter goes to fastest, one step mode
+ blitTwoStep = false;
+ filter = XGL_SCALED_RESOLVE_FASTEST_EXT;
+ break;
+
+ case 2:
+ // filter goes to nicest, one step mode
+ blitTwoStep = false;
+ filter = XGL_SCALED_RESOLVE_NICEST_EXT;
+ break;
+ }
+ }
+ }
+ }
+
+ //----------------------------------------------------------------- save old scissor state and disable scissor
+ GLScissorEnable_t oldsciss,newsciss;
+ m_ScissorEnable.Read( &oldsciss, 0 );
+
+ // turn off scissor
+ newsciss.enable = false;
+ m_ScissorEnable.Write( &newsciss, true, true );
+
+ //----------------------------------------------------------------- fork in the road, depending on two-step or not
+ if (blitTwoStep)
+ {
+ // a resolve that can't be done directly due to constraints on scaling or flipping.
+
+ // bind scratch FBO0 to read, scrub it, attach RBO
+ BindFBOToCtx ( m_scratchFBO[0], GL_READ_FRAMEBUFFER_EXT ); GLMCheckError();
+ glScrubFBO ( GL_READ_FRAMEBUFFER_EXT );
+ glAttachRBOtoFBO ( GL_READ_FRAMEBUFFER_EXT, formatClass, srcTex->m_rboName );
+
+ // bind scratch FBO1 to write, scrub it, attach scratch tex
+ BindFBOToCtx ( m_scratchFBO[1], GL_DRAW_FRAMEBUFFER_EXT ); GLMCheckError();
+ glScrubFBO ( GL_DRAW_FRAMEBUFFER_EXT );
+ glAttachTex2DtoFBO ( GL_DRAW_FRAMEBUFFER_EXT, formatClass, srcTex->m_texName, 0 );
+
+ // set read and draw buffers appropriately
+ glReadBuffer ( glAttachFromClass[formatClass] );
+ glDrawBuffer ( glAttachFromClass[formatClass] );
+
+ // blit#1 - to resolve to scratch
+ // implicitly means no scaling, thus will be done with NEAREST sampling
+
+ GLenum resolveFilter = GL_NEAREST;
+
+ glBlitFramebufferEXT( 0, 0, srcTex->m_layout->m_key.m_xSize, srcTex->m_layout->m_key.m_ySize,
+ 0, 0, srcTex->m_layout->m_key.m_xSize, srcTex->m_layout->m_key.m_ySize, // same source and dest rect, whole surface
+ blitMask, resolveFilter );
+ GLMCheckError();
+
+ // FBO1 now holds the interesting content.
+ // scrub FBO0, bind FBO1 to READ, fall through to next stage of blit where 1 goes onto 0 (or BACK)
+
+ glScrubFBO ( GL_READ_FRAMEBUFFER_EXT ); // zap FBO0
+ BindFBOToCtx ( m_scratchFBO[1], GL_READ_FRAMEBUFFER_EXT ); GLMCheckError();
+ }
+ else
+ {
+ // arrange source surface on FBO1 for blit directly to dest (which could be FBO0 or BACK)
+ BindFBOToCtx ( m_scratchFBO[1], GL_READ_FRAMEBUFFER_EXT ); GLMCheckError();
+ glScrubFBO ( GL_READ_FRAMEBUFFER_EXT );
+ if (blitResolves)
+ {
+ glAttachRBOtoFBO( GL_READ_FRAMEBUFFER_EXT, formatClass, srcTex->m_rboName );
+ }
+ else
+ {
+ glAttachTex2DtoFBO( GL_READ_FRAMEBUFFER_EXT, formatClass, srcTex->m_texName, srcMip );
+ }
+
+ glReadBuffer( glAttachFromClass[formatClass] );
+ }
+
+ //----------------------------------------------------------------- zero or one blits may have happened above, whichever took place, FBO1 is now on read
+
+ bool yflip = false;
+ if (blitToBack)
+ {
+ // backbuffer is special - FBO0 is left out (either scrubbed already, or not used)
+
+ BindFBOToCtx ( NULL, GL_DRAW_FRAMEBUFFER_EXT ); GLMCheckError();
+ glDrawBuffer ( GL_BACK ); GLMCheckError();
+
+ yflip = true;
+ }
+ else
+ {
+ // not going to GL_BACK - use FBO0. set up dest tex or RBO on it. i.e. it's OK to blit from MSAA to MSAA if needed, though unlikely.
+ Assert( dstTex != NULL );
+
+ BindFBOToCtx ( m_scratchFBO[0], GL_DRAW_FRAMEBUFFER_EXT ); GLMCheckError();
+ glScrubFBO ( GL_DRAW_FRAMEBUFFER_EXT );
+
+ if (dstTex->m_rboName)
+ {
+ glAttachRBOtoFBO( GL_DRAW_FRAMEBUFFER_EXT, formatClass, dstTex->m_rboName );
+ }
+ else
+ {
+ glAttachTex2DtoFBO( GL_DRAW_FRAMEBUFFER_EXT, formatClass, dstTex->m_texName, dstMip );
+ }
+
+ glDrawBuffer ( glAttachFromClass[formatClass] ); GLMCheckError();
+ }
+
+ // final blit
+
+ // i think in general, if we are blitting same size, gl_nearest is the right filter to pass.
+ // this re-steering won't kick in if there is scaling or a special scaled resolve going on.
+ if (!blitScales)
+ {
+ // steer it
+ filter = GL_NEAREST;
+ }
+
+ // this is blit #1 or #2 depending on what took place above.
+ if (yflip)
+ {
+ glBlitFramebufferEXT( srcRect->xmin, srcRect->ymin, srcRect->xmax, srcRect->ymax,
+ dstRect->xmin, dstRect->ymax, dstRect->xmax, dstRect->ymin, // note dest Y's are flipped
+ blitMask, filter );
+ }
+ else
+ {
+ glBlitFramebufferEXT( srcRect->xmin, srcRect->ymin, srcRect->xmax, srcRect->ymax,
+ dstRect->xmin, dstRect->ymin, dstRect->xmax, dstRect->ymax,
+ blitMask, filter );
+ }
+ GLMCheckError();
+
+ //----------------------------------------------------------------- scrub READ and maybe DRAW FBO, and unbind
+
+ glScrubFBO ( GL_READ_FRAMEBUFFER_EXT );
+ BindFBOToCtx ( NULL, GL_READ_FRAMEBUFFER_EXT ); GLMCheckError();
+ if (!blitToBack)
+ {
+ glScrubFBO ( GL_DRAW_FRAMEBUFFER_EXT );
+ BindFBOToCtx ( NULL, GL_DRAW_FRAMEBUFFER_EXT ); GLMCheckError();
+ }
+
+ //----------------------------------------------------------------- restore GLM's drawing FBO
+
+ // restore GLM drawing FBO
+ BindFBOToCtx( m_drawingFBO, GL_READ_FRAMEBUFFER_EXT ); GLMCheckError();
+ BindFBOToCtx( m_drawingFBO, GL_DRAW_FRAMEBUFFER_EXT ); GLMCheckError();
+
+ if (doPushPop)
+ {
+ glPopAttrib( );
+ }
+
+
+ //----------------------------------------------------------------- restore old scissor state
+ m_ScissorEnable.Write( &oldsciss, true, true );
+}
+
+
+void GLMContext::BlitTex( CGLMTex *srcTex, GLMRect *srcRect, int srcFace, int srcMip, CGLMTex *dstTex, GLMRect *dstRect, int dstFace, int dstMip, GLenum filter, bool useBlitFB )
+{
+ switch( srcTex->m_layout->m_format->m_glDataFormat )
+ {
+ case GL_BGRA:
+ case GL_RGB:
+ case GL_RGBA:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ #if 0
+ if (GLMKnob("caps-key",NULL) > 0.0)
+ {
+ useBlitFB = false;
+ }
+ #endif
+
+ if ( m_caps.m_cantBlitReliably ) // this is referring to a problem with the x3100..
+ {
+ useBlitFB = false;
+ }
+ break;
+ }
+
+ if (0)
+ {
+ GLMPRINTF(("-D- Blit from %d %d %d %d to %d %d %d %d",
+ srcRect->xmin, srcRect->ymin, srcRect->xmax, srcRect->ymax,
+ dstRect->xmin, dstRect->ymin, dstRect->xmax, dstRect->ymax
+ ));
+
+ GLMPRINTF(( "-D- src tex layout is %s", srcTex->m_layout->m_layoutSummary ));
+ GLMPRINTF(( "-D- dst tex layout is %s", dstTex->m_layout->m_layoutSummary ));
+ }
+
+ int pushed = 0;
+ uint pushmask = gl_radar7954721_workaround_maskval/*.GetInt()*/;
+ //GL_COLOR_BUFFER_BIT
+ //| GL_CURRENT_BIT
+ //| GL_ENABLE_BIT
+ //| GL_FOG_BIT
+ //| GL_PIXEL_MODE_BIT
+ //| GL_SCISSOR_BIT
+ //| GL_STENCIL_BUFFER_BIT
+ //| GL_TEXTURE_BIT
+ //GL_VIEWPORT_BIT
+ //;
+
+ if (gl_radar7954721_workaround_all/*.GetInt()*/!=0)
+ {
+ glPushAttrib( pushmask );
+ pushed++;
+ }
+ else
+ {
+ bool srcGamma = (srcTex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0;
+ bool dstGamma = (dstTex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0;
+
+ if (srcGamma != dstGamma)
+ {
+ if (gl_radar7954721_workaround_mixed/*.GetInt()*/)
+ {
+ glPushAttrib( pushmask );
+ pushed++;
+ }
+ }
+ }
+
+ if (useBlitFB)
+ {
+ // state we need to save
+ // current setting of scissor
+ // current setting of the drawing fbo (no explicit save, it's in the context)
+ GLScissorEnable_t oldsciss,newsciss;
+ m_ScissorEnable.Read( &oldsciss, 0 );
+
+ // remember to restore m_drawingFBO at end of effort
+
+ // setup
+ // turn off scissor
+ newsciss.enable = false;
+ m_ScissorEnable.Write( &newsciss, true, true );
+
+ // select which attachment enum we're going to use for the blit
+ // default to color0, unless it's a depth or stencil flava
+
+ Assert( srcTex->m_layout->m_format->m_glDataFormat == dstTex->m_layout->m_format->m_glDataFormat );
+
+ EGLMFBOAttachment attachIndex = (EGLMFBOAttachment)0;
+ GLenum attachIndexGL = 0;
+ GLuint blitMask = 0;
+ switch( srcTex->m_layout->m_format->m_glDataFormat )
+ {
+ case GL_BGRA:
+ case GL_RGB:
+ case GL_RGBA:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ attachIndex = kAttColor0;
+ attachIndexGL = GL_COLOR_ATTACHMENT0_EXT;
+ blitMask = GL_COLOR_BUFFER_BIT;
+ break;
+
+ case GL_DEPTH_COMPONENT:
+ attachIndex = kAttDepth;
+ attachIndexGL = GL_DEPTH_ATTACHMENT_EXT;
+ blitMask = GL_DEPTH_BUFFER_BIT;
+ break;
+
+ case GL_DEPTH_STENCIL_EXT:
+ attachIndex = kAttDepthStencil;
+ attachIndexGL = GL_DEPTH_STENCIL_ATTACHMENT_EXT;
+ blitMask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
+ break;
+
+ default:
+ Assert(0);
+ break;
+ }
+
+ // set the read fb, attach read tex at appropriate attach point, set read buffer
+ BindFBOToCtx( m_blitReadFBO, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ GLMFBOTexAttachParams attparams;
+ attparams.m_tex = srcTex;
+ attparams.m_face = srcFace;
+ attparams.m_mip = srcMip;
+ attparams.m_zslice = 0;
+ m_blitReadFBO->TexAttach( &attparams, attachIndex, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ glReadBuffer( attachIndexGL );
+ GLMCheckError();
+
+
+ // set the write fb and buffer, and attach write tex
+ BindFBOToCtx( m_blitDrawFBO, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ attparams.m_tex = dstTex;
+ attparams.m_face = dstFace;
+ attparams.m_mip = dstMip;
+ attparams.m_zslice = 0;
+ m_blitDrawFBO->TexAttach( &attparams, attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ glDrawBuffer( attachIndexGL );
+ GLMCheckError();
+
+ // do the blit
+ glBlitFramebufferEXT( srcRect->xmin, srcRect->ymin, srcRect->xmax, srcRect->ymax,
+ dstRect->xmin, dstRect->ymin, dstRect->xmax, dstRect->ymax,
+ blitMask, filter );
+ GLMCheckError();
+
+ // cleanup
+ // unset the read fb and buffer, detach read tex
+ // unset the write fb and buffer, detach write tex
+
+ m_blitReadFBO->TexDetach( attachIndex, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ m_blitDrawFBO->TexDetach( attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ // put the original FB back in place (both read and draw)
+ // this bind will hit both read and draw bindings
+ BindFBOToCtx( m_drawingFBO, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+ BindFBOToCtx( m_drawingFBO, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ // set the read and write buffers back to... what ? does it matter for anything but copies ? don't worry about it
+
+ // restore the scissor state
+ m_ScissorEnable.Write( &oldsciss, true, true );
+ }
+ else
+ {
+ // textured quad style
+
+ // we must attach the dest tex as the color buffer on the blit draw FBO
+ // so that means we need to re-set the drawing FBO on exit
+
+ EGLMFBOAttachment attachIndex = (EGLMFBOAttachment)0;
+ GLenum attachIndexGL = 0;
+ switch( srcTex->m_layout->m_format->m_glDataFormat )
+ {
+ case GL_BGRA:
+ case GL_RGB:
+ case GL_RGBA:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ attachIndex = kAttColor0;
+ attachIndexGL = GL_COLOR_ATTACHMENT0_EXT;
+ break;
+
+ default:
+ Assert(!"Can't blit that format");
+ break;
+ }
+
+ BindFBOToCtx( m_blitDrawFBO, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ GLMFBOTexAttachParams attparams;
+ attparams.m_tex = dstTex;
+ attparams.m_face = dstFace;
+ attparams.m_mip = dstMip;
+ attparams.m_zslice = 0;
+ m_blitDrawFBO->TexAttach( &attparams, attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ glDrawBuffer( attachIndexGL );
+ GLMCheckError();
+
+ // attempt to just set states directly the way we want them, then use the latched states to repair them afterward.
+ this->NullProgram(); // out of program mode
+
+ glDisable ( GL_ALPHA_TEST );
+ glDisable ( GL_CULL_FACE );
+ glDisable ( GL_POLYGON_OFFSET_FILL );
+ glDisable ( GL_SCISSOR_TEST );
+
+ glDisable ( GL_CLIP_PLANE0 );
+ glDisable ( GL_CLIP_PLANE1 );
+
+ glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
+ glDisable ( GL_BLEND );
+
+ glDepthMask ( GL_FALSE );
+ glDisable ( GL_DEPTH_TEST );
+
+ glDisable ( GL_STENCIL_TEST );
+ glStencilMask ( GL_FALSE );
+
+ GLMCheckError();
+
+ // now do the unlit textured quad...
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_2D, srcTex->m_texName );
+ GLMCheckError();
+
+ glEnable(GL_TEXTURE_2D);
+ GLMCheckError();
+
+ // immediate mode is fine
+
+ float topv = 1.0;
+ float botv = 0.0;
+
+ glBegin(GL_QUADS);
+ glTexCoord2f ( 0.0, botv );
+ glVertex3f ( -1.0, -1.0, 0.0 );
+
+ glTexCoord2f ( 1.0, botv );
+ glVertex3f ( 1.0, -1.0, 0.0 );
+
+ glTexCoord2f ( 1.0, topv );
+ glVertex3f ( 1.0, 1.0, 0.0 );
+
+ glTexCoord2f ( 0.0, topv );
+ glVertex3f ( -1.0, 1.0, 0.0 );
+ glEnd();
+ GLMCheckError();
+
+ glBindTexture( GL_TEXTURE_2D, 0 );
+ GLMCheckError();
+
+ glDisable(GL_TEXTURE_2D);
+ GLMCheckError();
+
+ // invalidate tex binding 0 so it gets reset
+ m_samplers[0].m_boundTex = NULL;
+
+ // leave active program empty - flush draw states will fix
+
+ // then restore states using the scoreboard
+
+ m_AlphaTestEnable.Flush( true );
+ m_AlphaToCoverageEnable.Flush( true );
+ m_CullFaceEnable.Flush( true );
+ m_DepthBias.Flush( true );
+ m_ScissorEnable.Flush( true );
+
+ m_ClipPlaneEnable.FlushIndex( 0, true );
+ m_ClipPlaneEnable.FlushIndex( 1, true );
+
+ m_ColorMaskSingle.Flush( true );
+ m_BlendEnable.Flush( true );
+
+ m_DepthMask.Flush( true );
+ m_DepthTestEnable.Flush( true );
+
+ m_StencilWriteMask.Flush( true );
+ m_StencilTestEnable.Flush( true );
+
+ // unset the write fb and buffer, detach write tex
+
+ m_blitDrawFBO->TexDetach( attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ // put the original FB back in place (both read and draw)
+ BindFBOToCtx( m_drawingFBO, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+ BindFBOToCtx( m_drawingFBO, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+ }
+
+ while(pushed)
+ {
+ glPopAttrib();
+ pushed--;
+ }
+}
+
+void GLMContext::ResolveTex( CGLMTex *tex, bool forceDirty )
+{
+ // only run resolve if it's (a) possible and (b) dirty or force-dirtied
+ if ( (tex->m_rboName) && ((tex->m_rboDirty)||forceDirty) )
+ {
+ // state we need to save
+ // current setting of scissor
+ // current setting of the drawing fbo (no explicit save, it's in the context)
+ GLScissorEnable_t oldsciss,newsciss;
+ m_ScissorEnable.Read( &oldsciss, 0 );
+
+ // remember to restore m_drawingFBO at end of effort
+
+ // setup
+ // turn off scissor
+ newsciss.enable = false;
+ m_ScissorEnable.Write( &newsciss, true, true );
+
+ // select which attachment enum we're going to use for the blit
+ // default to color0, unless it's a depth or stencil flava
+
+ // for resolve, only handle a modest subset of the possible formats
+ EGLMFBOAttachment attachIndex = (EGLMFBOAttachment)0;
+ (void)attachIndex;
+
+ GLenum attachIndexGL = 0;
+ GLuint blitMask = 0;
+ switch( tex->m_layout->m_format->m_glDataFormat )
+ {
+ case GL_BGRA:
+ case GL_RGB:
+ case GL_RGBA:
+ // case GL_ALPHA:
+ // case GL_LUMINANCE:
+ // case GL_LUMINANCE_ALPHA:
+ attachIndex = kAttColor0;
+ attachIndexGL = GL_COLOR_ATTACHMENT0_EXT;
+ blitMask = GL_COLOR_BUFFER_BIT;
+ break;
+
+ // case GL_DEPTH_COMPONENT:
+ // attachIndex = kAttDepth;
+ // attachIndexGL = GL_DEPTH_ATTACHMENT_EXT;
+ // blitMask = GL_DEPTH_BUFFER_BIT;
+ // break;
+
+ case GL_DEPTH_STENCIL_EXT:
+ attachIndex = kAttDepthStencil;
+ attachIndexGL = GL_DEPTH_STENCIL_ATTACHMENT_EXT;
+ blitMask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
+ break;
+
+ default:
+ Assert(!"Unsupported format for MSAA resolve" );
+ break;
+ }
+
+
+ // set the read fb, attach read RBO at appropriate attach point, set read buffer
+ BindFBOToCtx( m_blitReadFBO, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ // going to avoid the TexAttach / TexDetach calls due to potential confusion, implement it directly here
+
+ //-----------------------------------------------------------------------------------
+ // put tex->m_rboName on the read FB's attachment
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // you have to attach it both places...
+ // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
+
+ // bind the RBO to the GL_RENDERBUFFER_EXT target - is this extraneous ?
+ //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
+ //GLMCheckError();
+
+ // attach the GL_RENDERBUFFER_EXT target to the depth and stencil attach points
+ glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
+ GLMCheckError();
+
+ glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
+ GLMCheckError();
+
+ // no need to leave the RBO hanging on
+ //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ //GLMCheckError();
+ }
+ else
+ {
+ //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
+ //GLMCheckError();
+
+ glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, tex->m_rboName);
+ GLMCheckError();
+
+ //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ //GLMCheckError();
+ }
+
+ glReadBuffer( attachIndexGL );
+ GLMCheckError();
+
+ //-----------------------------------------------------------------------------------
+ // put tex->m_texName on the draw FBO attachment
+
+ // set the write fb and buffer, and attach write tex
+ BindFBOToCtx( m_blitDrawFBO, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ // regular path - attaching a texture2d
+
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, tex->m_texName, 0 );
+ GLMCheckError();
+
+ glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, tex->m_texName, 0 );
+ GLMCheckError();
+ }
+ else
+ {
+ glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, attachIndexGL, GL_TEXTURE_2D, tex->m_texName, 0 );
+ GLMCheckError();
+ }
+
+ glDrawBuffer( attachIndexGL );
+ GLMCheckError();
+
+ //-----------------------------------------------------------------------------------
+
+ // blit
+ glBlitFramebufferEXT( 0, 0, tex->m_layout->m_key.m_xSize, tex->m_layout->m_key.m_ySize,
+ 0, 0, tex->m_layout->m_key.m_xSize, tex->m_layout->m_key.m_ySize,
+ blitMask, GL_NEAREST );
+ // or should it be GL_LINEAR? does it matter ?
+
+ GLMCheckError();
+
+ //-----------------------------------------------------------------------------------
+ // cleanup
+ //-----------------------------------------------------------------------------------
+
+
+ // unset the read fb and buffer, detach read RBO
+ //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ //GLMCheckError();
+
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // detach the GL_RENDERBUFFER_EXT target from the depth and stencil attach points
+ glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
+ GLMCheckError();
+
+ glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
+ GLMCheckError();
+ }
+ else
+ {
+ glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, 0);
+ GLMCheckError();
+ }
+
+ //-----------------------------------------------------------------------------------
+ // unset the write fb and buffer, detach write tex
+
+
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0 );
+ GLMCheckError();
+
+ glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0 );
+ GLMCheckError();
+ }
+ else
+ {
+ glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, attachIndexGL, GL_TEXTURE_2D, 0, 0 );
+ GLMCheckError();
+ }
+
+ // put the original FB back in place (both read and draw)
+ // this bind will hit both read and draw bindings
+ BindFBOToCtx( m_drawingFBO, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+ BindFBOToCtx( m_drawingFBO, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ // set the read and write buffers back to... what ? does it matter for anything but copies ? don't worry about it
+
+ // restore the scissor state
+ m_ScissorEnable.Write( &oldsciss, true, true );
+
+ // mark the RBO clean on the resolved tex
+ tex->m_rboDirty = false;
+ }
+}
+
+void GLMContext::PreloadTex( CGLMTex *tex, bool force )
+{
+ #if 0 // disabled in sample for time being
+ // if conditions allow (i.e. a drawing surface is active)
+ // bind the texture on TMU 15
+ // set up a dummy program to sample it but not write (use 'discard')
+ // draw a teeny little triangle that won't generate a lot of fragments
+ if (!m_pairCache)
+ return;
+
+ if (!m_drawingFBO)
+ return;
+
+ if (!m_drawingFBO)
+ return;
+
+ if (tex->m_texPreloaded && !force) // only do one preload unless forced to re-do
+ {
+ //printf("\nnot-preloading %s", tex->m_debugLabel ? tex->m_debugLabel : "(unknown)");
+ return;
+ }
+
+ //printf("\npreloading %s", tex->m_debugLabel ? tex->m_debugLabel : "(unknown)");
+
+ CGLMProgram *vp = m_preloadTexVertexProgram;
+ CGLMProgram *fp = NULL;
+ switch(tex->m_layout->m_key.m_texGLTarget)
+ {
+ case GL_TEXTURE_2D: fp = m_preload2DTexFragmentProgram;
+ break;
+
+ case GL_TEXTURE_3D: fp = m_preload3DTexFragmentProgram;
+ break;
+
+ case GL_TEXTURE_CUBE_MAP: fp = m_preloadCubeTexFragmentProgram;
+ break;
+ }
+ if (!fp)
+ return;
+
+ CGLMShaderPair *preloadPair = m_pairCache->SelectShaderPair( vp, fp, 0 );
+ if (!preloadPair)
+ return;
+
+ GLhandleARB pairProgram = preloadPair->m_program;
+ uint pairRevision = preloadPair->m_revision;
+
+ m_boundPair = preloadPair;
+ m_boundPairProgram = pairProgram;
+ m_boundPairRevision = pairRevision;
+
+ glUseProgram( (GLuint)pairProgram );
+ GLMCheckError();
+
+ // note the binding (not really bound.. just sitting in the linked active GLSL program)
+ m_boundProgram[ kGLMVertexProgram ] = vp;
+ m_boundProgram[ kGLMFragmentProgram ] = fp;
+
+ // almost ready to draw...
+
+ int tmuForPreload = 15;
+ if(!m_boundPair->m_samplersFixed)
+ {
+ if (m_boundPair->m_locSamplers[tmuForPreload] >=0)
+ {
+ glUniform1iARB( m_boundPair->m_locSamplers[tmuForPreload], tmuForPreload );
+ GLMCheckError();
+ }
+ m_boundPair->m_samplersFixed = true;
+ }
+
+ // shut down all the generic attribute arrays on the detention level - next real draw will activate them again
+ m_lastKnownVertexAttribMask = 0;
+ for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
+ {
+ glDisableVertexAttribArray( index );
+ GLMCheckError();
+ }
+
+
+ // bind texture
+ this->BindTexToTMU( tex, 15 );
+
+ // unbind vertex/index buffers
+ this->BindBufferToCtx( kGLMVertexBuffer, NULL );
+ this->BindBufferToCtx( kGLMIndexBuffer, NULL );
+
+ // draw
+ static float posns[] = { 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f };
+
+ static int indices[] = { 0, 1, 2 };
+
+
+ glEnableVertexAttribArray( 0 );
+ GLMCheckError();
+
+ glVertexAttribPointer( 0, 3, GL_FLOAT, 0, 0, posns );
+ GLMCheckError();
+
+ glDrawRangeElements( GL_TRIANGLES, 0, 3, 3, GL_UNSIGNED_INT, indices);
+ GLMCheckError();
+
+ glDisableVertexAttribArray( 0 );
+ GLMCheckError();
+
+ m_lastKnownVertexAttribMask = 0;
+ m_lastKnownVertexAttribs[0].m_bufferRevision -= 1; // force mismatch so next FlushDrawStates restores the right attrib source
+
+ this->BindTexToTMU( NULL, 15 );
+
+ tex->m_texPreloaded = true;
+ #endif
+}
+
+
+void GLMContext::SetSamplerTex( int sampler, CGLMTex *tex )
+{
+ GLM_FUNC;
+ CheckCurrent();
+
+ m_samplers[sampler].m_drawTex = tex;
+}
+
+void GLMContext::SetSamplerParams( int sampler, GLMTexSamplingParams *params )
+{
+ GLM_FUNC;
+ CheckCurrent();
+
+ m_samplers[sampler].m_samp = *params;
+}
+
+
+CGLMFBO *GLMContext::NewFBO( void )
+{
+ GLM_FUNC;
+ MakeCurrent();
+
+ CGLMFBO *fbo = new CGLMFBO( this );
+
+ m_fboTable.push_back( fbo );
+
+ return fbo;
+}
+
+void GLMContext::DelFBO( CGLMFBO *fbo )
+{
+ GLM_FUNC;
+ MakeCurrent();
+
+ if (m_drawingFBO == fbo)
+ {
+ m_drawingFBO = NULL; //poof!
+ }
+
+ if (m_boundReadFBO == fbo )
+ {
+ this->BindFBOToCtx( NULL, GL_READ_FRAMEBUFFER_EXT );
+ m_boundReadFBO = NULL;
+ }
+
+ if (m_boundDrawFBO == fbo )
+ {
+ this->BindFBOToCtx( NULL, GL_DRAW_FRAMEBUFFER_EXT );
+ m_boundDrawFBO = NULL;
+ }
+
+ std::vector< CGLMFBO * >::iterator p = find( m_fboTable.begin(), m_fboTable.end(), fbo );
+ if (p != m_fboTable.end() )
+ {
+ m_fboTable.erase( p );
+ }
+
+ delete fbo;
+}
+
+void GLMContext::SetDrawingFBO( CGLMFBO *fbo )
+{
+ GLM_FUNC;
+ CheckCurrent();
+
+ // might want to validate that fbo object?
+ m_drawingFBO = fbo;
+}
+
+//===============================================================================
+
+CGLMProgram *GLMContext::NewProgram( EGLMProgramType type, char *progString )
+{
+ //hushed GLM_FUNC;
+
+ MakeCurrent();
+
+ CGLMProgram *prog = new CGLMProgram( this, type );
+
+ prog->SetProgramText( progString );
+ bool compile_ok = prog->CompileActiveSources();
+
+ //AssertOnce( compile_ok );
+
+ return prog;
+}
+
+void GLMContext::DelProgram( CGLMProgram *prog )
+{
+ GLM_FUNC;
+
+ this->MakeCurrent();
+
+ if (m_drawingProgram[ prog->m_type ] == prog)
+ {
+ m_drawingProgram[ prog->m_type ] = NULL;
+ }
+
+ // make sure to eliminate any cached pairs using this shader
+ bool purgeResult = m_pairCache->PurgePairsWithShader( prog );
+ Assert( !purgeResult ); // very unlikely to trigger
+
+ this->NullProgram();
+
+ delete prog;
+}
+
+void GLMContext::NullProgram( void )
+{
+ // just unbind everything on a prog delete
+ glSetEnable( GL_VERTEX_PROGRAM_ARB, false );
+ glSetEnable( GL_FRAGMENT_PROGRAM_ARB, false );
+
+ glBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 );
+ glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, 0 );
+
+ glUseProgram( 0 );
+ m_boundPair = NULL;
+ m_boundPairRevision = 0xFFFFFFFF;
+ m_boundPairProgram = (GLhandleARB)0xFFFFFFFF;
+
+ m_boundProgram[ kGLMVertexProgram ] = NULL;
+ m_boundProgram[ kGLMFragmentProgram ] = NULL;
+}
+
+void GLMContext::SetDrawingProgram( EGLMProgramType type, CGLMProgram *prog )
+{
+ GLM_FUNC;
+
+ this->MakeCurrent();
+
+ if (prog) // OK to pass NULL..
+ {
+ if (type != prog->m_type)
+ {
+ Debugger();
+ }
+ }
+ else
+ {
+ // if a null fragment program is passed, we activate our special null program
+ // thus FP is always always enabled.
+ if (type==kGLMFragmentProgram)
+ {
+ prog = m_nullFragmentProgram;
+ }
+ else
+ {
+ //Assert(!"Tried to set NULL vertex program");
+ }
+ }
+ m_drawingProgram[type] = prog;
+}
+
+void GLMContext::SetDrawingLang( EGLMProgramLang lang, bool immediate )
+{
+ if ( !m_caps.m_hasDualShaders ) return; // ignore attempts to change language when -glmdualshaders is not engaged
+
+ m_drawingLangAtFrameStart = lang;
+ if (immediate)
+ {
+ this->NullProgram();
+
+ m_drawingLang = m_drawingLangAtFrameStart;
+ }
+}
+
+void GLMContext::LinkShaderPair( CGLMProgram *vp, CGLMProgram *fp )
+{
+ if ( (m_pairCache) && (m_drawingLang==kGLMGLSL) && (vp && vp->m_descs[kGLMGLSL].m_valid) && (fp && fp->m_descs[kGLMGLSL].m_valid) )
+ {
+ CGLMShaderPair *pair = m_pairCache->SelectShaderPair( vp, fp, 0 );
+
+ Assert( pair != NULL );
+
+ this->NullProgram(); // clear out any binds that were done - next draw will set it right
+ }
+}
+
+void GLMContext::ClearShaderPairCache( void )
+{
+ if (m_pairCache)
+ {
+ this->NullProgram();
+ m_pairCache->Purge(); // bye bye all linked pairs
+ this->NullProgram();
+ }
+}
+
+void GLMContext::QueryShaderPair( int index, GLMShaderPairInfo *infoOut )
+{
+ if (m_pairCache)
+ {
+ m_pairCache->QueryShaderPair( index, infoOut );
+ }
+ else
+ {
+ memset( infoOut, 0, sizeof( *infoOut ) );
+ infoOut->m_status = -1;
+ }
+}
+
+void GLMContext::SetProgramParametersF( EGLMProgramType type, uint baseSlot, float *slotData, uint slotCount )
+{
+ GLM_FUNC;
+
+ Assert( baseSlot < kGLMProgramParamFloat4Limit );
+ Assert( baseSlot+slotCount <= kGLMProgramParamFloat4Limit );
+
+ GLMPRINTF(("-S-GLMContext::SetProgramParametersF %s slots %d - %d: ", (type==kGLMVertexProgram) ? "VS" : "FS", baseSlot, baseSlot + slotCount - 1 ));
+ for( int i=0; i m_programParamsF[type].m_dirtySlotCount)
+ {
+ m_programParamsF[type].m_dirtySlotCount = baseSlot+slotCount;
+ }
+}
+
+void GLMContext::SetProgramParametersB( EGLMProgramType type, uint baseSlot, int *slotData, uint boolCount )
+{
+ GLM_FUNC;
+
+ Assert( m_drawingLang == kGLMGLSL );
+ Assert( type==kGLMVertexProgram );
+
+ Assert( baseSlot < kGLMProgramParamBoolLimit );
+ Assert( baseSlot+boolCount <= kGLMProgramParamBoolLimit );
+
+ GLMPRINTF(("-S-GLMContext::SetProgramParametersB %s bools %d - %d: ", (type==kGLMVertexProgram) ? "VS" : "FS", baseSlot, baseSlot + boolCount - 1 ));
+ for( int i=0; i m_programParamsB[type].m_dirtySlotCount)
+ {
+ m_programParamsB[type].m_dirtySlotCount = baseSlot+boolCount;
+ }
+}
+
+void GLMContext::SetProgramParametersI( EGLMProgramType type, uint baseSlot, int *slotData, uint slotCount ) // groups of 4 ints...
+{
+ GLM_FUNC;
+
+ Assert( m_drawingLang == kGLMGLSL );
+ Assert( type==kGLMVertexProgram );
+
+ Assert( baseSlot < kGLMProgramParamInt4Limit );
+ Assert( baseSlot+slotCount <= kGLMProgramParamInt4Limit );
+
+ GLMPRINTF(("-S-GLMContext::SetProgramParametersI %s slots %d - %d: ", (type==kGLMVertexProgram) ? "VS" : "FS", baseSlot, baseSlot + slotCount - 1 ));
+ for( int i=0; i m_programParamsI[type].m_dirtySlotCount)
+ {
+ m_programParamsI[type].m_dirtySlotCount = baseSlot+slotCount;
+ }
+}
+
+
+CGLMBuffer *GLMContext::NewBuffer( EGLMBufferType type, uint size, uint options )
+{
+ //hushed GLM_FUNC;
+
+ MakeCurrent();
+
+ CGLMBuffer *prog = new CGLMBuffer( this, type, size, options );
+
+ return prog;
+}
+
+void GLMContext::DelBuffer( CGLMBuffer *buff )
+{
+ GLM_FUNC;
+
+ this->MakeCurrent();
+
+ for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
+ {
+ if (m_drawVertexSetup.m_attrs[index].m_buffer == buff)
+ {
+ // just clear the enable mask - this will force all the attrs to get re-sent on next sync
+ m_drawVertexSetup.m_attrMask = 0;
+ }
+ }
+
+ if (m_drawIndexBuffer == buff)
+ {
+ m_drawIndexBuffer = NULL;
+ }
+
+ if (m_lastKnownBufferBinds[ buff->m_type ] == buff)
+ {
+ // shoot it down
+ this->BindBufferToCtx( buff->m_type, NULL );
+ m_lastKnownBufferBinds[ buff->m_type ] = NULL;
+ }
+
+ delete buff;
+}
+
+
+void GLMContext::SetIndexBuffer( CGLMBuffer *buff )
+{
+ GLM_FUNC;
+ CheckCurrent();
+
+ m_drawIndexBuffer = buff;
+
+ // draw time is welcome to re-check, but we bind it immediately.
+ this->BindBufferToCtx( kGLMIndexBuffer, buff );
+}
+
+GLMVertexSetup g_blank_setup;
+
+void GLMContext::SetVertexAttributes( GLMVertexSetup *setup )
+{
+ GLM_FUNC;
+
+ // we now just latch the vert setup and then execute on it at flushdrawstatestime if shaders are enabled.
+ if (setup)
+ {
+ m_drawVertexSetup = *setup;
+ }
+ else
+ {
+ memset( &m_drawVertexSetup, 0, sizeof(m_drawVertexSetup) );
+ }
+
+ return;
+}
+
+void GLMContext::Clear( bool color, unsigned long colorValue, bool depth, float depthValue, bool stencil, unsigned int stencilValue, GLScissorBox_t *box )
+{
+ GLM_FUNC;
+ m_debugBatchIndex++; // clears are batches too (maybe blits should be also...)
+
+#if GLMDEBUG
+ GLMDebugHookInfo info;
+ memset( &info, 0, sizeof(info) );
+ info.m_caller = eClear;
+
+ do
+ {
+#endif
+ uint mask = 0;
+
+ GLClearColor_t clearcol;
+ GLClearDepth_t cleardep = { depthValue };
+ GLClearStencil_t clearsten = { (GLint)stencilValue };
+
+ // depth write mask must be saved&restored
+ GLDepthMask_t olddepthmask;
+ GLDepthMask_t newdepthmask = { true };
+
+ // stencil write mask must be saved and restored
+ GLStencilWriteMask_t oldstenmask;
+ GLStencilWriteMask_t newstenmask = { ~(GLint)0 };
+
+ GLColorMaskSingle_t oldcolormask;
+ GLColorMaskSingle_t newcolormask = { -1,-1,-1,-1 }; // D3D clears do not honor color mask, so force it
+
+ if (color)
+ {
+ // #define D3DCOLOR_ARGB(a,r,g,b) ((D3DCOLOR)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
+
+ clearcol.r = ((colorValue >> 16) & 0xFF) / 255.0f; //R
+ clearcol.g = ((colorValue >> 8) & 0xFF) / 255.0f; //G
+ clearcol.b = ((colorValue ) & 0xFF) / 255.0f; //B
+ clearcol.a = ((colorValue >> 24) & 0xFF) / 255.0f; //A
+
+ m_ClearColor.Write( &clearcol, true, true ); // no check, no wait
+ mask |= GL_COLOR_BUFFER_BIT;
+
+ // save and set color mask
+ m_ColorMaskSingle.Read( &oldcolormask, 0 );
+ m_ColorMaskSingle.Write( &newcolormask, true, true );
+ }
+
+ if (depth)
+ {
+ // get old depth write mask
+ m_DepthMask.Read( &olddepthmask, 0 );
+ m_DepthMask.Write( &newdepthmask, true, true );
+ m_ClearDepth.Write( &cleardep, true, true ); // no check, no wait
+ mask |= GL_DEPTH_BUFFER_BIT;
+ }
+
+ if (stencil)
+ {
+ m_ClearStencil.Write( &clearsten, true, true ); // no check, no wait
+ mask |= GL_STENCIL_BUFFER_BIT;
+
+ // save and set sten mask
+ m_StencilWriteMask.Read( &oldstenmask, 0 );
+ m_StencilWriteMask.Write( &newstenmask, true, true );
+ }
+
+ bool subrect = (box != NULL);
+ GLScissorEnable_t scissorEnableSave;
+ GLScissorEnable_t scissorEnableNew = { true };
+
+ GLScissorBox_t scissorBoxSave;
+ GLScissorBox_t scissorBoxNew;
+
+ if (subrect)
+ {
+ // save current scissorbox and enable
+ m_ScissorEnable.Read( &scissorEnableSave, 0 );
+ m_ScissorBox.Read( &scissorBoxSave, 0 );
+
+ if(0)
+ {
+ // calc new scissorbox as intersection against *box
+
+ // max of the mins
+ scissorBoxNew.x = std::max(scissorBoxSave.x, box->x);
+ scissorBoxNew.y = std::max(scissorBoxSave.y, box->y);
+
+ // min of the maxes
+ scissorBoxNew.width = ( std::min(scissorBoxSave.x+scissorBoxSave.width, box->x+box->width)) - scissorBoxNew.x;
+
+ // height is just min of the max y's, minus the new base Y
+ scissorBoxNew.height = ( std::min(scissorBoxSave.y+scissorBoxSave.height, box->y+box->height)) - scissorBoxNew.y;
+ }
+ else
+ {
+ // ignore old scissor box completely.
+ scissorBoxNew = *box;
+ }
+ // set new box and enable
+ m_ScissorEnable.Write( &scissorEnableNew, true, true );
+ m_ScissorBox.Write( &scissorBoxNew, true, true );
+ }
+
+ glClear( mask );
+
+ if (subrect)
+ {
+ // put old scissor box and enable back
+ m_ScissorEnable.Write( &scissorEnableSave, true, true );
+ m_ScissorBox.Write( &scissorBoxSave, true, true );
+ }
+
+ if (depth)
+ {
+ // put old depth write mask
+ m_DepthMask.Write( &olddepthmask );
+ }
+
+ if (color)
+ {
+ // put old color write mask
+ m_ColorMaskSingle.Write( &oldcolormask, true, true );
+ }
+
+ if (stencil)
+ {
+ // put old sten mask
+ m_StencilWriteMask.Write( &oldstenmask, true, true );
+ }
+
+#if GLMDEBUG
+ this->DebugHook( &info );
+ } while (info.m_loop);
+#endif
+}
+
+
+// stolen from glmgrbasics.cpp
+extern "C" uint GetCurrentKeyModifiers( void );
+enum ECarbonModKeyIndex
+{
+ EcmdKeyBit = 8, /* command key down?*/
+ EshiftKeyBit = 9, /* shift key down?*/
+ EalphaLockBit = 10, /* alpha lock down?*/
+ EoptionKeyBit = 11, /* option key down?*/
+ EcontrolKeyBit = 12 /* control key down?*/
+};
+
+enum ECarbonModKeyMask
+{
+ EcmdKey = 1 << EcmdKeyBit,
+ EshiftKey = 1 << EshiftKeyBit,
+ EalphaLock = 1 << EalphaLockBit,
+ EoptionKey = 1 << EoptionKeyBit,
+ EcontrolKey = 1 << EcontrolKeyBit
+};
+
+#if 0
+ static ConVar gl_flushpaircache ("gl_flushpaircache", "0");
+ static ConVar gl_paircachestats ("gl_paircachestats", "0");
+ static ConVar gl_mtglflush_at_tof ("gl_mtglflush_at_tof", "0");
+ static ConVar gl_texlayoutstats ("gl_texlayoutstats", "0" );
+#else
+ int gl_flushpaircache =0;
+ int gl_paircachestats =0;
+ int gl_mtglflush_at_tof =0;
+ int gl_texlayoutstats =0;
+#endif
+
+void GLMContext::BeginFrame( void )
+{
+ GLM_FUNC;
+
+ MakeCurrent();
+
+ m_debugFrameIndex++;
+ m_debugBatchIndex = -1;
+
+ // check for lang change at TOF
+ if (m_caps.m_hasDualShaders)
+ {
+ if (m_drawingLang != m_drawingLangAtFrameStart)
+ {
+ // language change. unbind everything..
+ this->NullProgram();
+
+ m_drawingLang = m_drawingLangAtFrameStart;
+ }
+ }
+
+ // scrub some critical shock absorbers
+ for( int i=0; i< 16; i++)
+ {
+ glDisableVertexAttribArray( i ); // enable GLSL attribute- this is just client state - will be turned back off
+ GLMCheckError();
+ }
+ m_lastKnownVertexAttribMask = 0;
+
+ //FIXME should we also zap the m_lastKnownAttribs array ? (worst case it just sets them all again on first batch)
+
+ BindBufferToCtx( kGLMVertexBuffer, NULL, true );
+ BindBufferToCtx( kGLMIndexBuffer, NULL, true );
+
+ if (gl_flushpaircache/*.GetInt()*/)
+ {
+ // do the flush and then set back to zero
+ this->ClearShaderPairCache();
+
+ printf("\n\n##### shader pair cache cleared\n\n");
+ gl_flushpaircache = 0; //.SetValue( 0 );
+ }
+
+ if (gl_paircachestats/*.GetInt()*/)
+ {
+ // do the flush and then set back to zero
+ this->m_pairCache->DumpStats();
+
+ gl_paircachestats = 0; //.SetValue( 0 );
+ }
+
+ if (gl_texlayoutstats/*.GetInt()*/)
+ {
+ this->m_texLayoutTable->DumpStats();
+
+ gl_texlayoutstats = 0; //.SetValue( 0 );
+ }
+
+ if (gl_mtglflush_at_tof/*.GetInt()*/)
+ {
+ glFlush(); // TOF flush - skip this if benchmarking, enable it if human playing (smoothness)
+ }
+
+#if GLMDEBUG
+ // init debug hook information
+ GLMDebugHookInfo info;
+ memset( &info, 0, sizeof(info) );
+ info.m_caller = eBeginFrame;
+
+ do
+ {
+ this->DebugHook( &info );
+ } while (info.m_loop);
+
+#endif
+
+}
+
+void GLMContext::EndFrame( void )
+{
+ GLM_FUNC;
+
+#if GLMDEBUG
+ // init debug hook information
+ GLMDebugHookInfo info;
+ memset( &info, 0, sizeof(info) );
+ info.m_caller = eEndFrame;
+
+ do
+ {
+#endif
+ if (!m_oneCtxEnable) // if using dual contexts, this flush is needed
+ {
+ glFlush();
+ }
+#if GLMDEBUG
+ this->DebugHook( &info );
+ } while (info.m_loop);
+#endif
+}
+
+//===============================================================================
+
+CGLMQuery *GLMContext::NewQuery( GLMQueryParams *params )
+{
+ CGLMQuery *query = new CGLMQuery( this, params );
+
+ return query;
+}
+
+void GLMContext::DelQuery( CGLMQuery *query )
+{
+ // may want to do some finish/
+ delete query;
+}
+
+// static ConVar mat_vsync( "mat_vsync", "0", 0, "Force sync to vertical retrace", true, 0.0, true, 1.0 );
+int mat_vsync = 1;
+
+//===============================================================================
+
+// ConVar glm_nullrefresh_capslock( "glm_nullrefresh_capslock", "0" );
+// ConVar glm_literefresh_capslock( "glm_literefresh_capslock", "0" );
+
+// extern ConVar gl_blitmode;
+extern int gl_blitmode;
+
+void GLMContext::Present( CGLMTex *tex )
+{
+#if DX9MODE
+ GLM_FUNC;
+
+ MakeCurrent();
+
+ // this is the path whether full screen or windowed... we always blit.
+ CShowPixelsParams showparams;
+ memset( &showparams, 0, sizeof(showparams) );
+
+ showparams.m_srcTexName = tex->m_texName;
+ showparams.m_width = tex->m_layout->m_key.m_xSize;
+ showparams.m_height = tex->m_layout->m_key.m_ySize;
+// showparams.m_vsyncEnable = m_displayParams.m_vsyncEnable = mat_vsync; //.GetBool();
+// showparams.m_fsEnable = m_displayParams.m_fsEnable;
+
+ // we call showpixels once with the "only sync view" arg set, so we know what the latest surface size is, before trying to do our own blit !
+// showparams.m_onlySyncView = true;
+// g_engine->ShowPixels(&showparams); // doesn't actually show anything, just syncs window/fs state (would make a useful separate call)
+// showparams.m_onlySyncView = false;
+
+ // blit to GL_BACK done here, not in engine, this lets us do resolve directly if conditions are right
+
+ GLMRect srcRect, dstRect;
+
+ uint dstWidth,dstHeight;
+ g_engine->DisplayedSize( dstWidth,dstHeight );
+
+ srcRect.xmin = 0;
+ srcRect.ymin = 0;
+ srcRect.xmax = showparams.m_width;
+ srcRect.ymax = showparams.m_height;
+
+ dstRect.xmin = 0;
+ dstRect.ymin = 0;
+ dstRect.xmax = dstWidth;
+ dstRect.ymax = dstHeight;
+
+ // do not ask for LINEAR if blit is unscaled
+ // NULL means targeting GL_BACK. Blit2 will break it down into two steps if needed, and will handle resolve, scale, flip.
+ bool blitScales = (showparams.m_width != dstWidth) || (showparams.m_height != dstHeight);
+ this->Blit2( tex, &srcRect, 0,0,
+ NULL, &dstRect, 0,0,
+ blitScales ? GL_LINEAR : GL_NEAREST );
+
+ if (m_oneCtxEnable) // if using single context, we need to blast some state so GLM will recover after the FBO fiddlin'
+ {
+ BindFBOToCtx( NULL, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+ BindFBOToCtx( NULL, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+ }
+
+ g_engine->ShowPixels(&showparams);
+
+ if (m_oneCtxEnable)
+ {
+ // put the original FB back in place (both read and draw)
+ // this bind will hit both read and draw bindings
+ BindFBOToCtx( m_drawingFBO, GL_READ_FRAMEBUFFER_EXT );
+ GLMCheckError();
+ BindFBOToCtx( m_drawingFBO, GL_DRAW_FRAMEBUFFER_EXT );
+ GLMCheckError();
+
+ // put em back !!
+ m_ScissorEnable.Flush( true );
+ m_ScissorBox.Flush( true );
+ m_ViewportBox.Flush( true );
+ }
+ else
+ {
+ MakeCurrent();
+ }
+#endif
+}
+
+
+
+//===============================================================================
+// GLMContext protected methods
+
+// a naive implementation of this would just clear-drawable on the context at entry,
+// and then capture and set fullscreen if requested.
+// however that would glitch thescreen every time the user changed resolution while staying in full screen.
+// but in windowed mode there's really not much to do in here. Yeah, this routine centers around obtaining
+// drawables for fullscreen mode, and/or dropping those drawables if we're going back to windowed.
+
+// um, are we expected to re-make the standard surfaces (color, depthstencil) if the res changes? is that now this routine's job ?
+
+// so, kick it off with an assessment of whather we were FS previously or not.
+// if there was no prior display params latched, then it wasn't.
+
+// changes in here take place immediately. If you want to defer display changes then that's going to be a different method.
+// common assumption is that there will be two places that call this: context create and the implementation of the DX9 Reset method.
+// in either case the client code is aware of what it signed up for.
+
+bool GLMContext::SetDisplayParams( GLMDisplayParams *params )
+{
+ m_displayParams = *params; // latch em
+ m_displayParamsValid = true;
+ return true;
+}
+
+//extern ConVar gl_singlecontext; // single context mode go-ahead if 10.6.3 or higher
+extern int gl_singlecontext; // it's in glmgrbasics.cpp
+
+//ConVar gl_can_query_fast("gl_can_query_fast", "0");
+int gl_can_query_fast = 1; // assume SLGU
+
+GLMContext::GLMContext( GLMDisplayParams *params )
+{
+#if DX9MODE
+ // flag our copy of display params as blank
+ m_displayParamsValid = false;
+
+ // peek at any CLI options
+ m_slowAssertEnable = false;//CommandLine()->FindParm("-glmassertslow");
+ m_slowSpewEnable = false; //CommandLine()->FindParm("-glmspewslow");
+ m_slowCheckEnable = m_slowAssertEnable || m_slowSpewEnable;
+
+ m_drawingLangAtFrameStart = m_drawingLang = kGLMGLSL; // default to GLSL
+
+ // this affects FlushDrawStates which will route program bindings, uniform delivery, sampler setup, and enables accordingly.
+
+ if ( 0 /*CommandLine()->FindParm("-glslmode")*/ )
+ {
+ m_drawingLangAtFrameStart = m_drawingLang = kGLMGLSL;
+ }
+ if ( 0 /* CommandLine()->FindParm("-arbmode") && !CommandLine()->FindParm("-glslcontrolflow") */ )
+ {
+ m_drawingLangAtFrameStart = m_drawingLang = kGLMARB;
+ }
+
+ // proceed with rest of init
+
+ m_nsctx = NULL;
+ m_ctx = NULL;
+
+ // call engine, ask for the attrib list (also naming the specific renderer ID) and use that to make our context
+ CGLPixelFormatAttribute *selAttribs = NULL;
+ uint selWords = 0;
+
+ memset( &m_caps, 0, sizeof( m_caps ) );
+ //g_engine->GetDesiredPixelFormatAttribsAndRendererInfo( (uint**)&selAttribs, &selWords, &m_caps );
+ g_engine->GetRendererInfo( &m_caps );
+ uint selBytes = selWords * sizeof( uint );
+
+ // call engine, ask it about the window we're targeting, get the NSGLContext back, share against that
+ PseudoNSGLContextPtr shareNsCtx = g_engine->GetNSGLContextForWindow( (void*)params->m_focusWindow );
+
+
+ // decide if we're going to try single context mode.
+ m_oneCtxEnable = true; // 10.6 only... //(m_caps.m_osComboVersion >= 0x000A0603) && (gl_singlecontext/*.GetInt()*/ );
+
+ bool success = false;
+ if(m_oneCtxEnable)
+ {
+ // just steal the window's context
+ m_nsctx = shareNsCtx;
+ m_ctx = GetCGLContextFromNSGL( shareNsCtx );
+
+ success = (m_nsctx != NULL) && (m_ctx != NULL);
+ }
+ else
+ {
+ // this is the old 10.5.x two-context path.... ugh
+ success = NewNSGLContext( (unsigned long*)selAttribs, shareNsCtx, &m_nsctx, &m_ctx );
+ }
+
+ // If we're compiling for 64-bit with a 32-bit GLint we should only allow the conversion
+ // between 'this' and GLint if it can fit in the GLint, otherwise consider this to be failure
+ if ( sizeof(this) > sizeof(GLint) )
+ success = ( (uintptr_t)this & 0xFFFFFFFF00000000 ) == 0;
+
+ if (success)
+ {
+ //write a cookie into the CGL context leading back to the GLM context object
+ GLint glm_context_link = (GLint)((uintptr_t)this);
+ CGLSetParameter( m_ctx, kCGLCPClientStorage, &glm_context_link );
+
+ // save off the pixel format attributes we used
+ memcpy(m_pixelFormatAttribs, selAttribs, selBytes );
+ }
+
+ if ( !success )
+ {
+ Debugger(); //FIXME #PMB# bad news, maybe exit to shell if this happens
+ }
+
+ if ( 1 /* CommandLine()->FindParm("-glmspewcaps") */) //FIXME change to '0' later
+ {
+ DumpCaps();
+ }
+
+ SetDisplayParams( params );
+
+ m_texLayoutTable = new CGLMTexLayoutTable;
+
+ memset( m_samplers, 0, sizeof( m_samplers ) );
+ m_activeTexture = -1;
+
+ m_texLocks.reserve( 16 );
+
+ // FIXME need a texture tracking table so we can reliably delete CGLMTex objects at context teardown
+
+ m_boundReadFBO = NULL;
+ m_boundDrawFBO = NULL;
+ m_drawingFBO = NULL;
+
+ memset( m_boundProgram, 0, sizeof(m_boundProgram) );
+ memset( m_drawingProgram, 0, sizeof(m_boundProgram) );
+ memset( m_programParamsF , 0, sizeof (m_programParamsF) );
+ memset( m_programParamsB , 0, sizeof (m_programParamsB) );
+ memset( m_programParamsI , 0, sizeof (m_programParamsI) );
+
+ m_paramWriteMode = eParamWriteDirtySlotRange; // default to fastest mode
+ /*
+ if (CommandLine()->FindParm("-glmwriteallslots")) m_paramWriteMode = eParamWriteAllSlots;
+ if (CommandLine()->FindParm("-glmwriteshaderslots")) m_paramWriteMode = eParamWriteShaderSlots;
+ if (CommandLine()->FindParm("-glmwriteshaderslotsoptional")) m_paramWriteMode = eParamWriteShaderSlotsOptional;
+ if (CommandLine()->FindParm("-glmwritedirtyslotrange")) m_paramWriteMode = eParamWriteDirtySlotRange;
+ */
+
+ m_attribWriteMode = eAttribWriteDirty;
+
+ /*
+ if (CommandLine()->FindParm("-glmwriteallattribs")) m_attribWriteMode = eAttribWriteAll;
+ if (CommandLine()->FindParm("-glmwritedirtyattribs")) m_attribWriteMode = eAttribWriteDirty;
+ */
+
+ m_pairCache = new CGLMShaderPairCache( this );
+ m_boundPair = NULL;
+ m_boundPairRevision = 0xFFFFFFFF;
+ m_boundPairProgram = (GLhandleARB)0xFFFFFFFF; // GLSL only
+
+ memset( m_lastKnownBufferBinds, 0, sizeof(m_lastKnownBufferBinds) );
+ memset( m_lastKnownVertexAttribs, 0, sizeof(m_lastKnownVertexAttribs) );
+ m_lastKnownVertexAttribMask = 0;
+
+ // make a null program for use when client asks for NULL FP
+ m_nullFragmentProgram = this->NewProgram(kGLMFragmentProgram, g_nullFragmentProgramText );
+
+ // make dummy programs for doing texture preload via dummy draw
+ m_preloadTexVertexProgram = this->NewProgram(kGLMVertexProgram, g_preloadTexVertexProgramText );
+ m_preload2DTexFragmentProgram = this->NewProgram(kGLMFragmentProgram, g_preload2DTexFragmentProgramText );
+ m_preload3DTexFragmentProgram = this->NewProgram(kGLMFragmentProgram, g_preload3DTexFragmentProgramText );
+ m_preloadCubeTexFragmentProgram = this->NewProgram(kGLMFragmentProgram, g_preloadCubeTexFragmentProgramText );
+
+ m_drawIndexBuffer = NULL;
+
+ //memset( &m_drawVertexSetup, 0, sizeof(m_drawVertexSetup) );
+ SetVertexAttributes( NULL ); // will set up all the entries in m_drawVertexSetup
+
+ m_debugFontTex = NULL;
+
+ // debug state
+ m_debugFrameIndex = -1;
+ m_debugBatchIndex = -1;
+
+#if GLMDEBUG
+ // #######################################################################################
+
+ // DebugHook state - we could set these to more interesting values in response to a CLI arg like "startpaused" or something if desired
+ //m_paused = false;
+ m_holdFrameBegin = -1;
+ m_holdFrameEnd = -1;
+ m_holdBatch = m_holdBatchFrame = -1;
+
+ m_debugDelayEnable = false;
+ m_debugDelay = 1<<19; // ~0.5 sec delay
+
+ m_autoClearColor = m_autoClearDepth = m_autoClearStencil = false;
+ m_autoClearColorValues[0] = 0.0; //red
+ m_autoClearColorValues[1] = 1.0; //green
+ m_autoClearColorValues[2] = 0.0; //blue
+ m_autoClearColorValues[3] = 1.0; //alpha
+
+ m_selKnobIndex = 0;
+ m_selKnobMinValue = -10.0f;
+ m_selKnobMaxValue = 10.0f;
+ m_selKnobIncrement = 1/256.0f;
+
+ // #######################################################################################
+#endif
+
+ // make two scratch FBO's for blit purposes
+ m_blitReadFBO = this->NewFBO();
+ m_blitDrawFBO = this->NewFBO();
+
+ for( int i=0; iNewFBO();
+ }
+
+ bool new_mtgl = m_caps.m_hasPerfPackage1; // i.e. 10.6.4 plus new driver
+
+ /*
+ if ( CommandLine()->FindParm("-glmenablemtgl2") )
+ {
+ new_mtgl = true;
+ }
+
+ if ( CommandLine()->FindParm("-glmdisablemtgl2") )
+ {
+ new_mtgl = false;
+ }
+ */
+
+ bool mtgl_on = params->m_mtgl;
+ /*
+ if (CommandLine()->FindParm("-glmenablemtgl"))
+ {
+ mtgl_on = true;
+ }
+
+ if (CommandLine()->FindParm("-glmdisablemtgl"))
+ {
+ mtgl_on = false;
+ }
+ */
+
+ CGLError result = (CGLError)0;
+ if (mtgl_on)
+ {
+ bool ready = false;
+
+ if (new_mtgl)
+ {
+ // afterburner
+ CGLContextEnable kCGLCPGCDMPEngine = ((CGLContextEnable)1314);
+ result = CGLEnable( m_ctx, kCGLCPGCDMPEngine );
+ if (!result)
+ {
+ ready = true; // succeeded - no need to try non-MTGL
+ printf("\nMTGL detected.\n");
+ }
+ else
+ {
+ printf("\nMTGL *not* detected, falling back.\n");
+ }
+ }
+
+ if (!ready)
+ {
+ // try old MTGL
+ result = CGLEnable( m_ctx, kCGLCEMPEngine );
+ if (!result)
+ {
+ printf("\nMTGL has been detected.\n");
+ ready = true; // succeeded - no need to try non-MTGL
+ }
+ }
+ }
+
+ // also, set the remote convar "gl_can_query_fast" to 1 if perf package present, else 0.
+ gl_can_query_fast = m_caps.m_hasPerfPackage1?1:0; //.SetValue( m_caps.m_hasPerfPackage1?1:0 );
+
+ GLMCheckError();
+#endif
+}
+
+GLMContext::~GLMContext ()
+{
+ // a lot of stuff that needs to be freed / destroyed
+
+ if (m_debugFontTex)
+ {
+ this->DelTex( m_debugFontTex );
+ m_debugFontTex = NULL;
+ }
+
+ if ( m_nullFragmentProgram )
+ {
+ this->DelProgram( m_nullFragmentProgram );
+ m_nullFragmentProgram = NULL;
+ }
+
+ // walk m_fboTable and free them up..
+ for( std::vector< CGLMFBO * >::iterator p = m_fboTable.begin(); p != m_fboTable.end(); p++ )
+ {
+ CGLMFBO *fbo = *p;
+ this->DelFBO( fbo );
+ }
+ m_fboTable.clear();
+
+ if (m_pairCache)
+ {
+ delete m_pairCache;
+ m_pairCache = NULL;
+ }
+
+ // we need a m_texTable I think..
+
+ // m_texLayoutTable can be scrubbed once we know that all the tex are freed
+
+ if (m_nsctx && (!m_oneCtxEnable) )
+ {
+ DelNSGLContext( m_nsctx );
+ m_nsctx = NULL;
+ m_ctx = NULL;
+ }
+}
+
+
+
+void GLMContext::SelectTMU( int tmu )
+{
+ //GLM_FUNC;
+
+ CheckCurrent();
+ if (tmu != m_activeTexture)
+ {
+ glActiveTexture( GL_TEXTURE0+tmu );
+ GLMCheckError();
+
+ m_activeTexture = tmu;
+ }
+}
+
+int GLMContext::BindTexToTMU( CGLMTex *tex, int tmu, bool noCheck )
+{
+ GLM_FUNC;
+ GLMPRINTF(("--- GLMContext::BindTexToTMU tex %p GL name %d -> TMU %d ", tex, tex ? tex->m_texName : -1, tmu ));
+
+ CheckCurrent();
+
+ #if GLMDEBUG
+ if ( tex && tex->m_debugLabel && (!strcmp( tex->m_debugLabel, "error" ) ) )
+ {
+ static char stop_here = 0;
+ if (stop_here)
+ {
+ stop_here = 1;
+ }
+ }
+ #endif
+
+ if (tex && (tex->m_layout->m_key.m_texFlags & kGLMTexMultisampled) )
+ {
+ if (tex->m_rboDirty)
+ {
+ // the texture must be a multisampled render target which has been targeted recently for drawing.
+ // check that it's not still attached...
+ Assert( tex->m_rtAttachCount==0 );
+
+ // let it resolve the MSAA RBO back to the texture
+ ResolveTex( tex );
+ }
+ }
+
+ SelectTMU( tmu );
+
+ // if another texture was previously bound there, mark it not bound now
+ // this should not be skipped
+
+ if (m_samplers[tmu].m_boundTex)
+ {
+ m_samplers[tmu].m_boundTex->m_bindPoints &= ~(1<m_layout->m_key.m_texGLTarget, m_samplers[tmu].m_boundTex->m_texName );
+ //}
+
+ // note m_samplers[tmu].m_boundTex is now stale but we will step on it shortly
+ }
+
+ // if texture chosen is different, or if noCheck is set, do the bind
+ if (tex)
+ {
+ // bind new tex and mark it
+ if ((tex != m_samplers[tmu].m_boundTex) || noCheck)
+ {
+ // if not being forced, we should see if the bind point (target) of the departing tex is different.
+ if (!noCheck)
+ {
+ if ( (m_samplers[tmu].m_boundTex) )
+ {
+ // there is an outgoing tex.
+ // same target?
+ if ( m_samplers[tmu].m_boundTex->m_layout->m_key.m_texGLTarget != tex->m_layout->m_key.m_texGLTarget )
+ {
+ // no, different target. inbound tex will be set below. Here, just clear the different target of the outbound tex.
+ glBindTexture( m_samplers[tmu].m_boundTex->m_layout->m_key.m_texGLTarget, 0 );
+ }
+ else
+ {
+ // same target, new tex, no work to do.
+ }
+ }
+ }
+ else
+ {
+ // mega scrub
+ glBindTexture( GL_TEXTURE_1D, 0 );
+ glBindTexture( GL_TEXTURE_2D, 0 );
+ glBindTexture( GL_TEXTURE_3D, 0 );
+ glBindTexture( GL_TEXTURE_CUBE_MAP, 0 );
+ }
+
+ glBindTexture( tex->m_layout->m_key.m_texGLTarget, tex->m_texName );
+ GLMCheckError();
+ }
+ tex->m_bindPoints |= (1<m_layout->m_key.m_texGLTarget, 0 );
+ GLMCheckError();
+ }
+ else
+ {
+ // none was bound before, so no action
+ }
+ m_samplers[tmu].m_boundTex = NULL;
+ }
+
+ return 0;
+}
+
+void GLMContext::BindFBOToCtx( CGLMFBO *fbo, GLenum bindPoint )
+{
+ GLM_FUNC;
+ GLMPRINTF(( "--- GLMContext::BindFBOToCtx fbo %p, GL name %d", fbo, (fbo) ? fbo->m_name : -1 ));
+
+ CheckCurrent();
+
+ bool targetRead = (bindPoint==GL_READ_FRAMEBUFFER_EXT) || (bindPoint==GL_FRAMEBUFFER_EXT);
+ bool targetDraw = (bindPoint==GL_DRAW_FRAMEBUFFER_EXT) || (bindPoint==GL_FRAMEBUFFER_EXT);
+
+ if (targetRead)
+ {
+ if (fbo) // you can pass NULL to go back to no-FBO
+ {
+ glBindFramebufferEXT( GL_READ_FRAMEBUFFER_EXT, fbo->m_name );
+ GLMCheckError();
+
+ m_boundReadFBO = fbo;
+ //dontcare fbo->m_bound = true;
+ }
+ else
+ {
+ glBindFramebufferEXT( GL_READ_FRAMEBUFFER_EXT, 0 );
+ GLMCheckError();
+
+ m_boundReadFBO = NULL;
+ }
+ }
+
+ if (targetDraw)
+ {
+ if (fbo) // you can pass NULL to go back to no-FBO
+ {
+ glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, fbo->m_name );
+ GLMCheckError();
+
+ m_boundDrawFBO = fbo;
+ //dontcare fbo->m_bound = true;
+ }
+ else
+ {
+ glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, 0 );
+ GLMCheckError();
+
+ m_boundDrawFBO = NULL;
+ }
+ }
+}
+
+void GLMContext::BindBufferToCtx( EGLMBufferType type, CGLMBuffer *buff, bool force )
+{
+ GLM_FUNC;
+ GLMPRINTF(( "--- GLMContext::BindBufferToCtx buff %p, GL name %d", buff, (buff) ? buff->m_name : -1 ));
+
+ CheckCurrent();
+
+ if (!force)
+ {
+ // compare desired bind to last known bind, and see if we can bail
+ if (m_lastKnownBufferBinds[ type ] == buff)
+ {
+ return;
+ }
+ }
+
+ GLenum target=0;
+ switch( type )
+ {
+ case kGLMVertexBuffer: target = GL_ARRAY_BUFFER_ARB; break;
+ case kGLMIndexBuffer: target = GL_ELEMENT_ARRAY_BUFFER_ARB; break;
+ case kGLMUniformBuffer: target = GL_UNIFORM_BUFFER_EXT; break;
+ case kGLMPixelBuffer: target = GL_PIXEL_UNPACK_BUFFER_ARB; break;
+
+ default: Assert(!"Unknown buffer type" );
+ }
+
+ bool wasBound = false;
+ bool isBound = false;
+
+ (void)wasBound;
+ (void)isBound;
+
+ if (m_lastKnownBufferBinds[type])
+ {
+ m_lastKnownBufferBinds[type]->m_bound = false;
+ m_lastKnownBufferBinds[type] = NULL;
+ wasBound = true;
+ }
+
+ if (buff)
+ {
+ if (buff->m_buffGLTarget != target)
+ Debugger();
+
+ glBindBufferARB( buff->m_buffGLTarget, buff->m_name );
+ GLMCheckError();
+
+ m_lastKnownBufferBinds[ type ] = buff;
+ buff->m_bound = true;
+
+ isBound = true;
+ }
+ else
+ {
+ // isBound stays false
+ // bind name 0
+ // note that no buffer is bound in the ctx state
+
+ glBindBufferARB( target, 0 );
+ GLMCheckError();
+
+ m_lastKnownBufferBinds[ type ] = NULL;
+ }
+}
+
+//ConVar gl_can_mix_shader_gammas( "gl_can_mix_shader_gammas", 0 );
+int gl_can_mix_shader_gammas = 0;
+
+//ConVar gl_cannot_mix_shader_gammas( "gl_cannot_mix_shader_gammas", 0 );
+int gl_cannot_mix_shader_gammas = 0;
+
+void GLMContext::FlushDrawStates( bool shadersOn ) // shadersOn = true for draw calls, false for clear calls
+{
+ GLM_FUNC;
+
+ CheckCurrent();
+
+ // FBO
+ if ( (m_drawingFBO != m_boundDrawFBO) || (m_drawingFBO != m_boundReadFBO) )
+ {
+ //GLMPRINTF(("\nGLMContext::FlushDrawStates, setting FBO to %8x(gl %d), was %8x(gl %d)", m_drawingFBO, (m_drawingFBO? m_drawingFBO->m_name: -1),m_boundFBO, (m_boundFBO ? m_boundFBO->m_name : -1) ));
+ this->BindFBOToCtx( m_drawingFBO, GL_READ_FRAMEBUFFER_EXT );
+ this->BindFBOToCtx( m_drawingFBO, GL_DRAW_FRAMEBUFFER_EXT );
+ }
+
+ // if drawing FBO has any MSAA attachments, mark them dirty
+ {
+ for( int att=kAttColor0; attm_attach[ att ].m_tex)
+ {
+ CGLMTex *tex = m_drawingFBO->m_attach[ att ].m_tex;
+
+ if (tex->m_rboName) // is it MSAA
+ {
+ // mark it dirty
+ tex->m_rboDirty = true;
+ }
+ }
+ }
+ }
+
+ // renderstates
+ this->FlushStates(); // latched renderstates..
+
+ // if there is no color target - bail out
+ // OK, this doesn't work in general - you can't leave the color target floating(null) or you will get FBO errors
+ //if (!m_boundDrawFBO[0].m_attach[0].m_tex)
+ //{
+ // GLMPRINTF(("-D- GLMContext::FlushDrawStates -> no color target! exiting.. " ));
+ // return;
+ //}
+
+ bool tex0_srgb = (m_boundDrawFBO[0].m_attach[0].m_tex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0;
+
+ // you can only actually use the sRGB FB state on some systems.. check caps
+ if (m_caps.m_hasGammaWrites)
+ {
+ GLBlendEnableSRGB_t writeSRGBState;
+ m_BlendEnableSRGB.Read( &writeSRGBState, 0 ); // the client set value, not the API-written value yet..
+ bool draw_srgb = writeSRGBState.enable;
+
+ if (draw_srgb)
+ {
+ if (tex0_srgb)
+ {
+ // good - draw mode and color tex agree
+ }
+ else
+ {
+ // bad
+
+ // Client has asked to write sRGB into a texture that can't do it.
+ // there is no way to satisfy this unless we change the RT tex and we avoid doing that.
+ // (although we might consider a ** ONE TIME ** promotion.
+ // this shouldn't be a big deal if the tex format is one where it doesn't matter like 32F.
+
+ GLMPRINTF(("-Z- srgb-enabled FBO conflict: attached tex %08x [%s] is not SRGB", m_boundDrawFBO[0].m_attach[0].m_tex, m_boundDrawFBO[0].m_attach[0].m_tex->m_layout->m_layoutSummary ));
+
+ // do we shoot down the srgb-write state for this batch?
+ // I think the runtime will just ignore it.
+ }
+ }
+ else
+ {
+ if (tex0_srgb)
+ {
+ // odd - client is not writing sRGB into a texture which *can* do it.
+ //GLMPRINTF(( "-Z- srgb-disabled FBO conflict: attached tex %08x [%s] is SRGB", m_boundFBO[0].m_attach[0].m_tex, m_boundFBO[0].m_attach[0].m_tex->m_layout->m_layoutSummary ));
+ //writeSRGBState.enable = true;
+ //m_BlendEnableSRGB.Write( &writeSRGBState );
+ }
+ else
+ {
+ // good - draw mode and color tex agree
+ }
+ }
+
+ // now go ahead and flush the SRGB write state for real
+ // set the noDefer on it too
+ m_BlendEnableSRGB.Flush( /*true*/ );
+ }
+ // else... FlushDrawStates will work it out via flSRGBWrite in the fragment shader..
+
+ // textures and sampling
+ // note we generate a mask of which samplers are running "decode sRGB" mode, to help out the shader pair cache mechanism below.
+ uint srgbMask = 0;
+ for( int i=0; im_boundTex != samp->m_drawTex)
+ {
+ this->BindTexToTMU( samp->m_drawTex, i );
+ samp->m_boundTex = samp->m_drawTex;
+ }
+
+ // push sampling params? it will check each one individually.
+ if (samp->m_boundTex)
+ {
+ samp->m_boundTex->ApplySamplingParams( &samp->m_samp );
+ }
+
+ if (samp->m_samp.m_srgb)
+ {
+ srgbMask |= (1<m_descs[ kGLMARB ].m_valid)
+ {
+ glSetEnable( GL_VERTEX_PROGRAM_ARB, true );
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vp->m_descs[ kGLMARB ].m_object.arb);
+ GLMCheckError();
+
+ m_boundProgram[ kGLMVertexProgram ] = vp;
+ vpgood = true;
+ }
+ else
+ {
+ //Assert( !"Trying to draw with invalid ARB vertex program" );
+ }
+ }
+ else
+ {
+ //Assert( !"Trying to draw with NULL ARB vertex program" );
+ }
+ }
+
+ // fragment side
+ {
+ CGLMProgram *fp = m_drawingProgram[ kGLMFragmentProgram ];
+ if (fp)
+ {
+ if (fp->m_descs[ kGLMARB ].m_valid)
+ {
+ glSetEnable( GL_FRAGMENT_PROGRAM_ARB, true );
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fp->m_descs[ kGLMARB ].m_object.arb);
+ GLMCheckError();
+
+ m_boundProgram[ kGLMFragmentProgram ] = fp;
+ fpgood = true;
+ }
+ else
+ {
+ //Assert( !"Trying to draw with invalid ARB fragment program" );
+ m_boundProgram[ kGLMFragmentProgram ] = NULL;
+ }
+ }
+ else
+ {
+ // this is actually OK, we substitute a dummy shader
+ glSetEnable( GL_FRAGMENT_PROGRAM_ARB, true );
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_nullFragmentProgram->m_descs[kGLMARB].m_object.arb );
+ m_boundProgram[ kGLMFragmentProgram ] = m_nullFragmentProgram;
+ fpgood = true;
+ }
+ }
+
+ if (fpgood & vpgood)
+ {
+ // flush parameter values to both stages
+ // FIXME: this can be optimized by dirty range, since ARB supports single-parameter-bank aka .env
+ // FIXME: magic numbers, yuk
+
+ glProgramEnvParameters4fvEXT( GL_VERTEX_PROGRAM_ARB, 0, 256, (const GLfloat*)&m_programParamsF[kGLMVertexProgram].m_values[0][0] );
+ GLMCheckError();
+
+ glProgramEnvParameters4fvEXT( GL_FRAGMENT_PROGRAM_ARB, 0, 32, (const GLfloat*)&m_programParamsF[kGLMFragmentProgram].m_values[0][0] );
+ GLMCheckError();
+ }
+ else
+ {
+ // silence all (clears wind up here for example)
+
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0 );
+ glSetEnable( GL_VERTEX_PROGRAM_ARB, false );
+ m_boundProgram[ kGLMVertexProgram ] = NULL;
+
+ glSetEnable( GL_FRAGMENT_PROGRAM_ARB, false );
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0 );
+ m_boundProgram[ kGLMFragmentProgram ] = NULL;
+ }
+///////////////////////////////////
+
+ // ARB vert setup. maybe generalize this to handle both ARB and GLSL after we see what GLSL attrib setup looks like.
+
+ //http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribPointer.xml
+ //http://www.opengl.org/sdk/docs/man/xhtml/glEnableVertexAttribArray.xml
+
+ // for (each attrib)
+ // if (enable unchanged and off) -> do nothing
+ // if (enable changed to off) -> disable that array ... set the attrib pointer to nil for clarity
+ // if (enable changed to on) -> bind the appropriate vertex buffer, set that attrib, log it
+ // if (enable unchanged and on) -> diff the attrib setup, re-bind if needed, log it
+
+ GLMVertexSetup *setup = &m_drawVertexSetup;
+ uint relevantMask = setup->m_attrMask;
+
+ for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
+ {
+ uint mask = 1<m_attrs[index]; // ptr to desired setup
+ CGLMBuffer * buf = setdesc->m_buffer; // bind buffer
+ Assert( buf );
+
+ BindBufferToCtx( kGLMVertexBuffer, buf );
+
+ glEnableVertexAttribArray( index ); // enable attribute, set pointer.
+ GLMCheckError();
+
+ glVertexAttribPointer( index, setdesc->m_datasize, setdesc->m_datatype, setdesc->m_normalized, setdesc->m_stride, (const GLvoid *)(uintptr_t)setdesc->m_offset );
+ GLMCheckError();
+ //GLMPRINTF(("--- GLMContext::SetVertexAttributes attr %d set to offset/stride %d/%d in buffer %d (normalized=%s)", index, setdesc->m_offset, setdesc->m_stride, setdesc->m_buffer->m_name, setdesc->m_normalized?"true":"false" ));
+ }
+ else
+ {
+ // disable attribute
+ glDisableVertexAttribArray( index );
+ GLMCheckError();
+ //GLMPRINTF((" -- GLMContext::SetVertexAttributes attr %d is disabled", index ));
+
+ // tidy up in case there was garbage? necessary ?
+ memset ( &setup->m_attrs[index], 0, sizeof(setup->m_attrs[index]) );
+ }
+ }
+
+///////////////////////////////////
+ }
+ break;
+
+ case kGLMGLSL:
+ {
+ // early out if one of the stages is not set.
+ // draw code needs to watch for this too.
+ if ( (m_drawingProgram[ kGLMVertexProgram ]==NULL) || (m_drawingProgram[ kGLMFragmentProgram ]==NULL) )
+ {
+ this->NullProgram();
+ return;
+ }
+
+ // examine selected drawing programs for both stages
+ // try to find a match in thelinked-pair-cache
+ // if no match, link one
+ // examine metadata
+ // get uniform locations for parameters, attributes, and samplers
+ // put in cache
+
+ // dispatch vertex attribute locations to shader (could be one-time)
+ // dispatch parameter values to both stages (could be optimized with UBO)
+ // dispatch sampler locations to shader (need sampler metadata)
+
+ // new way - use the pair cache
+
+ // cook up some extra bits so that we can track different srgb-usages of the same vp/fp pair.
+ // note that this is only important on some hardware/OS combos.
+ // let the pair cache decide if it needs to honor the extra key bits or not.
+
+
+ // decide if we need to mix extra bits into the lookup key.
+ bool useExtraKeyBits = m_caps.m_costlyGammaFlips;
+
+ // the "can" variable is allowed to override the static assessment.
+ if ( gl_can_mix_shader_gammas/*.GetInt()*/ )
+ {
+ useExtraKeyBits = false;
+ }
+
+ // the "cannot" variable is allowed to override the first two
+ if ( gl_cannot_mix_shader_gammas/*.GetInt()*/ )
+ {
+ useExtraKeyBits = true;
+ }
+
+ uint extraKeyBits = 0;
+
+ if (useExtraKeyBits)
+ {
+ extraKeyBits = (srgbMask & m_drawingProgram[ kGLMFragmentProgram ]->m_samplerMask);
+ }
+
+ CGLMShaderPair *newPair = m_pairCache->SelectShaderPair( m_drawingProgram[ kGLMVertexProgram ], m_drawingProgram[ kGLMFragmentProgram ], extraKeyBits );
+ GLhandleARB newPairProgram = newPair->m_program;
+ uint newPairRevision = newPair->m_revision;
+
+ // you cannot only key on the pair address, since pairs get evicted and pair records likely get recycled.
+ // so key on all three - pair address, program name, revision number
+ // this will also catch cases where a pair is re-linked (batch debugger / live edit)
+
+ if ( (newPair != m_boundPair) || (newPairProgram != m_boundPairProgram) || (newPairRevision != m_boundPairRevision) )
+ {
+ m_boundPair = newPair;
+ m_boundPairProgram = newPairProgram;
+ m_boundPairRevision = newPairRevision;
+
+ glUseProgram( (uintptr_t)newPairProgram );
+ GLMCheckError();
+
+ // set the dirty levels appropriately since the program changed and has never seen any of the current values.
+ m_programParamsF[kGLMVertexProgram].m_dirtySlotCount = m_drawingProgram[ kGLMVertexProgram ]->m_descs[kGLMGLSL].m_highWater+1;
+ m_programParamsF[kGLMFragmentProgram].m_dirtySlotCount = m_drawingProgram[ kGLMFragmentProgram ]->m_descs[kGLMGLSL].m_highWater+1;
+
+ // bool and int dirty levels get set to max, we don't have actual high water marks for them
+ // code which sends the values must clamp on these types.
+ m_programParamsB[kGLMVertexProgram].m_dirtySlotCount = kGLMProgramParamBoolLimit;
+ m_programParamsB[kGLMFragmentProgram].m_dirtySlotCount = 0;
+
+ m_programParamsI[kGLMVertexProgram].m_dirtySlotCount = kGLMProgramParamInt4Limit;
+ m_programParamsI[kGLMFragmentProgram].m_dirtySlotCount = 0;
+ }
+
+ // note the binding (not really bound.. just sitting in the linked active GLSL program)
+ m_boundProgram[ kGLMVertexProgram ] = m_drawingProgram[ kGLMVertexProgram ];
+ m_boundProgram[ kGLMFragmentProgram ] = m_drawingProgram[ kGLMFragmentProgram ];
+
+ // now pave the way for drawing
+
+ // parameters - find and set
+
+ // vertex stage --------------------------------------------------------------------
+ // find "vc" in VS
+ GLint vconstLoc = m_boundPair->m_locVertexParams;
+ if (vconstLoc >=0)
+ {
+ #if GLMDEBUG
+ static uint paramsPushed=0,paramsSkipped=0,callsPushed=0; // things that happened on pushed param trips
+ static uint callsSkipped=0,paramsSkippedByCallSkip=0; // on unpushed param trips (zero dirty)
+
+ (void)paramsPushed;
+ (void)paramsSkipped;
+ (void)callsPushed;
+ (void)callsSkipped;
+ (void)paramsSkippedByCallSkip;
+ #endif
+
+ int slotCountToPush = 0;
+ int shaderSlots = m_boundPair->m_vertexProg->m_descs[kGLMGLSL].m_highWater+1;
+ int dirtySlots = m_programParamsF[kGLMVertexProgram].m_dirtySlotCount;
+
+
+ switch( m_paramWriteMode )
+ {
+ case eParamWriteAllSlots: slotCountToPush = kGLMVertexProgramParamFloat4Limit; break;
+ case eParamWriteShaderSlots: slotCountToPush = shaderSlots; break;
+
+ case eParamWriteShaderSlotsOptional:
+ {
+ slotCountToPush = shaderSlots;
+
+ // ...unless, we're actually unchanged since last draw
+ if (dirtySlots == 0)
+ {
+ // write none
+ slotCountToPush = 0;
+ }
+ }
+ break;
+
+ case eParamWriteDirtySlotRange: slotCountToPush = dirtySlots; break;
+ }
+
+ if (slotCountToPush)
+ {
+ glUniform4fv( vconstLoc, slotCountToPush, &m_programParamsF[kGLMVertexProgram].m_values[0][0] );
+ GLMCheckError();
+
+ #if GLMDEBUG
+ paramsPushed += slotCountToPush;
+ paramsSkipped += shaderSlots - slotCountToPush;
+
+ callsPushed++;
+ #endif
+ }
+ else
+ {
+ #if GLMDEBUG
+ paramsSkippedByCallSkip += shaderSlots;
+
+ callsSkipped++;
+ #endif
+ }
+
+ #if GLMDEBUG && 0
+ if (GLMKnob("caps-key",NULL) > 0.0)
+ {
+ // spew
+ GLMPRINTF(("VP callsPushed=%d ( paramsPushed=%d paramsSkipped=%d ) callsSkipped=%d (paramsSkippedByCallSkip=%d)",
+ callsPushed, paramsPushed, paramsSkipped, callsSkipped, paramsSkippedByCallSkip
+ ));
+ }
+ #endif
+
+ m_programParamsF[kGLMVertexProgram].m_dirtySlotCount = 0; //ack
+ }
+
+ // see if VS uses i0, b0, b1, b2, b3.
+ // use a glUniform1i to set any one of these if active. skip all of them if no dirties reported.
+ // my kingdom for the UBO extension!
+
+ // ------- bools ---------- //
+ if ( 1 /*m_programParamsB[kGLMVertexProgram].m_dirtySlotCount*/ ) // optimize this later after the float param pushes are proven out
+ {
+ GLint vconstBool0Loc = m_boundPair->m_locVertexBool0; //glGetUniformLocationARB( prog, "b0");
+ if ( vconstBool0Loc >= 0 )
+ {
+ glUniform1i( vconstBool0Loc, m_programParamsB[kGLMVertexProgram].m_values[0] ); //FIXME magic number
+ GLMCheckError();
+ }
+
+ GLint vconstBool1Loc = m_boundPair->m_locVertexBool1; //glGetUniformLocationARB( prog, "b1");
+ if ( vconstBool1Loc >= 0 )
+ {
+ glUniform1i( vconstBool1Loc, m_programParamsB[kGLMVertexProgram].m_values[1] ); //FIXME magic number
+ GLMCheckError();
+ }
+
+ GLint vconstBool2Loc = m_boundPair->m_locVertexBool2; //glGetUniformLocationARB( prog, "b2");
+ if ( vconstBool2Loc >= 0 )
+ {
+ glUniform1i( vconstBool2Loc, m_programParamsB[kGLMVertexProgram].m_values[2] ); //FIXME magic number
+ GLMCheckError();
+ }
+
+ GLint vconstBool3Loc = m_boundPair->m_locVertexBool3; //glGetUniformLocationARB( prog, "b3");
+ if ( vconstBool3Loc >= 0 )
+ {
+ glUniform1i( vconstBool3Loc, m_programParamsB[kGLMVertexProgram].m_values[3] ); //FIXME magic number
+ GLMCheckError();
+ }
+ m_programParamsB[kGLMVertexProgram].m_dirtySlotCount = 0; //ack
+ }
+
+ // ------- int ---------- //
+ if ( 1 /*m_programParamsI[kGLMVertexProgram].m_dirtySlotCount*/ ) // optimize this later after the float param pushes are proven out
+ {
+ GLint vconstInt0Loc = m_boundPair->m_locVertexInteger0; //glGetUniformLocationARB( prog, "i0");
+ if ( vconstInt0Loc >= 0 )
+ {
+ glUniform1i( vconstInt0Loc, m_programParamsI[kGLMVertexProgram].m_values[0][0] ); //FIXME magic number
+ GLMCheckError();
+ }
+ m_programParamsI[kGLMVertexProgram].m_dirtySlotCount = 0; //ack
+ }
+
+
+ // attribs - find and set
+ // GLSL vert setup - clone/edit of ARB setup. try to re-unify these later.
+
+ GLMVertexSetup *setup = &m_drawVertexSetup;
+ uint relevantMask = setup->m_attrMask;
+
+ //static char *attribnames[] = { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15" };
+
+ CGLMBuffer *loopCurrentBuf = NULL; // local shock absorber for this loop
+ for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
+ {
+ uint mask = 1<m_attrs[index]; // ptr to desired setup
+
+ bool writeAttrib = false;
+
+ switch(m_attribWriteMode)
+ {
+ case eAttribWriteAll:
+ writeAttrib = true;
+ break;
+
+ case eAttribWriteDirty:
+ static uint hits=0,misses=0;
+ (void)hits;
+ (void)misses;
+
+ // first see if we have to do anything at all.
+ // the equality operator checks buffer name, offset, stride, datatype and normalized.
+ // we check buffer revision separately, submitter of vertex setup is not expected to provide it (zero is preferred).
+ // consult the actual buffer directly.
+
+ // note also, we're only doing thi compare when attrib #index is active for this batch.
+ // previously-active attribs which are becoming disabled need not be checked..
+
+ GLMVertexAttributeDesc *lastDesc = &m_lastKnownVertexAttribs[index];
+ if ( (!(*newDesc == *lastDesc)) || (newDesc->m_buffer->m_revision != lastDesc->m_bufferRevision) )
+ {
+ *lastDesc = *newDesc; // latch new setup
+ lastDesc->m_bufferRevision = newDesc->m_buffer->m_revision; // including proper revision of the sourcing buffer
+
+ writeAttrib = true;
+ misses++;
+ }
+ else
+ {
+ hits++;
+ }
+
+ #if 0
+ if ( ((hits+misses) % 10000)==0)
+ {
+ printf("\n** attrib setup hits %d misses %d",hits,misses);
+ }
+ #endif
+ break;
+ }
+
+ if( writeAttrib )
+ {
+ CGLMBuffer * buf = newDesc->m_buffer; // bind buffer
+ Assert( buf );
+
+ if (buf != loopCurrentBuf)
+ {
+ BindBufferToCtx( kGLMVertexBuffer, buf ); // (if not already on the bind point of interest)
+ GLMCheckError();
+
+ loopCurrentBuf = buf;
+ }
+
+ glVertexAttribPointer( index, newDesc->m_datasize, newDesc->m_datatype, newDesc->m_normalized, newDesc->m_stride, (const GLvoid *)(uintptr_t)newDesc->m_offset );
+ GLMCheckError();
+ }
+
+ // enable is checked separately from the attrib binding
+ if (! (m_lastKnownVertexAttribMask & (1<m_locFragmentParams;
+ if (fconstLoc >=0)
+ {
+ #if GLMDEBUG
+ static uint paramsPushed=0,paramsSkipped=0,callsPushed=0; // things that happened on pushed param trips
+ static uint callsSkipped=0,paramsSkippedByCallSkip=0; // on unpushed param trips (zero dirty)
+
+ (void)paramsPushed;
+ (void)paramsSkipped;
+ (void)callsPushed;
+ (void)callsSkipped;
+ (void)paramsSkippedByCallSkip;
+ #endif
+
+ int slotCountToPush = 0;
+ int shaderSlots = m_boundPair->m_fragmentProg->m_descs[kGLMGLSL].m_highWater+1;
+ int dirtySlots = m_programParamsF[kGLMFragmentProgram].m_dirtySlotCount;
+
+ switch( m_paramWriteMode )
+ {
+ case eParamWriteAllSlots: slotCountToPush = kGLMFragmentProgramParamFloat4Limit; break;
+ case eParamWriteShaderSlots: slotCountToPush = shaderSlots; break;
+
+ case eParamWriteShaderSlotsOptional:
+ {
+ slotCountToPush = shaderSlots;
+
+ // ...unless, we're actually unchanged since last draw
+ if (dirtySlots == 0)
+ {
+ // write none
+ slotCountToPush = 0;
+ }
+ }
+ break;
+
+ case eParamWriteDirtySlotRange: slotCountToPush = dirtySlots; break;
+ }
+
+ if (slotCountToPush)
+ {
+ glUniform4fv( fconstLoc, slotCountToPush, &m_programParamsF[kGLMFragmentProgram].m_values[0][0] );
+ GLMCheckError();
+
+ #if GLMDEBUG
+ paramsPushed += slotCountToPush;
+ paramsSkipped += shaderSlots - slotCountToPush;
+
+ callsPushed++;
+ #endif
+ }
+ else
+ {
+ #if GLMDEBUG
+ paramsSkippedByCallSkip += shaderSlots;
+
+ callsSkipped++;
+ #endif
+ }
+
+ #if GLMDEBUG && 0
+ if ( 0 && (GLMKnob("caps-key",NULL) > 0.0) ) // turn on as needed
+ {
+ // spew
+ GLMPRINTF(("FP callsPushed=%d ( paramsPushed=%d paramsSkipped=%d ) callsSkipped=%d (paramsSkippedByCallSkip=%d)",
+ callsPushed, paramsPushed, paramsSkipped, callsSkipped, paramsSkippedByCallSkip
+ ));
+ }
+ #endif
+
+ m_programParamsF[kGLMFragmentProgram].m_dirtySlotCount = 0; //ack
+ }
+
+ // fake SRGB
+ if (!m_caps.m_hasGammaWrites) // do we need to think about fake SRGB?
+ {
+ if (m_boundPair->m_locFragmentFakeSRGBEnable >= 0) // does the shader have that uniform handy?
+ {
+ float desiredValue = m_FakeBlendEnableSRGB ? 1.0 : 0.0; // what should it be set to?
+
+ if (desiredValue != m_boundPair->m_fakeSRGBEnableValue) // and is that different from what it is known to be set to ?
+ {
+ glUniform1f( m_boundPair->m_locFragmentFakeSRGBEnable, desiredValue ); // if so, write it
+ GLMCheckError();
+
+ m_boundPair->m_fakeSRGBEnableValue = desiredValue; // and recall that we did so
+ }
+ }
+ }
+
+ //samplers
+ if (m_boundPair)
+ {
+ if(!m_boundPair->m_samplersFixed)
+ {
+ for( int sampler=0; sampler<16; sampler++)
+ {
+ if (m_boundPair->m_locSamplers[sampler] >=0)
+ {
+ glUniform1iARB( m_boundPair->m_locSamplers[sampler], sampler );
+ GLMCheckError();
+ }
+ }
+ m_boundPair->m_samplersFixed = true;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ this->NullProgram();
+ }
+}
+
+
+#if GLMDEBUG
+
+enum EGLMDebugDumpOptions
+{
+ eDumpBatchInfo,
+ eDumpSurfaceInfo,
+ eDumpStackCrawl,
+ eDumpShaderLinks,
+// eDumpShaderText, // we never use this one
+ eDumpShaderParameters,
+ eDumpTextureSetup,
+ eDumpVertexAttribSetup,
+ eDumpVertexData,
+ eOpenShadersForEdit
+};
+
+enum EGLMVertDumpMode
+{
+ // options that affect eDumpVertexData above
+ eDumpVertsNoTransformDump,
+ eDumpVertsTransformedByViewProj,
+ eDumpVertsTransformedByModelViewProj,
+ eDumpVertsTransformedByBoneZeroThenViewProj,
+ eDumpVertsTransformedByBonesThenViewProj,
+ eLastDumpVertsMode
+};
+
+const char *g_vertDumpModeNames[] =
+{
+ "noTransformDump",
+ "transformedByViewProj",
+ "transformedByModelViewProj",
+ "transformedByBoneZeroThenViewProj",
+ "transformedByBonesThenViewProj"
+};
+
+static void CopyTilEOL( char *dst, char *src, int dstSize )
+{
+ dstSize--;
+
+ int i=0;
+ while ( (im_caller==eDrawElements) || (info->m_caller==eDrawArrays) );
+ const char *batchtype = is_draw ? "draw" : "clear";
+
+ if (options & (1<m_attach[i].m_tex;
+ if (tex)
+ {
+ GLMPRINTF(("-D- bound FBO (%8x) attachment %d = tex %8x (GL %d) (%s)", fbo, i, tex, tex->m_texName, tex->m_layout->m_layoutSummary ));
+ }
+ else
+ {
+ // warning if no depthstencil attachment
+ switch(i)
+ {
+ case kAttDepth:
+ case kAttStencil:
+ case kAttDepthStencil:
+ GLMPRINTF(("-D- bound FBO (%8x) attachment %d = NULL, warning!", fbo, i ));
+ break;
+ }
+ }
+ }
+ }
+
+ #if 0 // disabled in steamworks sample for the time being
+ if (options & (1<GetStackCrawl(&cp);
+
+ GLMPRINTF(("-D-" ));
+ GLMPRINTF(("-D- stack crawl"));
+ for( int i=0; i< cp.m_frameCount; i++)
+ {
+ GLMPRINTF(("-D-\t%s", cp.m_crawlNames[i] ));
+ }
+ }
+ #endif
+
+ if ( (options & (1<m_text, "#//ATTRIBMAP");
+ if (attribmap)
+ {
+ CopyTilEOL( attribtemp, attribmap, sizeof(attribtemp) );
+ }
+ else
+ {
+ strcpy( attribtemp, "no attrib map" );
+ }
+
+ char *trans = strstr(vp->m_text, "#// trans#");
+ if (trans)
+ {
+ CopyTilEOL( transtemp, trans, sizeof(transtemp) );
+ }
+ else
+ {
+ strcpy( transtemp, "no translation info" );
+ }
+
+ const char *linkpath = "no file link";
+
+ #if GLMDEBUG && 0 // no editable shader support in example code
+ linkpath = vp->m_editable->m_mirror->m_path;
+
+ GLMPRINTF(("-D-"));
+ GLMPRINTF(("-D- ARBVP || GL %d || Path %s ", vp->m_descs[kGLMARB].m_object.arb, linkpath ));
+ GLMPRINTF(("-D- Attribs %s", attribtemp ));
+ GLMPRINTF(("-D- Trans %s", transtemp ));
+ #endif
+
+ /*
+ if ( (options & (1<m_string, eDebugDump ));
+ }
+ */
+ }
+ else
+ {
+ GLMPRINTF(("-D- VP (none)" ));
+ }
+
+ if (fp)
+ {
+ char *trans = strstr(fp->m_text, "#// trans#");
+ if (trans)
+ {
+ CopyTilEOL( transtemp, trans, sizeof(transtemp) );
+ }
+ else
+ {
+ strcpy( transtemp, "no translation info" );
+ }
+
+ const char *linkpath = "no file link";
+
+ #if GLMDEBUG && 0 // no editable shader support in example code
+ linkpath = fp->m_editable->m_mirror->m_path;
+
+ GLMPRINTF(("-D-"));
+ GLMPRINTF(("-D- FP || GL %d || Path %s ", fp->m_descs[kGLMARB].m_object.arb, linkpath ));
+ GLMPRINTF(("-D- Trans %s", transtemp ));
+ #endif
+
+ /*
+ if ( (options & (1<m_string, eDebugDump));
+ }
+ */
+ }
+ else
+ {
+ GLMPRINTF(("-D- FP (none)" ));
+ }
+ }
+
+ if ( (options & (1<m_drawVertexSetup;
+ for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
+ {
+ usesSkinning |= (setup->m_attrMask & (1<m_vtxAttribMap[index]>>4)== D3DDECLUSAGE_BLENDWEIGHT);
+ }
+ if (usesSkinning)
+ {
+ upperSlotLimit = 256;
+ }
+
+ while( slotIndex < upperSlotLimit )
+ {
+ // if slot index is in a masked range, skip it
+ // if slot index is the start of a matrix, label it, print it, skip ahead 4 slots
+ for( int maski=0; vmaskranges[maski] >=0; maski+=2)
+ {
+ if ( (slotIndex >= vmaskranges[maski]) && (slotIndex <= vmaskranges[maski+1]) )
+ {
+ // that index is masked. set to one past end of range, print a blank line for clarity
+ slotIndex = vmaskranges[maski+1]+1;
+ GLMPrintStr("-D- .....");
+ }
+ }
+
+ if (slotIndex < upperSlotLimit)
+ {
+ float *values = &m_programParamsF[ kGLMVertexProgram ].m_values[slotIndex][0];
+
+ #if 0 // Source specific
+ switch( slotIndex )
+ {
+ case 4:
+ printmat( "MODELVIEWPROJ", slotIndex, 4, values );
+ slotIndex += 4;
+ break;
+
+ case 8:
+ printmat( "VIEWPROJ", slotIndex, 4, values );
+ slotIndex += 4;
+ break;
+
+ default:
+ if (slotIndex>=58)
+ {
+ // bone
+ char bonelabel[100];
+
+ sprintf(bonelabel, "MODEL_BONE%-2d", (slotIndex-58)/3 );
+ printmat( bonelabel, slotIndex, 3, values );
+
+ slotIndex += 3;
+ }
+ else
+ {
+ // just print the one slot
+ GLMPRINTF(("-D- %03d: [ %10.5f %10.5f %10.5f %10.5f ] %s", slotIndex, values[0], values[1], values[2], values[3], label ));
+ slotIndex++;
+ }
+ break;
+ }
+ #else
+ // just print the one slot
+ GLMPRINTF(("-D- %03d: [ %10.5f %10.5f %10.5f %10.5f ] %s", slotIndex, values[0], values[1], values[2], values[3], label ));
+ slotIndex++;
+ #endif
+ }
+ }
+
+ // VP stage still, if in GLSL mode, find the bound pair and see if it has live i0, b0-b3 uniforms
+ if (m_boundPair) // should only be non-NULL in GLSL mode
+ {
+ if (m_boundPair->m_locVertexBool0>=0)
+ {
+ GLMPRINTF(("-D- GLSL 'b0': %d", m_programParamsB[kGLMVertexProgram].m_values[0] ));
+ }
+
+ if (m_boundPair->m_locVertexBool1>=0)
+ {
+ GLMPRINTF(("-D- GLSL 'b1': %d", m_programParamsB[kGLMVertexProgram].m_values[1] ));
+ }
+
+ if (m_boundPair->m_locVertexBool2>=0)
+ {
+ GLMPRINTF(("-D- GLSL 'b2': %d", m_programParamsB[kGLMVertexProgram].m_values[2] ));
+ }
+
+ if (m_boundPair->m_locVertexBool3>=0)
+ {
+ GLMPRINTF(("-D- GLSL 'b3': %d", m_programParamsB[kGLMVertexProgram].m_values[3] ));
+ }
+
+ if (m_boundPair->m_locVertexInteger0>=0)
+ {
+ GLMPRINTF(("-D- GLSL 'i0': %d", m_programParamsI[kGLMVertexProgram].m_values[0][0] ));
+ }
+ }
+
+ GLMPRINTF(("-D-"));
+ GLMPRINTF(("-D- FP parameters " ));
+
+ static int fmaskranges[] = { 40,41, -1,-1 };
+
+ slotIndex = 0;
+ label = "";
+ while(slotIndex < 4) // reduced from 40 for example code
+ {
+ // if slot index is in a masked range, skip it
+ // if slot index is the start of a matrix, label it, print it, skip ahead 4 slots
+ for( int maski=0; fmaskranges[maski] >=0; maski+=2)
+ {
+ if ( (slotIndex >= fmaskranges[maski]) && (slotIndex <= fmaskranges[maski+1]) )
+ {
+ // that index is masked. set to one past end of range, print a blank line for clarity
+ slotIndex = fmaskranges[maski+1]+1;
+ GLMPrintStr("-D- .....");
+ }
+ }
+
+ if (slotIndex < 40)
+ {
+ float *values = &m_programParamsF[ kGLMFragmentProgram ].m_values[slotIndex][0];
+ #if 0 //Source specific
+ switch( slotIndex )
+ {
+ case 0: label = "g_EnvmapTint"; break;
+ case 1: label = "g_DiffuseModulation"; break;
+ case 2: label = "g_EnvmapContrast_ShadowTweaks"; break;
+ case 3: label = "g_EnvmapSaturation_SelfIllumMask (xyz, and w)"; break;
+ case 4: label = "g_SelfIllumTint_and_BlendFactor (xyz, and w)"; break;
+
+ case 12: label = "g_ShaderControls"; break;
+ case 13: label = "g_DepthFeatheringConstants"; break;
+
+ case 20: label = "g_EyePos"; break;
+ case 21: label = "g_FogParams"; break;
+ case 22: label = "g_FlashlightAttenuationFactors"; break;
+ case 23: label = "g_FlashlightPos"; break;
+ case 24: label = "g_FlashlightWorldToTexture"; break;
+
+ case 28: label = "cFlashlightColor"; break;
+ case 29: label = "g_LinearFogColor"; break;
+ case 30: label = "cLightScale"; break;
+ case 31: label = "cFlashlightScreenScale"; break;
+
+ default:
+ label = "";
+ break;
+ }
+ #else
+ label = "";
+ #endif
+ GLMPRINTF(("-D- %03d: [ %10.5f %10.5f %10.5f %10.5f ] %s", slotIndex, values[0], values[1], values[2], values[3], label ));
+
+ slotIndex ++;
+ }
+ }
+
+ //if (m_boundPair->m_locFragmentFakeSRGBEnable)
+ //{
+ // GLMPRINTF(("-D- GLSL 'flEnableSRGBWrite': %f", m_boundPair->m_fakeSRGBEnableValue ));
+ //}
+ }
+
+ if ( (options & (1<m_layout->m_layoutSummary ));
+
+ GLMPRINTF(("-D- addressMode[ %s %s %s ]",
+ GLMDecode( eGL_ENUM, samp->m_addressModes[0] ),
+ GLMDecode( eGL_ENUM, samp->m_addressModes[1] ),
+ GLMDecode( eGL_ENUM, samp->m_addressModes[2] )
+ ));
+
+ GLMPRINTF(("-D- magFilter [ %s ]", GLMDecode( eGL_ENUM, samp->m_magFilter ) ));
+ GLMPRINTF(("-D- minFilter [ %s ]", GLMDecode( eGL_ENUM, samp->m_minFilter ) ));
+ GLMPRINTF(("-D- srgb [ %s ]", samp->m_srgb ? "T" : "F" ));
+
+ // add more as needed later..
+ }
+ }
+ }
+
+ if ( (options & (1<m_drawVertexSetup;
+
+ uint relevantMask = setup->m_attrMask;
+ for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
+ {
+ uint mask = 1<m_attrs[index];
+
+ char sizestr[100];
+ if (setdesc->m_datasize < 32)
+ {
+ sprintf( sizestr, "%d", setdesc->m_datasize);
+ }
+ else
+ {
+ strcpy( sizestr, GLMDecode( eGL_ENUM, setdesc->m_datasize ) );
+ }
+
+ if (setup->m_vtxAttribMap[index] != 0xBB)
+ {
+ GLMPRINTF(("-D- attr=%-2d decl=$%s%1d stride=%-2d offset=%-3d buf=%08x bufbase=%08x size=%s type=%s normalized=%s ",
+ index,
+ GLMDecode(eD3D_VTXDECLUSAGE, setup->m_vtxAttribMap[index]>>4 ),
+ setup->m_vtxAttribMap[index]&0x0F,
+ setdesc->m_stride,
+ setdesc->m_offset,
+ setdesc->m_buffer,
+ setdesc->m_buffer->m_lastMappedAddress,
+ sizestr,
+ GLMDecode( eGL_ENUM, setdesc->m_datatype),
+ setdesc->m_normalized?"Y":"N"
+ ));
+ }
+ else
+ {
+ // the attrib map is referencing an attribute that is not wired up in the vertex setup...
+ Debugger();
+ }
+ }
+ }
+ }
+
+ if ( (options & (1<m_drawVertexSetup;
+ int start = info->m_drawStart;
+ int end = info->m_drawEnd;
+ int endLimit = start + (1<=0)
+ {
+ mark += sprintf(mark, "-D- %04d: ", vtxIndex );
+ }
+
+ // for transform dumping, we latch values as we spot them
+ float vtxPos[4];
+ int vtxBoneIndices[4]; // only three get used
+ float vtxBoneWeights[4]; // only three get used and index 2 is synthesized from 0 and 1
+
+ vtxPos[0] = vtxPos[1] = vtxPos[2] = 0.0;
+ vtxPos[3] = 1.0;
+
+ vtxBoneIndices[0] = vtxBoneIndices[1] = vtxBoneIndices[2] = vtxBoneIndices[3] = 0;
+ vtxBoneWeights[0] = vtxBoneWeights[1] = vtxBoneWeights[2] = vtxBoneWeights[3] = 0.0;
+
+ for( int attr = 0; attr < kGLMVertexAttributeIndexMax; attr++ )
+ {
+ if (setup->m_attrMask & (1<m_attrs[ attr ];
+
+ // print that attribute.
+
+ // on OSX, VB's never move unless resized. You can peek at them when unmapped. Safe enough for debug..
+ char *bufferBase = (char*)desc->m_buffer->m_lastMappedAddress;
+
+ uint stride = desc->m_stride;
+ uint fieldoffset = desc->m_offset;
+ uint baseoffset = vtxIndex * stride;
+
+ char *attrBase = bufferBase + baseoffset + fieldoffset;
+
+ uint usage = setup->m_vtxAttribMap[attr]>>4;
+ uint usageindex = setup->m_vtxAttribMap[attr]&0x0F;
+
+ if (vtxIndex <0)
+ {
+ mark += sprintf(mark, "[%s%1d @ offs=%04d / strd %03d] ", GLMDecode(eD3D_VTXDECLUSAGE, usage ), usageindex, fieldoffset, stride );
+ }
+ else
+ {
+ mark += sprintf(mark, "[%s%1d ", GLMDecode(eD3D_VTXDECLUSAGE, usage ), usageindex );
+
+ if (desc->m_datasize<32)
+ {
+ for( int which = 0; which < desc->m_datasize; which++ )
+ {
+ static const char *fieldname = "xyzw";
+ switch( desc->m_datatype )
+ {
+ case GL_FLOAT:
+ {
+ float *floatbase = (float*)attrBase;
+ mark += sprintf(mark, (usage != D3DDECLUSAGE_TEXCOORD) ? "%c%7.3f " : "%c%.3f", fieldname[which], floatbase[which] );
+
+ if (usage==D3DDECLUSAGE_POSITION)
+ {
+ if (which<4)
+ {
+ // latch pos
+ vtxPos[which] = floatbase[which];
+ }
+ }
+
+ if (usage==D3DDECLUSAGE_BLENDWEIGHT)
+ {
+ if (which<4)
+ {
+ // latch weight
+ vtxBoneWeights[which] = floatbase[which];
+ }
+ }
+ }
+ break;
+
+ case GL_UNSIGNED_BYTE:
+ {
+ unsigned char *unchbase = (unsigned char*)attrBase;
+ mark += sprintf(mark, "%c$%02X ", fieldname[which], unchbase[which] );
+ }
+ break;
+
+ default:
+ // hold off on other formats for now
+ mark += sprintf(mark, "%c????? ", fieldname[which] );
+ break;
+ }
+ }
+ }
+ else // special path for BGRA bytes which are expressed in GL by setting the *size* to GL_BGRA (gross large enum)
+ {
+ switch(desc->m_datasize)
+ {
+ case GL_BGRA: // byte reversed color
+ {
+ for( int which = 0; which < 4; which++ )
+ {
+ static const char *fieldname = "BGRA";
+ switch( desc->m_datatype )
+ {
+ case GL_UNSIGNED_BYTE:
+ {
+ unsigned char *unchbase = (unsigned char*)attrBase;
+ mark += sprintf(mark, "%c$%02X ", fieldname[which], unchbase[which] );
+
+ if (usage==D3DDECLUSAGE_BLENDINDICES)
+ {
+ if (which<4)
+ {
+ // latch index
+ vtxBoneIndices[which] = unchbase[which]; // ignoring the component reverse which BGRA would inflict, but we also ignore it below so it matches up.
+ }
+ }
+ }
+ break;
+
+ default:
+ Debugger();
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ mark += sprintf(mark, "] " );
+ }
+ }
+ }
+ GLMPrintStr( buf, eDebugDump );
+
+ if (vtxIndex >=0)
+ {
+ // if transform dumping requested, and we've reached the actual vert dump phase, do it
+ float vtxout[4];
+ const char *translabel = NULL; // NULL means no print...
+
+ switch( g_vertDumpMode )
+ {
+ case eDumpVertsNoTransformDump: break;
+
+ case eDumpVertsTransformedByViewProj: // viewproj is slot 8
+ {
+ float *viewproj = &m_programParamsF[ kGLMVertexProgram ].m_values[8][0];
+ transform_dp4( vtxPos, viewproj, 4, vtxout );
+ translabel = "post-viewproj";
+ }
+ break;
+
+ case eDumpVertsTransformedByModelViewProj: // modelviewproj is slot 4
+ {
+ float *modelviewproj = &m_programParamsF[ kGLMVertexProgram ].m_values[4][0];
+ transform_dp4( vtxPos, modelviewproj, 4, vtxout );
+ translabel = "post-modelviewproj";
+ }
+ break;
+
+ case eDumpVertsTransformedByBoneZeroThenViewProj:
+ {
+ float postbone[4];
+ postbone[3] = 1.0;
+
+ float *bonemat = &m_programParamsF[ kGLMVertexProgram ].m_values[58][0];
+ transform_dp4( vtxPos, bonemat, 3, postbone );
+
+ float *viewproj = &m_programParamsF[ kGLMVertexProgram ].m_values[8][0]; // viewproj is slot 8
+ transform_dp4( postbone, viewproj, 4, vtxout );
+
+ translabel = "post-bone0-viewproj";
+ }
+ break;
+
+ case eDumpVertsTransformedByBonesThenViewProj:
+ {
+ float bone[4][4]; // [bone index][bone member] // members are adjacent
+
+ vtxout[0] = vtxout[1] = vtxout[2] = vtxout[3] = 0;
+
+ // unpack the third weight
+ vtxBoneWeights[2] = 1.0 - (vtxBoneWeights[0] + vtxBoneWeights[1]);
+
+ for( int ibone=0; ibone<3; ibone++ )
+ {
+ int boneindex = vtxBoneIndices[ ibone ];
+ float *bonemat = &m_programParamsF[ kGLMVertexProgram ].m_values[58+(boneindex*3)][0];
+
+ float boneweight = vtxBoneWeights[ibone];
+
+ float postbonevtx[4];
+
+ transform_dp4( vtxPos, bonemat, 3, postbonevtx );
+
+ // add weighted sum into output
+ for( int which=0; which<4; which++ )
+ {
+ vtxout[which] += boneweight * postbonevtx[which];
+ }
+ }
+
+ // fix W ? do we care ? check shaders to see what they do...
+ translabel = "post-skin3bone-viewproj";
+ }
+ break;
+
+ default:
+ break;
+ }
+ if(translabel)
+ {
+ // for extra credit, do the perspective divide and viewport
+
+ GLMPRINTF(("-D- %-24s: [ %7.4f %7.4f %7.4f %7.4f ]", translabel, vtxout[0],vtxout[1],vtxout[2],vtxout[3] ));
+ GLMPRINTF(("-D-" ));
+ }
+ }
+
+ if (vtxIndex<0)
+ {
+ vtxIndex = start-1; // for printing of the data (note it will be incremented at bottom of loop, so bias down by 1)
+ }
+ else
+ { // no more < and > around vert dump lines
+ //mark += sprintf(mark, "" );
+ }
+ }
+ }
+
+ if (options & (1<m_editable->OpenInEditor();
+ }
+
+ if (m_drawingProgram[ kGLMFragmentProgram ])
+ {
+ m_drawingProgram[ kGLMFragmentProgram ]->m_editable->OpenInEditor();
+ }
+ #endif
+ }
+/*
+ if (options & (1<<))
+ {
+ }
+*/
+ // trailer line
+ GLMPRINTF(("-D- ===================================================================================== end %s %d frame %d", batchtype, m_debugBatchIndex, m_debugFrameIndex ));
+
+ GLMSetIndent(oldIndent);
+}
+
+// here is the table that binds knob numbers to names. change at will.
+const char *g_knobnames[] =
+{
+/*0*/ "dummy",
+
+/*1*/ "FB-SRGB",
+ #if 0
+ /*1*/ "tex-U0-bias", // src left
+ /*2*/ "tex-V0-bias", // src upper
+ /*3*/ "tex-U1-bias", // src right
+ /*4*/ "tex-V1-bias", // src bottom
+
+ /*5*/ "pos-X0-bias", // dst left
+ /*6*/ "pos-Y0-bias", // dst upper
+ /*7*/ "pos-X1-bias", // dst right
+ /*8*/ "pos-Y1-bias", // dst bottom
+ #endif
+
+};
+int g_knobcount = sizeof( g_knobnames ) / sizeof( g_knobnames[0] );
+
+void GLMContext::DebugHook( GLMDebugHookInfo *info )
+{
+#if 0 // disabled in steamworks example for time being
+ bool debughook = false;
+ // debug hook is called after an action has taken place.
+ // that would be the initial action, or a repeat.
+ // if paused, we stay inside this function until return.
+ // when returning, we inform the caller if it should repeat its last action or continue.
+ // there is no global pause state. The rest of the app runs at the best speed it can.
+
+ // initial stuff we do unconditionally
+
+ // increment iteration
+ info->m_iteration++; // can be thought of as "number of times the caller's action has now occurred - starting at 1"
+
+ // now set initial state guess for the info block (outcome may change below)
+ info->m_loop = false;
+
+ // check prior hold-conditions to see if any of them hit.
+ // note we disarm each trigger once the hold has occurred (one-shot style)
+
+ switch( info->m_caller )
+ {
+ case eBeginFrame:
+ if (debughook) GLMPRINTF(("-D- Caller: BeginFrame" ));
+ if ( (m_holdFrameBegin>=0) && (m_holdFrameBegin==m_debugFrameIndex) ) // did we hit a frame breakpoint?
+ {
+ if (debughook) GLMPRINTF(("-D- BeginFrame trigger match, clearing m_holdFrameBegin, hold=true" ));
+
+ m_holdFrameBegin = -1;
+
+ info->m_holding = true;
+ }
+ break;
+
+ case eClear:
+ if (debughook) GLMPRINTF(("-D- Caller: Clear" ));
+ if ( (m_holdBatch>=0) && (m_holdBatchFrame>=0) && (m_holdBatch==m_debugBatchIndex) && (m_holdBatchFrame==m_debugFrameIndex) )
+ {
+ if (debughook) GLMPRINTF(("-D- Clear trigger match, clearing m_holdBatch&Frame, hold=true" ));
+
+ m_holdBatch = m_holdBatchFrame = -1;
+
+ info->m_holding = true;
+ }
+ break;
+
+ case eDrawElements:
+ if (debughook) GLMPRINTF(( (info->m_caller==eClear) ? "-D- Caller: Clear" : "-D- Caller: Draw" ));
+ if ( (m_holdBatch>=0) && (m_holdBatchFrame>=0) && (m_holdBatch==m_debugBatchIndex) && (m_holdBatchFrame==m_debugFrameIndex) )
+ {
+ if (debughook) GLMPRINTF(("-D- Draw trigger match, clearing m_holdBatch&Frame, hold=true" ));
+
+ m_holdBatch = m_holdBatchFrame = -1;
+
+ info->m_holding = true;
+ }
+ break;
+
+ case eEndFrame:
+ if (debughook) GLMPRINTF(("-D- Caller: EndFrame" ));
+
+ // check for any expired batch hold req
+ if ( (m_holdBatch>=0) && (m_holdBatchFrame>=0) && (m_holdBatchFrame==m_debugFrameIndex) )
+ {
+ // you tried to say 'next batch', but there wasn't one in this frame.
+ // target first batch of next frame instead
+ if (debughook) GLMPRINTF(("-D- EndFrame noticed an expired draw hold trigger, rolling to next frame, hold=false"));
+
+ m_holdBatch = 0;
+ m_holdBatchFrame++;
+
+ info->m_holding = false;
+ }
+
+ // now check for an explicit hold on end of this frame..
+ if ( (m_holdFrameEnd>=0) && (m_holdFrameEnd==m_debugFrameIndex) )
+ {
+ if (debughook) GLMPRINTF(("-D- EndFrame trigger match, clearing m_holdFrameEnd, hold=true" ));
+
+ m_holdFrameEnd = -1;
+
+ info->m_holding = true;
+ }
+ break;
+ }
+
+ // spin until event queue is empty *and* hold is false
+
+ int evtcount=0;
+
+ bool refresh = info->m_holding || m_debugDelayEnable; // only refresh once per initial visit (if paused!) or follow up event input
+ int breakToDebugger = 0;
+ // 1 = break to GDB
+ // 2 = break to OpenGL Profiler if attached
+
+ do
+ {
+ if (refresh)
+ {
+ if (debughook) GLMPRINTF(("-D- pushing pixels" ));
+ this->DebugPresent(); // show pixels
+
+ uint minidumpOptions = (1<DebugDump( info, minidumpOptions, g_vertDumpMode );
+
+ usleep(10000); // lil sleep
+
+ refresh = false;
+ }
+
+ bool eventCheck = true; // event pull will be skipped if we detect a shader edit being done
+ // keep editable shaders in sync
+ #if GLMDEBUG
+
+ bool redrawBatch = false;
+ if (m_drawingProgram[ kGLMVertexProgram ])
+ {
+ if( m_drawingProgram[ kGLMVertexProgram ]->SyncWithEditable() )
+ {
+ redrawBatch = true;
+ }
+ }
+
+ if (m_drawingProgram[ kGLMFragmentProgram ])
+ {
+ if( m_drawingProgram[ kGLMFragmentProgram ]->SyncWithEditable() )
+ {
+ redrawBatch = true;
+ }
+ }
+
+ if (redrawBatch)
+ {
+ // act as if user pressed the option-\ key
+
+ if (m_drawingLang == kGLMGLSL)
+ {
+ // if GLSL mode, force relink - and refresh the pair cache as needed
+ if (m_boundPair)
+ {
+ // fix it in place
+ m_boundPair->RefreshProgramPair();
+ }
+ }
+ FlushDrawStates( true ); // this is key, because the linked shader pair may have changed (note call to PurgePairsWithShader in cglmprogram.cpp)
+
+ GLMPRINTF(("-- Shader changed, re-running batch" ));
+
+ m_holdBatch = m_debugBatchIndex;
+ m_holdBatchFrame = m_debugFrameIndex;
+ m_debugDelayEnable = false;
+
+ info->m_holding = false;
+ info->m_loop = true;
+
+ eventCheck = false;
+ }
+ #endif
+
+ if(eventCheck)
+ {
+ g_extCocoaMgr->PumpWindowsMessageLoop();
+ CCocoaEvent evt;
+ evtcount = g_extCocoaMgr->GetEvents( &evt, 1, true ); // asking for debug events only.
+ if (evtcount)
+ {
+ // print it
+ if (debughook) GLMPRINTF(("-D- Received debug key '%c' with modifiers %x", evt.m_UnicodeKeyUnmodified, evt.m_ModifierKeyMask ));
+
+ // flag for refresh if we spin again
+ refresh = 1;
+
+ switch(evt.m_UnicodeKeyUnmodified)
+ {
+ case ' ': // toggle pause
+ // clear all the holds to be sure
+ m_holdFrameBegin = m_holdFrameEnd = m_holdBatch = m_holdBatchFrame = -1;
+ info->m_holding = !info->m_holding;
+
+ if (!info->m_holding)
+ {
+ m_debugDelayEnable = false; // coming out of pause means no slow mo
+ }
+
+ GLMPRINTF((info->m_holding ? "-D- Paused." : "-D- Unpaused." ));
+ break;
+
+ case 'f': // frame advance
+ GLMPRINTF(("-D- Command: next frame" ));
+ m_holdFrameBegin = m_debugFrameIndex+1; // stop at top of next numbered frame
+ m_debugDelayEnable = false; // get there fast
+
+ info->m_holding = false;
+ break;
+
+ case ']': // ahead 1 batch
+ case '}': // ahead ten batches
+ {
+ int delta = evt.m_UnicodeKeyUnmodified == ']' ? 1 : 10;
+ m_holdBatch = m_debugBatchIndex+delta;
+ m_holdBatchFrame = m_debugFrameIndex;
+ m_debugDelayEnable = false; // get there fast
+ info->m_holding = false;
+ GLMPRINTF(("-D- Command: advance %d batches to %d", delta, m_holdBatch ));
+ }
+ break;
+
+ case '[': // back one batch
+ case '{': // back 10 batches
+ {
+ int delta = evt.m_UnicodeKeyUnmodified == '[' ? -1 : -10;
+ m_holdBatch = m_debugBatchIndex + delta;
+ if (m_holdBatch<0)
+ {
+ m_holdBatch = 0;
+ }
+ m_holdBatchFrame = m_debugFrameIndex+1; // next frame, but prev batch #
+ m_debugDelayEnable = false; // get there fast
+ info->m_holding = false;
+ GLMPRINTF(("-D- Command: rewind %d batches to %d", delta, m_holdBatch ));
+ }
+ break;
+
+ case '\\': // batch rerun
+
+ m_holdBatch = m_debugBatchIndex;
+ m_holdBatchFrame = m_debugFrameIndex;
+ m_debugDelayEnable = false;
+ info->m_holding = false;
+ info->m_loop = true;
+ GLMPRINTF(("-D- Command: re-run batch %d", m_holdBatch ));
+ break;
+
+ case 'c': // toggle auto color clear
+ m_autoClearColor = !m_autoClearColor;
+ GLMPRINTF((m_autoClearColor ? "-D- Auto color clear ON" : "-D- Auto color clear OFF" ));
+ break;
+
+ case 's': // toggle auto stencil clear
+ m_autoClearStencil = !m_autoClearStencil;
+ GLMPRINTF((m_autoClearStencil ? "-D- Auto stencil clear ON" : "-D- Auto stencil clear OFF" ));
+ break;
+
+ case 'd': // toggle auto depth clear
+ m_autoClearDepth = !m_autoClearDepth;
+ GLMPRINTF((m_autoClearDepth ? "-D- Auto depth clear ON" : "-D- Auto depth clear OFF" ));
+ break;
+
+ case '.': // break to debugger or insta-quit
+ if (evt.m_ModifierKeyMask & (1<m_holding = true;
+ info->m_loop = true; // so when you come back from debugger, you get another spin (i.e. you enter paused mode)
+ }
+ break;
+
+ case 'g': // break to OGLP and enable OGLP logging of spew
+ if (GLMDetectOGLP()) // if this comes back true, there will be a breakpoint set on glColor4sv.
+ {
+ uint channelMask = GLMDetectAvailableChannels(); // will re-assert whether spew goes to OGLP log
+
+ if (channelMask & (1<m_holding = true;
+ info->m_loop = true; // so when you come back from debugger, you get another spin (i.e. you enter paused mode)
+ }
+ }
+ break;
+
+ case '_': // toggle slow mo
+ m_debugDelayEnable = !m_debugDelayEnable;
+ break;
+
+ case '-': // go slower
+ if (m_debugDelayEnable)
+ {
+ // already in slow mo, so lower speed
+ m_debugDelay <<= 1; // double delay
+ if (m_debugDelay > (1<<24))
+ {
+ m_debugDelay = (1<<24);
+ }
+ }
+ else
+ {
+ // enter slow mo
+ m_debugDelayEnable = true;
+ }
+ break;
+
+ case '=': // go faster
+ if (m_debugDelayEnable)
+ {
+ // already in slow mo, so raise speed
+ m_debugDelay >>= 1; // halve delay
+ if (m_debugDelay < (1<<17))
+ {
+ m_debugDelay = (1<<17);
+ }
+ }
+ else
+ {
+ // enter slow mo
+ m_debugDelayEnable = true;
+ }
+ break;
+
+ case 'v':
+ // open vs in editor (foreground pop)
+ #if GLMDEBUG
+ if (m_boundProgram[ kGLMVertexProgram ])
+ {
+ m_boundProgram[ kGLMVertexProgram ]->m_editable->OpenInEditor( true );
+ }
+ #endif
+ break;
+
+ case 'p':
+ // open fs/ps in editor (foreground pop)
+ #if GLMDEBUG
+ if (m_boundProgram[ kGLMFragmentProgram ])
+ {
+ m_boundProgram[ kGLMFragmentProgram ]->m_editable->OpenInEditor( true );
+ }
+ #endif
+ break;
+
+ case '<': // dump fewer verts
+ case '>': // dump more verts
+ {
+ int delta = (evt.m_UnicodeKeyUnmodified=='>') ? 1 : -1;
+ g_maxVertsToDumpLog2 = MIN( MAX( g_maxVertsToDumpLog2+delta, 0 ), 16 );
+
+ // just re-dump the verts
+ DebugDump( info, 1<= eLastDumpVertsMode)
+ {
+ // wrap
+ newmode = eDumpVertsNoTransformDump;
+ }
+ g_vertDumpMode = (EGLMVertDumpMode)newmode;
+
+ GLMPRINTF(("-D- New vert dump mode is %s", g_vertDumpModeNames[g_vertDumpMode] ));
+ }
+ break;
+
+ case 'u': // more crawl
+ {
+ CStackCrawlParams cp;
+ memset( &cp, 0, sizeof(cp) );
+ cp.m_frameLimit = kMaxCrawlFrames;
+
+ g_extCocoaMgr->GetStackCrawl(&cp);
+
+ GLMPRINTF(("-D-" ));
+ GLMPRINTF(("-D- extended stack crawl:"));
+ for( int i=0; i< cp.m_frameCount; i++)
+ {
+ GLMPRINTF(("-D-\t%s", cp.m_crawlNames[i] ));
+ }
+ }
+ break;
+
+ case 'q':
+ DebugDump( info, 0xFFFFFFFF, g_vertDumpMode );
+ break;
+
+
+ case 'H':
+ case 'h':
+ {
+ // toggle drawing language. hold down shift key to do it immediately.
+
+ if (m_caps.m_hasDualShaders)
+ {
+ bool immediate;
+
+ immediate = evt.m_UnicodeKeyUnmodified == 'H'; // (evt.m_ModifierKeyMask & (1<=0) && (flavorSelect m_selKnobMaxValue)
+ {
+ val = m_selKnobMaxValue;
+ }
+ // send new value back to the knob
+ GLMKnob( g_knobnames[ m_selKnobIndex ], &val );
+ }
+
+ if (evt.m_UnicodeKeyUnmodified == 'z')
+ {
+ // zero
+ val = 0.0f;
+
+ // send new value back to the knob
+ GLMKnob( g_knobnames[ m_selKnobIndex ], &val );
+ }
+
+ GLMPRINTF(("-D- Knob # %d (%s) set to %f (%f/1024.0)", m_selKnobIndex, g_knobnames[ m_selKnobIndex ], val, val * 1024.0 ));
+
+ usleep( 500000 );
+ refresh = false;
+ }
+ }
+ break;
+
+ }
+ }
+ }
+ } while( ((evtcount>0) || info->m_holding) && (!breakToDebugger) );
+
+ if (m_debugDelayEnable)
+ {
+ usleep( m_debugDelay );
+ }
+
+ if (breakToDebugger)
+ {
+ switch (breakToDebugger)
+ {
+ case 1:
+ Debugger();
+ break;
+
+ case 2:
+ short fakecolor[4];
+ glColor4sv( fakecolor ); // break to OGLP
+ break;
+ }
+ // re-flush all GLM states so you can fiddle with them in the debugger. then run the batch again and spin..
+ FlushStates( true );
+ }
+#endif
+}
+
+void GLMContext::DebugPresent( void )
+{
+ CGLMTex *drawBufferTex = m_drawingFBO->m_attach[kAttColor0].m_tex;
+ glFinish();
+ this->Present( drawBufferTex );
+}
+
+void GLMContext::DebugClear( void )
+{
+ // get old clear color
+ GLClearColor_t clearcol_orig;
+ m_ClearColor.Read( &clearcol_orig,0 );
+
+ // new clear color
+ GLClearColor_t clearcol;
+ clearcol.r = m_autoClearColorValues[0];
+ clearcol.g = m_autoClearColorValues[1];
+ clearcol.b = m_autoClearColorValues[2];
+ clearcol.a = m_autoClearColorValues[3];
+ m_ClearColor.Write( &clearcol, true, true ); // don't check, don't defer
+
+ uint mask = 0;
+
+ if (m_autoClearColor) mask |= GL_COLOR_BUFFER_BIT;
+ if (m_autoClearDepth) mask |= GL_DEPTH_BUFFER_BIT;
+ if (m_autoClearStencil) mask |= GL_STENCIL_BUFFER_BIT;
+
+ glClear( mask );
+ glFinish();
+
+ // put old color back
+ m_ClearColor.Write( &clearcol_orig, true, true ); // don't check, don't defer
+}
+
+#endif
+
+void GLMContext::DrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices )
+{
+ GLM_FUNC;
+
+// CheckCurrent();
+
+ m_debugBatchIndex++; // batch index increments unconditionally on entry
+
+ bool hasVP = m_boundProgram[ kGLMVertexProgram ] != NULL;
+ bool hasFP = m_boundProgram[ kGLMFragmentProgram ] != NULL;
+
+ void *indicesActual = (void*)indices;
+ if (m_drawIndexBuffer->m_pseudo)
+ {
+ // you have to pass actual address, not offset... shhh... secret
+ indicesActual = (void*)((uintptr_t)indicesActual + (uintptr_t)m_drawIndexBuffer->m_pseudoBuf);
+ }
+
+#if GLMDEBUG
+ // init debug hook information
+ GLMDebugHookInfo info;
+ memset( &info, 0, sizeof(info) );
+ info.m_caller = eDrawElements;
+
+ // relay parameters we're operating under
+ info.m_drawMode = mode;
+ info.m_drawStart = start;
+ info.m_drawEnd = end;
+ info.m_drawCount = count;
+ info.m_drawType = type;
+ info.m_drawIndices = indices;
+
+ do
+ {
+ // obey global options re pre-draw clear
+ if (m_autoClearColor || m_autoClearDepth || m_autoClearStencil)
+ {
+ GLMPRINTF(("-- DrawRangeElements auto clear" ));
+ this->DebugClear();
+ }
+
+ // always sync with editable shader text prior to draw
+ #if GLMDEBUG
+ //FIXME disengage this path if context is in GLSL mode..
+ // it will need fixes to get the shader pair re-linked etc if edits happen anyway.
+
+ if (m_boundProgram[ kGLMVertexProgram ])
+ {
+ m_boundProgram[ kGLMVertexProgram ]->SyncWithEditable();
+ }
+ else
+ {
+ //AssertOnce(!"drawing with no vertex program bound");
+ }
+
+
+ if (m_boundProgram[ kGLMFragmentProgram ])
+ {
+ m_boundProgram[ kGLMFragmentProgram ]->SyncWithEditable();
+ }
+ else
+ {
+ //AssertOnce(!"drawing with no fragment program bound");
+ }
+ #endif
+
+ // do the drawing
+ if (hasVP && hasFP)
+ {
+ glDrawRangeElements( mode, start, end, count, type, indicesActual );
+ GLMCheckError();
+
+ if (m_slowCheckEnable)
+ {
+ CheckNative();
+ }
+ }
+ this->DebugHook( &info );
+ } while (info.m_loop);
+#else
+ if (hasVP && hasFP)
+ {
+ glDrawRangeElements( mode, start, end, count, type, indicesActual );
+ GLMCheckError();
+
+ if (m_slowCheckEnable)
+ {
+ CheckNative();
+ }
+ }
+#endif
+}
+
+void GLMContext::DrawArrays( GLenum mode, GLuint first, GLuint count )
+{
+ GLM_FUNC;
+
+ m_debugBatchIndex++; // batch index increments unconditionally on entry
+
+ bool hasVP = m_boundProgram[ kGLMVertexProgram ] != NULL;
+ bool hasFP = m_boundProgram[ kGLMFragmentProgram ] != NULL;
+
+ // note that the GLMDEBUG path is not wired up here yet
+ if (hasVP && hasFP)
+ {
+ #if GLMDEBUG && 0
+ // init debug hook information
+ GLMDebugHookInfo info;
+ memset( &info, 0, sizeof(info) );
+ info.m_caller = eDrawArrays;
+
+ // relay parameters we're operating under
+ info.m_drawMode = mode;
+ info.m_drawStart = first;
+ info.m_drawEnd = first+count;
+ info.m_drawCount = count;
+ info.m_drawType = 0; // no one was using this anyway..
+ info.m_drawIndices = NULL;
+
+ glDrawArrays(mode, first, count);
+ GLMCheckError();
+
+ DebugDump( &info, 0xFFFFFFFF, g_vertDumpMode );
+ #else
+ glDrawArrays(mode, first, count);
+ GLMCheckError();
+ #endif
+
+ if (m_slowCheckEnable)
+ {
+ CheckNative();
+ }
+ }
+}
+
+void GLMContext::CheckNative( void )
+{
+ // note that this is available in release. We don't use GLMPRINTF for that reason.
+ // note we do not get called unless either slow-batch asserting or logging is enabled.
+
+ bool gpuProcessing;
+ GLint fragmentGPUProcessing, vertexGPUProcessing;
+
+ CGLGetParameter (CGLGetCurrentContext(), kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
+ CGLGetParameter(CGLGetCurrentContext(), kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
+
+ // spews then asserts.
+ // that way you can enable both, get log output on a pair if it's slow, and then the debugger will pop.
+ if(m_slowSpewEnable)
+ {
+ if ( !vertexGPUProcessing )
+ {
+ m_boundProgram[ kGLMVertexProgram ]->LogSlow( m_drawingLang );
+ }
+ if ( !fragmentGPUProcessing )
+ {
+ m_boundProgram[ kGLMFragmentProgram ]->LogSlow( m_drawingLang );
+ }
+ }
+
+ if(m_slowAssertEnable)
+ {
+ if ( !vertexGPUProcessing || !fragmentGPUProcessing)
+ {
+ Assert( !"slow batch" );
+ }
+ }
+}
+
+
+
+// debug font
+void GLMContext::GenDebugFontTex( void )
+{
+ if(!m_debugFontTex)
+ {
+ // make a 128x128 RGBA texture
+ GLMTexLayoutKey key;
+ memset( &key, 0, sizeof(key) );
+
+ key.m_texGLTarget = GL_TEXTURE_2D;
+ key.m_xSize = 128;
+ key.m_ySize = 128;
+ key.m_zSize = 1;
+ key.m_texFormat = D3DFMT_A8R8G8B8;
+ key.m_texFlags = 0;
+
+ m_debugFontTex = this->NewTex( &key, "GLM debug font" );
+
+
+ //-----------------------------------------------------
+ GLMTexLockParams lockreq;
+
+ lockreq.m_tex = m_debugFontTex;
+ lockreq.m_face = 0;
+ lockreq.m_mip = 0;
+
+ GLMTexLayoutSlice *slice = &m_debugFontTex->m_layout->m_slices[ lockreq.m_tex->CalcSliceIndex( lockreq.m_face, lockreq.m_mip ) ];
+
+ lockreq.m_region.xmin = lockreq.m_region.ymin = lockreq.m_region.zmin = 0;
+ lockreq.m_region.xmax = slice->m_xSize;
+ lockreq.m_region.ymax = slice->m_ySize;
+ lockreq.m_region.zmax = slice->m_zSize;
+
+ char *lockAddress;
+ int yStride;
+ int zStride;
+
+ m_debugFontTex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
+ GLMCheckError();
+
+ //-----------------------------------------------------
+ // fetch elements of font data and make texels... we're doing the whole slab so we don't really need the stride info
+ unsigned long *destTexelPtr = (unsigned long *)lockAddress;
+
+ for( int index = 0; index < 16384; index++ )
+ {
+ if (g_glmDebugFontMap[index] == ' ')
+ {
+ // clear
+ *destTexelPtr = 0x00000000;
+ }
+ else
+ {
+ // opaque white (drawing code can modulate if desired)
+ *destTexelPtr = 0xFFFFFFFF;
+ }
+ destTexelPtr++;
+ }
+
+ //-----------------------------------------------------
+ GLMTexLockParams unlockreq;
+
+ unlockreq.m_tex = m_debugFontTex;
+ unlockreq.m_face = 0;
+ unlockreq.m_mip = 0;
+
+ // region need not matter for unlocks
+ unlockreq.m_region.xmin = unlockreq.m_region.ymin = unlockreq.m_region.zmin = 0;
+ unlockreq.m_region.xmax = unlockreq.m_region.ymax = unlockreq.m_region.zmax = 0;
+
+ m_debugFontTex->Unlock( &unlockreq );
+ GLMCheckError();
+
+ //-----------------------------------------------------
+ // change up the tex sampling on this texture to be "nearest" not linear
+
+ //-----------------------------------------------------
+
+ // don't leave texture bound on the TMU
+ this->BindTexToTMU(NULL, 0 );
+
+ // also make the index and vertex buffers for use - up to 1K indices and 1K verts
+
+ uint indexBufferSize = 1024*2;
+
+ m_debugFontIndices = this->NewBuffer(kGLMIndexBuffer, indexBufferSize, 0); // two byte indices
+
+ // we go ahead and lock it now, and fill it with indices 0-1023.
+ char *indices = NULL;
+ GLMBuffLockParams idxLock;
+ idxLock.m_offset = 0;
+ idxLock.m_size = indexBufferSize;
+ idxLock.m_nonblocking = false;
+ idxLock.m_discard = false;
+ m_debugFontIndices->Lock( &idxLock, &indices );
+ for( int i=0; i<1024; i++)
+ {
+ unsigned short *idxPtr = &((unsigned short*)indices)[i];
+ *idxPtr = i;
+ }
+ m_debugFontIndices->Unlock();
+
+ m_debugFontVertices = this->NewBuffer(kGLMVertexBuffer, 1024 * 128, 0); // up to 128 bytes per vert
+ }
+}
+
+#define MAX_DEBUG_CHARS 256
+struct GLMDebugTextVertex
+{
+ float x,y,z;
+ float u,v;
+ char rgba[4];
+};
+
+void GLMContext::DrawDebugText( float x, float y, float z, float drawCharWidth, float drawCharHeight, char *string )
+{
+ if (!m_debugFontTex)
+ {
+ GenDebugFontTex();
+ }
+
+ // setup needed to draw text
+
+ // we're assuming that +x goes left to right on screen, no billboarding math in here
+ // and that +y goes bottom up
+ // caller knows projection / rectangle so it gets to decide vertex spacing
+
+ // debug font must be bound to TMU 0
+ // texturing enabled
+ // alpha blending enabled
+ // generate a quad per character
+ // characters are 6px wide by 11 px high.
+ // upper left character in tex is 0x20
+ // y axis will need to be flipped for display
+
+ // for any character in 0x20 - 0x7F - here are the needed UV's
+
+ // leftU = ((character % 16) * 6.0f / 128.0f)
+ // rightU = lowU + (6.0 / 128.0);
+ // topV = ((character - 0x20) * 11.0f / 128.0f)
+ // bottomV = lowV + (11.0f / 128.0f)
+
+ int stringlen = strlen( string );
+ if (stringlen > MAX_DEBUG_CHARS)
+ {
+ stringlen = MAX_DEBUG_CHARS;
+ }
+
+ // lock
+ char *vertices = NULL;
+ GLMBuffLockParams vtxLock;
+ vtxLock.m_offset = 0;
+ vtxLock.m_size = 1024 * stringlen;
+ vtxLock.m_nonblocking = false;
+ vtxLock.m_discard = false;
+ m_debugFontVertices->Lock( &vtxLock, &vertices );
+
+ GLMDebugTextVertex *vtx = (GLMDebugTextVertex*)vertices;
+ GLMDebugTextVertex *vtxOutPtr = vtx;
+
+ for( int charindex = 0; charindex < stringlen; charindex++ )
+ {
+ float leftU,rightU,topV,bottomV;
+
+ int character = (int)string[charindex];
+ character -= 0x20;
+ if ( (character<0) || (character > 0x7F) )
+ {
+ character = '*' - 0x20;
+ }
+
+ leftU = ((character & 0x0F) * 6.0f ) / 128.0f;
+ rightU = leftU + (6.0f / 128.0f);
+
+ topV = ((character >> 4) * 11.0f ) / 128.0f;
+ bottomV = topV + (11.0f / 128.0f);
+
+ float posx,posy,posz;
+
+ posx = x + (drawCharWidth * (float)charindex);
+ posy = y;
+ posz = z;
+
+ // generate four verts
+ // first vert will be upper left of displayed quad (low X, high Y) then we go clockwise
+ for( int quadvert = 0; quadvert < 4; quadvert++ )
+ {
+ bool isTop = (quadvert <2); // verts 0 and 1
+ bool isLeft = (quadvert & 1) == (quadvert >> 1); // verts 0 and 3
+
+ vtxOutPtr->x = posx + (isLeft ? 0.0f : drawCharWidth);
+ vtxOutPtr->y = posy + (isTop ? drawCharHeight : 0.0f);
+ vtxOutPtr->z = posz;
+
+ vtxOutPtr->u = isLeft ? leftU : rightU;
+ vtxOutPtr->v = isTop ? topV : bottomV;
+
+ vtxOutPtr++;
+ }
+ }
+
+ // verts are done.
+ // unlock...
+
+ m_debugFontVertices->Unlock();
+
+ // make a vertex setup
+ GLMVertexSetup vertSetup;
+
+ // position, color, tc = 0, 3, 8
+ vertSetup.m_attrMask = (1<BindTexToTMU( m_debugFontTex, 0 );
+
+ SelectTMU(0); // somewhat redundant
+
+ glDisable( GL_DEPTH_TEST );
+
+ glEnable(GL_TEXTURE_2D);
+ GLMCheckError();
+
+ if (0)
+ {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ GLMCheckError();
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ GLMCheckError();
+
+ glVertexPointer( 3, GL_FLOAT, sizeof( vtx[0] ), &vtx[0].x );
+ GLMCheckError();
+
+ glClientActiveTexture(GL_TEXTURE0);
+ GLMCheckError();
+
+ glTexCoordPointer( 2, GL_FLOAT, sizeof( vtx[0] ), &vtx[0].u );
+ GLMCheckError();
+ }
+ else
+ {
+ SetVertexAttributes( &vertSetup );
+ }
+
+ glDrawArrays( GL_QUADS, 0, stringlen * 4 );
+ GLMCheckError();
+
+ // disable all the input streams
+ if (0)
+ {
+ glDisableClientState(GL_VERTEX_ARRAY);
+ GLMCheckError();
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ GLMCheckError();
+ }
+ else
+ {
+ SetVertexAttributes( NULL );
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ GLMCheckError();
+
+ this->BindTexToTMU( NULL, 0 );
+}
+
+
+
+//===============================================================================
+
+void GLMgrSelfTests( void )
+{
+ return; // until such time as the tests are revised or axed
+
+ // make a new context on renderer 0.
+ GLMContext *ctx = GLMgr::aGLMgr()->NewContext( 0 ); ////FIXME you can't make contexts this way any more.
+ if (!ctx)
+ {
+ Debugger(); // no go
+ return;
+ }
+
+ // make a test object based on that context.
+ int alltests[] = {0,1,2,3, -1};
+ int newtests[] = {3, -1};
+ int notests[] = {-1};
+
+ int *testlist = notests;
+
+ GLMTestParams params;
+ memset( ¶ms, 0, sizeof(params) );
+
+ params.m_ctx = ctx;
+ params.m_testList = testlist;
+
+ params.m_glErrToDebugger = true;
+ params.m_glErrToConsole = true;
+
+ params.m_intlErrToDebugger = true;
+ params.m_intlErrToConsole = true;
+
+ params.m_frameCount = 1000;
+
+ GLMTester testobj( ¶ms );
+
+ testobj.RunTests( );
+
+ GLMgr::aGLMgr()->DelContext( ctx );
+}
+
+void GLMContext::SetDefaultStates( void )
+{
+ GLM_FUNC;
+ CheckCurrent();
+
+ m_AlphaTestEnable.Default();
+ m_AlphaTestFunc.Default();
+
+ m_AlphaToCoverageEnable.Default();
+
+ m_CullFaceEnable.Default();
+ m_CullFrontFace.Default();
+
+ m_PolygonMode.Default();
+ m_DepthBias.Default();
+
+ m_ClipPlaneEnable.Default();
+ m_ClipPlaneEquation.Default();
+
+ m_ScissorEnable.Default();
+ m_ScissorBox.Default();
+
+ m_ViewportBox.Default();
+ m_ViewportDepthRange.Default();
+
+ m_ColorMaskSingle.Default();
+ m_ColorMaskMultiple.Default();
+
+ m_BlendEnable.Default();
+ m_BlendFactor.Default();
+ m_BlendEquation.Default();
+ m_BlendColor.Default();
+ //m_BlendEnableSRGB.Default(); // this isn't useful until there is an FBO bound - in fact it will trip a GL error.
+
+ m_DepthTestEnable.Default();
+ m_DepthFunc.Default();
+ m_DepthMask.Default();
+
+ m_StencilTestEnable.Default();
+ m_StencilFunc.Default();
+ m_StencilOp.Default();
+ m_StencilWriteMask.Default();
+
+ m_ClearColor.Default();
+ m_ClearDepth.Default();
+ m_ClearStencil.Default();
+}
+
+void GLMContext::FlushStates( bool noDefer )
+{
+ GLM_FUNC;
+ CheckCurrent();
+
+ m_AlphaTestEnable.Flush( noDefer );
+ m_AlphaTestFunc.Flush( noDefer );
+
+ m_AlphaToCoverageEnable.Flush( noDefer );
+
+ m_CullFaceEnable.Flush( noDefer );
+ m_CullFrontFace.Flush( noDefer );
+
+ m_PolygonMode.Flush( noDefer );
+ m_DepthBias.Flush( noDefer );
+
+ #if GLMDEBUG
+ m_ClipPlaneEnable.Flush( true ); // always push clip state
+ m_ClipPlaneEquation.Flush( true );
+ #else
+ m_ClipPlaneEnable.Flush( noDefer );
+ m_ClipPlaneEquation.Flush( noDefer );
+ #endif
+
+
+ m_ScissorEnable.Flush( noDefer );
+ m_ScissorBox.Flush( noDefer );
+
+ m_ViewportBox.Flush( noDefer );
+ m_ViewportDepthRange.Flush( noDefer );
+
+ m_ColorMaskSingle.Flush( noDefer );
+ m_ColorMaskMultiple.Flush( noDefer );
+
+ m_BlendEnable.Flush( noDefer );
+ m_BlendFactor.Flush( noDefer );
+ m_BlendEquation.Flush( noDefer );
+ m_BlendColor.Flush( noDefer );
+
+ // the next call should not occur until we're sure the proper SRGB tex format is underneath the FBO.
+ // So, we're moving it up to FlushDrawStates so it can happen at just the right time.
+ //m_BlendEnableSRGB.Flush( noDefer );
+
+ m_DepthTestEnable.Flush( noDefer );
+ m_DepthFunc.Flush( noDefer );
+ m_DepthMask.Flush( noDefer );
+
+ m_StencilTestEnable.Flush( noDefer );
+ m_StencilFunc.Flush( noDefer );
+ m_StencilOp.Flush( noDefer );
+ m_StencilWriteMask.Flush( noDefer );
+
+ m_ClearColor.Flush( noDefer );
+ m_ClearDepth.Flush( noDefer );
+ m_ClearStencil.Flush( noDefer );
+
+ GLMCheckError();
+}
+
+void GLMContext::VerifyStates ( void )
+{
+ GLM_FUNC;
+ CheckCurrent();
+
+ // bare bones sanity check, head over to the debugger if our sense of the current context state is not correct
+ // we should only want to call this after a flush or the checks will flunk.
+
+ if( m_AlphaTestEnable.Check() ) GLMStop();
+ if( m_AlphaTestFunc.Check() ) GLMStop();
+
+ if( m_AlphaToCoverageEnable.Check() ) GLMStop();
+
+ if( m_CullFaceEnable.Check() ) GLMStop();
+ if( m_CullFrontFace.Check() ) GLMStop();
+
+ if( m_PolygonMode.Check() ) GLMStop();
+ if( m_DepthBias.Check() ) GLMStop();
+
+ if( m_ClipPlaneEnable.Check() ) GLMStop();
+ //if( m_ClipPlaneEquation.Check() ) GLMStop();
+
+ if( m_ScissorEnable.Check() ) GLMStop();
+ if( m_ScissorBox.Check() ) GLMStop();
+
+
+ if( m_ViewportBox.Check() ) GLMStop();
+ if( m_ViewportDepthRange.Check() ) GLMStop();
+
+ if( m_ColorMaskSingle.Check() ) GLMStop();
+ if( m_ColorMaskMultiple.Check() ) GLMStop();
+
+ if( m_BlendEnable.Check() ) GLMStop();
+ if( m_BlendFactor.Check() ) GLMStop();
+ if( m_BlendEquation.Check() ) GLMStop();
+ if( m_BlendColor.Check() ) GLMStop();
+
+ // only do this as caps permit
+ if (m_caps.m_hasGammaWrites)
+ {
+ if( m_BlendEnableSRGB.Check() ) GLMStop();
+ }
+
+ if( m_DepthTestEnable.Check() ) GLMStop();
+ if( m_DepthFunc.Check() ) GLMStop();
+ if( m_DepthMask.Check() ) GLMStop();
+
+ if( m_StencilTestEnable.Check() ) GLMStop();
+ if( m_StencilFunc.Check() ) GLMStop();
+ if( m_StencilOp.Check() ) GLMStop();
+ if( m_StencilWriteMask.Check() ) GLMStop();
+
+ if( m_ClearColor.Check() ) GLMStop();
+ if( m_ClearDepth.Check() ) GLMStop();
+ if( m_ClearStencil.Check() ) GLMStop();
+}
+
+void GLMContext::WriteAlphaTestEnable( GLAlphaTestEnable_t *src )
+{
+ m_AlphaTestEnable.Write( src );
+}
+
+void GLMContext::WriteAlphaTestFunc( GLAlphaTestFunc_t *src )
+{
+ m_AlphaTestFunc.Write( src );
+}
+
+void GLMContext::WriteAlphaToCoverageEnable( GLAlphaToCoverageEnable_t *src )
+{
+ m_AlphaToCoverageEnable.Write( src );
+}
+
+void GLMContext::WriteCullFaceEnable( GLCullFaceEnable_t *src )
+{
+ m_CullFaceEnable.Write( src );
+}
+
+void GLMContext::WriteCullFrontFace( GLCullFrontFace_t *src )
+{
+ m_CullFrontFace.Write( src );
+}
+
+void GLMContext::WritePolygonMode( GLPolygonMode_t *src )
+{
+ m_PolygonMode.Write( src );
+}
+
+void GLMContext::WriteDepthBias( GLDepthBias_t *src )
+{
+ m_DepthBias.Write( src );
+}
+
+void GLMContext::WriteClipPlaneEnable( GLClipPlaneEnable_t *src, int which )
+{
+ m_ClipPlaneEnable.WriteIndex( src, which );
+}
+
+void GLMContext::WriteClipPlaneEquation( GLClipPlaneEquation_t *src, int which )
+{
+ m_ClipPlaneEquation.WriteIndex( src, which );
+}
+
+void GLMContext::WriteScissorEnable( GLScissorEnable_t *src )
+{
+ m_ScissorEnable.Write( src );
+}
+
+void GLMContext::WriteScissorBox( GLScissorBox_t *src )
+{
+ m_ScissorBox.Write( src );
+}
+
+void GLMContext::WriteViewportBox( GLViewportBox_t *src )
+{
+ m_ViewportBox.Write( src );
+}
+
+void GLMContext::WriteViewportDepthRange( GLViewportDepthRange_t *src )
+{
+ m_ViewportDepthRange.Write( src );
+}
+
+void GLMContext::WriteColorMaskSingle( GLColorMaskSingle_t *src )
+{
+ m_ColorMaskSingle.Write( src );
+}
+
+void GLMContext::WriteColorMaskMultiple( GLColorMaskMultiple_t *src, int which )
+{
+ m_ColorMaskMultiple.WriteIndex( src, which );
+}
+
+void GLMContext::WriteBlendEnable( GLBlendEnable_t *src )
+{
+ m_BlendEnable.Write( src );
+}
+
+void GLMContext::WriteBlendFactor( GLBlendFactor_t *src )
+{
+ m_BlendFactor.Write( src );
+}
+
+void GLMContext::WriteBlendEquation( GLBlendEquation_t *src )
+{
+ m_BlendEquation.Write( src );
+}
+
+void GLMContext::WriteBlendColor( GLBlendColor_t *src )
+{
+ m_BlendColor.Write( src );
+}
+
+void GLMContext::WriteBlendEnableSRGB( GLBlendEnableSRGB_t *src )
+{
+ if (m_caps.m_hasGammaWrites) // only if caps allow do we actually push it through to the extension
+ {
+ m_BlendEnableSRGB.Write( src );
+ }
+ else
+ {
+ m_FakeBlendEnableSRGB = src->enable;
+ }
+ // note however that we're still tracking what this mode should be, so FlushDrawStates can look at it and adjust the pixel shader
+ // if fake SRGB mode is in place (m_caps.m_hasGammaWrites is false)
+}
+
+void GLMContext::WriteDepthTestEnable( GLDepthTestEnable_t *src )
+{
+ m_DepthTestEnable.Write( src );
+}
+
+void GLMContext::WriteDepthFunc( GLDepthFunc_t *src )
+{
+ m_DepthFunc.Write( src );
+}
+
+void GLMContext::WriteDepthMask( GLDepthMask_t *src )
+{
+ m_DepthMask.Write( src );
+}
+
+void GLMContext::WriteStencilTestEnable( GLStencilTestEnable_t *src )
+{
+ m_StencilTestEnable.Write( src );
+}
+
+void GLMContext::WriteStencilFunc( GLStencilFunc_t *src )
+{
+ m_StencilFunc.Write( src );
+}
+
+void GLMContext::WriteStencilOp( GLStencilOp_t *src, int which )
+{
+ m_StencilOp.WriteIndex( src, which );
+}
+
+void GLMContext::WriteStencilWriteMask( GLStencilWriteMask_t *src )
+{
+ m_StencilWriteMask.Write( src );
+}
+
+void GLMContext::WriteClearColor( GLClearColor_t *src )
+{
+ m_ClearColor.Write( src );
+}
+
+void GLMContext::WriteClearDepth( GLClearDepth_t *src )
+{
+ m_ClearDepth.Write( src );
+}
+
+void GLMContext::WriteClearStencil( GLClearStencil_t *src )
+{
+ m_ClearStencil.Write( src );
+}
+
+//===============================================================================
+// template specializations for each type of state
+
+
+// --- GLAlphaTestEnable ---
+void GLContextSet( GLAlphaTestEnable_t *src )
+{
+ glSetEnable( GL_ALPHA_TEST, src->enable );
+}
+
+void GLContextGet( GLAlphaTestEnable_t *dst )
+{
+ dst->enable = glIsEnabled( GL_ALPHA_TEST );
+}
+
+void GLContextGetDefault( GLAlphaTestEnable_t *dst )
+{
+ dst->enable = GL_FALSE;
+}
+
+// --- GLAlphaTestFunc ---
+void GLContextSet( GLAlphaTestFunc_t *src )
+{
+ glAlphaFunc( src->func, src->ref );
+}
+
+void GLContextGet( GLAlphaTestFunc_t *dst )
+{
+ glGetEnumv( GL_ALPHA_TEST_FUNC, &dst->func );
+ glGetFloatv( GL_ALPHA_TEST_REF, &dst->ref );
+}
+
+void GLContextGetDefault( GLAlphaTestFunc_t *dst )
+{
+ dst->func = GL_ALWAYS;
+ dst->ref = 0.0f;
+}
+
+// --- GLAlphaToCoverageEnable ---
+void GLContextSet( GLAlphaToCoverageEnable_t *src )
+{
+ glSetEnable( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, src->enable );
+}
+
+void GLContextGet( GLAlphaToCoverageEnable_t *dst )
+{
+ dst->enable = glIsEnabled( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB );
+}
+
+void GLContextGetDefault( GLAlphaToCoverageEnable_t *dst )
+{
+ dst->enable = GL_FALSE;
+}
+
+// --- GLCullFaceEnable ---
+void GLContextSet( GLCullFaceEnable_t *src )
+{
+ glSetEnable( GL_CULL_FACE, src->enable );
+}
+
+void GLContextGet( GLCullFaceEnable_t *dst )
+{
+ dst->enable = glIsEnabled( GL_CULL_FACE );
+}
+
+void GLContextGetDefault( GLCullFaceEnable_t *dst )
+{
+ dst->enable = GL_TRUE;
+}
+
+
+// --- GLCullFrontFace ---
+void GLContextSet( GLCullFrontFace_t *src )
+{
+ glFrontFace( src->value ); // legal values are GL_CW or GL_CCW
+}
+
+void GLContextGet( GLCullFrontFace_t *dst )
+{
+ glGetEnumv( GL_FRONT_FACE, &dst->value );
+}
+
+void GLContextGetDefault( GLCullFrontFace_t *dst )
+{
+ dst->value = GL_CCW;
+}
+
+
+// --- GLPolygonMode ---
+void GLContextSet( GLPolygonMode_t *src )
+{
+ glPolygonMode( GL_FRONT, src->values[0] );
+ glPolygonMode( GL_BACK, src->values[1] );
+}
+
+void GLContextGet( GLPolygonMode_t *dst )
+{
+ glGetEnumv( GL_POLYGON_MODE, &dst->values[0] );
+
+}
+
+void GLContextGetDefault( GLPolygonMode_t *dst )
+{
+ dst->values[0] = dst->values[1] = GL_FILL;
+}
+
+
+// --- GLDepthBias ---
+// note the implicit enable / disable.
+// if you set non zero values, it is enabled, otherwise not.
+void GLContextSet( GLDepthBias_t *src )
+{
+ bool enable = (src->factor != 0.0f) || (src->units != 0.0f);
+
+ glSetEnable( GL_POLYGON_OFFSET_FILL, enable );
+ glPolygonOffset( src->factor, src->units );
+}
+
+void GLContextGet( GLDepthBias_t *dst )
+{
+ glGetFloatv ( GL_POLYGON_OFFSET_FACTOR, &dst->factor );
+ glGetFloatv ( GL_POLYGON_OFFSET_UNITS, &dst->units );
+}
+
+void GLContextGetDefault( GLDepthBias_t *dst )
+{
+ dst->factor = 0.0;
+ dst->units = 0.0;
+}
+
+
+// --- GLScissorEnable ---
+void GLContextSet( GLScissorEnable_t *src )
+{
+ glSetEnable( GL_SCISSOR_TEST, src->enable );
+}
+
+void GLContextGet( GLScissorEnable_t *dst )
+{
+ dst->enable = glIsEnabled( GL_SCISSOR_TEST );
+}
+
+void GLContextGetDefault( GLScissorEnable_t *dst )
+{
+ dst->enable = GL_FALSE;
+}
+
+
+// --- GLScissorBox ---
+void GLContextSet( GLScissorBox_t *src )
+{
+ glScissor ( src->x, src->y, src->width, src->height );
+}
+
+void GLContextGet( GLScissorBox_t *dst )
+{
+ glGetIntegerv ( GL_SCISSOR_BOX, &dst->x );
+}
+
+void GLContextGetDefault( GLScissorBox_t *dst )
+{
+ // hmmmm, good question? we can't really know a good answer so we pick a silly one
+ // and the client better come back with a better answer later.
+ dst->x = dst->y = 0;
+ dst->width = dst->height = 16;
+}
+
+
+// --- GLViewportBox ---
+
+void GLContextSet( GLViewportBox_t *src )
+{
+ glViewport (src->x, src->y, src->width, src->height );
+}
+
+void GLContextGet( GLViewportBox_t *dst )
+{
+ glGetIntegerv ( GL_VIEWPORT, &dst->x );
+}
+
+void GLContextGetDefault( GLViewportBox_t *dst )
+{
+ // as with the scissor box, we don't know yet, so pick a silly one and change it later
+ dst->x = dst->y = 0;
+ dst->width = dst->height = 16;
+}
+
+
+// --- GLViewportDepthRange ---
+void GLContextSet( GLViewportDepthRange_t *src )
+{
+ glDepthRange ( src->near, src->far );
+}
+
+void GLContextGet( GLViewportDepthRange_t *dst )
+{
+ glGetDoublev ( GL_DEPTH_RANGE, &dst->near );
+}
+
+void GLContextGetDefault( GLViewportDepthRange_t *dst )
+{
+ dst->near = 0.0;
+ dst->far = 1.0;
+}
+
+// --- GLClipPlaneEnable ---
+void GLContextSetIndexed( GLClipPlaneEnable_t *src, int index )
+{
+ #if 0 // disabled for sample GLMDEBUG
+ if (0 /*CommandLine()->FindParm("-caps_noclipplanes")*/)
+ {
+ if (GLMKnob("caps-key",NULL) > 0.0)
+ {
+ // caps ON means NO clipping
+ src->enable = false;
+ }
+ }
+ #endif
+ glSetEnable( GL_CLIP_PLANE0 + index, src->enable );
+ GLMCheckError();
+}
+
+void GLContextGetIndexed( GLClipPlaneEnable_t *dst, int index )
+{
+ dst->enable = glIsEnabled( GL_CLIP_PLANE0 + index );
+}
+
+void GLContextGetDefaultIndexed( GLClipPlaneEnable_t *dst, int index )
+{
+ dst->enable = 0;
+}
+
+
+
+// --- GLClipPlaneEquation ---
+void GLContextSetIndexed( GLClipPlaneEquation_t *src, int index )
+{
+ // shove into glGlipPlane
+ GLdouble coeffs[4] = { src->x, src->y, src->z, src->w };
+
+ glClipPlane( GL_CLIP_PLANE0 + index, coeffs );
+ GLMCheckError();
+}
+
+void GLContextGetIndexed( GLClipPlaneEquation_t *dst, int index )
+{
+ Debugger(); // do this later
+// glClipPlane( GL_CLIP_PLANE0 + index, coeffs );
+// GLdouble coeffs[4] = { src->x, src->y, src->z, src->w };
+}
+
+void GLContextGetDefaultIndexed( GLClipPlaneEquation_t *dst, int index )
+{
+ dst->x = 1.0;
+ dst->y = 0.0;
+ dst->z = 0.0;
+ dst->w = 0.0;
+}
+
+
+// --- GLColorMaskSingle ---
+void GLContextSet( GLColorMaskSingle_t *src )
+{
+ glColorMask( src->r, src->g, src->b, src->a );
+}
+
+void GLContextGet( GLColorMaskSingle_t *dst )
+{
+ glGetBooleanv( GL_COLOR_WRITEMASK, (GLboolean*)&dst->r);
+}
+
+void GLContextGetDefault( GLColorMaskSingle_t *dst )
+{
+ dst->r = dst->g = dst->b = dst->a = 1;
+}
+
+
+// --- GLColorMaskMultiple ---
+void GLContextSetIndexed( GLColorMaskMultiple_t *src, int index )
+{
+ // FIXME: this call is not in the Leopard headers. A runtime-lookup will be needed.
+ pfnglColorMaskIndexedEXT ( index, src->r, src->g, src->b, src->a );
+}
+
+void GLContextGetIndexed( GLColorMaskMultiple_t *dst, int index )
+{
+ // FIXME: this call is not in the Leopard headers. A runtime-lookup will be needed.
+ glGetBooleanIndexedvEXT ( GL_COLOR_WRITEMASK, index, (GLboolean*)&dst->r );
+}
+
+void GLContextGetDefaultIndexed( GLColorMaskMultiple_t *dst, int index )
+{
+ dst->r = dst->g = dst->b = dst->a = 1;
+}
+
+
+// --- GLBlendEnable ---
+void GLContextSet( GLBlendEnable_t *src )
+{
+ glSetEnable( GL_BLEND, src->enable );
+}
+
+void GLContextGet( GLBlendEnable_t *dst )
+{
+ dst->enable = glIsEnabled( GL_BLEND );
+}
+
+void GLContextGetDefault( GLBlendEnable_t *dst )
+{
+ dst->enable = GL_FALSE;
+}
+
+
+// --- GLBlendFactor ---
+void GLContextSet( GLBlendFactor_t *src )
+{
+ glBlendFunc ( src->srcfactor, src->dstfactor );
+}
+
+void GLContextGet( GLBlendFactor_t *dst )
+{
+ glGetEnumv ( GL_BLEND_SRC, &dst->srcfactor );
+ glGetEnumv ( GL_BLEND_DST, &dst->dstfactor );
+}
+
+void GLContextGetDefault( GLBlendFactor_t *dst )
+{
+ dst->srcfactor = GL_ONE;
+ dst->dstfactor = GL_ZERO;
+}
+
+
+// --- GLBlendEquation ---
+void GLContextSet( GLBlendEquation_t *src )
+{
+ glBlendEquation ( src->equation );
+}
+
+void GLContextGet( GLBlendEquation_t *dst )
+{
+ glGetEnumv ( GL_BLEND_EQUATION, &dst->equation );
+}
+
+void GLContextGetDefault( GLBlendEquation_t *dst )
+{
+ dst->equation = GL_FUNC_ADD;
+}
+
+
+// --- GLBlendColor ---
+void GLContextSet( GLBlendColor_t *src )
+{
+ glBlendColor ( src->r, src->g, src->b, src->a );
+}
+
+void GLContextGet( GLBlendColor_t *dst )
+{
+ glGetFloatv ( GL_BLEND_COLOR, &dst->r );
+}
+
+void GLContextGetDefault( GLBlendColor_t *dst )
+{
+ //solid white
+ dst->r = dst->g = dst->b = dst->a = 1.0;
+}
+
+
+// --- GLBlendEnableSRGB ---
+
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+
+void GLContextSet( GLBlendEnableSRGB_t *src )
+{
+ #if GLMDEBUG
+ // just check in debug... this is too expensive to look at on MTGL
+ if (src->enable)
+ {
+ GLboolean srgb_capable = false;
+ glGetBooleanv( GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgb_capable);
+
+ if (src->enable && !srgb_capable)
+ {
+ GLMPRINTF(("-Z- srgb-state-set FBO conflict: attempt to enable SRGB on non SRGB capable FBO config"));
+ }
+ }
+ #endif
+ // this query is not useful unless you have the ARB_framebuffer_srgb ext.
+ //GLint encoding = 0;
+ //pfnglGetFramebufferAttachmentParameteriv( GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &encoding );
+ //GLMCheckError();
+
+ glSetEnable( GL_FRAMEBUFFER_SRGB_EXT, src->enable );
+ GLMCheckError();
+}
+
+void GLContextGet( GLBlendEnableSRGB_t *dst )
+{
+ //dst->enable = glIsEnabled( GL_FRAMEBUFFER_SRGB_EXT );
+ dst->enable = true; // wtf ?
+}
+
+void GLContextGetDefault( GLBlendEnableSRGB_t *dst )
+{
+ dst->enable = GL_FALSE;
+}
+
+
+// --- GLDepthTestEnable ---
+void GLContextSet( GLDepthTestEnable_t *src )
+{
+ glSetEnable( GL_DEPTH_TEST, src->enable );
+}
+
+void GLContextGet( GLDepthTestEnable_t *dst )
+{
+ dst->enable = glIsEnabled( GL_DEPTH_TEST );
+}
+
+void GLContextGetDefault( GLDepthTestEnable_t *dst )
+{
+ dst->enable = GL_FALSE;
+}
+
+
+// --- GLDepthFunc ---
+void GLContextSet( GLDepthFunc_t *src )
+{
+ glDepthFunc ( src->func );
+}
+
+void GLContextGet( GLDepthFunc_t *dst )
+{
+ glGetEnumv ( GL_DEPTH_FUNC, &dst->func );
+}
+
+void GLContextGetDefault( GLDepthFunc_t *dst )
+{
+ dst->func = GL_GEQUAL;
+}
+
+
+// --- GLDepthMask ---
+void GLContextSet( GLDepthMask_t *src )
+{
+ glDepthMask ( src->mask );
+}
+
+void GLContextGet( GLDepthMask_t *dst )
+{
+ glGetBooleanv ( GL_DEPTH_WRITEMASK, (GLboolean*)&dst->mask );
+}
+
+void GLContextGetDefault( GLDepthMask_t *dst )
+{
+ dst->mask = GL_TRUE;
+}
+
+
+// --- GLStencilTestEnable ---
+void GLContextSet( GLStencilTestEnable_t *src )
+{
+ glSetEnable( GL_STENCIL_TEST, src->enable );
+}
+
+void GLContextGet( GLStencilTestEnable_t *dst )
+{
+ dst->enable = glIsEnabled( GL_STENCIL_TEST );
+}
+
+void GLContextGetDefault( GLStencilTestEnable_t *dst )
+{
+ dst->enable = GL_FALSE;
+}
+
+
+// --- GLStencilFunc ---
+void GLContextSet( GLStencilFunc_t *src )
+{
+ glStencilFuncSeparateATI( src->frontfunc, src->backfunc, src->ref, src->mask);
+}
+
+void GLContextGet( GLStencilFunc_t *dst )
+{
+ glGetEnumv ( GL_STENCIL_FUNC, &dst->frontfunc );
+ glGetEnumv ( GL_STENCIL_BACK_FUNC_ATI, &dst->backfunc );
+ glGetIntegerv ( GL_STENCIL_REF, &dst->ref );
+ glGetIntegerv ( GL_STENCIL_VALUE_MASK, (GLint*)&dst->mask );
+}
+
+void GLContextGetDefault( GLStencilFunc_t *dst )
+{
+ dst->frontfunc = GL_ALWAYS;
+ dst->backfunc = GL_ALWAYS;
+ dst->ref = 0;
+ dst->mask = 0xFFFFFFFF;
+}
+
+
+// --- GLStencilOp --- indexed 0=front, 1=back
+
+void GLContextSetIndexed( GLStencilOp_t *src, int index )
+{
+ GLenum face = (index==0) ? GL_FRONT : GL_BACK;
+
+ glStencilOpSeparateATI( face, src->sfail, src->dpfail, src->dppass );
+}
+
+void GLContextGetIndexed( GLStencilOp_t *dst, int index )
+{
+ GLenum face = (index==0) ? GL_FRONT : GL_BACK;
+
+ glGetEnumv ( (index==0) ? GL_STENCIL_FAIL : GL_STENCIL_BACK_FAIL_ATI, &dst->sfail );
+ glGetEnumv ( (index==0) ? GL_STENCIL_PASS_DEPTH_FAIL : GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI, &dst->dpfail );
+ glGetEnumv ( (index==0) ? GL_STENCIL_PASS_DEPTH_PASS : GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI, &dst->dppass );
+}
+
+void GLContextGetDefaultIndexed( GLStencilOp_t *dst, int index )
+{
+ dst->sfail = dst->dpfail = dst->dppass = GL_KEEP;
+}
+
+
+// --- GLStencilWriteMask ---
+void GLContextSet( GLStencilWriteMask_t *src )
+{
+ glStencilMask( src->mask );
+}
+
+void GLContextGet( GLStencilWriteMask_t *dst )
+{
+ glGetIntegerv ( GL_STENCIL_WRITEMASK, &dst->mask );
+}
+
+void GLContextGetDefault( GLStencilWriteMask_t *dst )
+{
+ dst->mask = 0xFFFFFFFF;
+}
+
+
+// --- GLClearColor ---
+void GLContextSet( GLClearColor_t *src )
+{
+ glClearColor( src->r, src->g, src->b, src->a );
+}
+
+void GLContextGet( GLClearColor_t *dst )
+{
+ glGetFloatv ( GL_COLOR_CLEAR_VALUE, &dst->r );
+}
+
+void GLContextGetDefault( GLClearColor_t *dst )
+{
+ dst->r = dst->g = dst->b = 0.5;
+ dst->a = 1.0;
+}
+
+
+// --- GLClearDepth ---
+void GLContextSet( GLClearDepth_t *src )
+{
+ glClearDepth ( src->d );
+}
+
+void GLContextGet( GLClearDepth_t *dst )
+{
+ glGetDoublev ( GL_DEPTH_CLEAR_VALUE, &dst->d );
+}
+
+void GLContextGetDefault( GLClearDepth_t *dst )
+{
+ dst->d = 1.0;
+}
+
+
+// --- GLClearStencil ---
+void GLContextSet( GLClearStencil_t *src )
+{
+ glClearStencil( src->s );
+}
+
+void GLContextGet( GLClearStencil_t *dst )
+{
+ glGetIntegerv ( GL_STENCIL_CLEAR_VALUE, &dst->s );
+}
+
+void GLContextGetDefault( GLClearStencil_t *dst )
+{
+ dst->s = 0;
+}
+
+//===============================================================================
+
+
+GLMTester::GLMTester(GLMTestParams *params)
+{
+ m_params = *params;
+
+ m_drawFBO = NULL;
+ m_drawColorTex = NULL;
+ m_drawDepthTex = NULL;
+}
+
+GLMTester::~GLMTester()
+{
+}
+
+void GLMTester::StdSetup( void )
+{
+ GLMContext *ctx = m_params.m_ctx;
+
+ m_drawWidth = 1024;
+ m_drawHeight = 768;
+
+ // make an FBO to draw into and activate it. no depth buffer yet
+ m_drawFBO = ctx->NewFBO();
+
+ // make color buffer texture
+
+ GLMTexLayoutKey colorkey;
+ CGLMTex *colortex;
+ memset( &colorkey, 0, sizeof(colorkey) );
+
+ colorkey.m_texGLTarget = GL_TEXTURE_2D;
+ colorkey.m_xSize = m_drawWidth;
+ colorkey.m_ySize = m_drawHeight;
+ colorkey.m_zSize = 1;
+
+ colorkey.m_texFormat = D3DFMT_A8R8G8B8;
+ colorkey.m_texFlags = kGLMTexRenderable;
+
+ m_drawColorTex = ctx->NewTex( &colorkey );
+
+ // do not leave that texture bound on the TMU
+ ctx->BindTexToTMU(NULL, 0 );
+
+
+ // attach color to FBO
+ GLMFBOTexAttachParams colorParams;
+ memset( &colorParams, 0, sizeof(colorParams) );
+
+ colorParams.m_tex = m_drawColorTex;
+ colorParams.m_face = 0;
+ colorParams.m_mip = 0;
+ colorParams.m_zslice= 0; // for clarity..
+
+ m_drawFBO->TexAttach( &colorParams, kAttColor0 );
+
+ // check it.
+ bool ready = m_drawFBO->IsReady();
+ InternalError( !ready, "drawing FBO no go");
+
+ // bind it
+ ctx->BindFBOToCtx( m_drawFBO, GL_READ_FRAMEBUFFER_EXT );
+ ctx->BindFBOToCtx( m_drawFBO, GL_DRAW_FRAMEBUFFER_EXT );
+
+ glViewport(0, 0, (GLsizei) m_drawWidth, (GLsizei) m_drawHeight );
+ CheckGLError("stdsetup viewport");
+
+ glScissor( 0,0, (GLsizei) m_drawWidth, (GLsizei) m_drawHeight );
+ CheckGLError("stdsetup scissor");
+
+ glOrtho( -1,1, -1,1, -1,1 );
+ CheckGLError("stdsetup ortho");
+
+ // activate debug font
+ ctx->GenDebugFontTex();
+}
+
+void GLMTester::StdCleanup( void )
+{
+ GLMContext *ctx = m_params.m_ctx;
+
+ // unbind
+ ctx->BindFBOToCtx( NULL, GL_READ_FRAMEBUFFER_EXT );
+ ctx->BindFBOToCtx( NULL, GL_DRAW_FRAMEBUFFER_EXT );
+
+ // del FBO
+ if (m_drawFBO)
+ {
+ ctx->DelFBO( m_drawFBO );
+ m_drawFBO = NULL;
+ }
+
+ // del tex
+ if (m_drawColorTex)
+ {
+ ctx->DelTex( m_drawColorTex );
+ m_drawColorTex = NULL;
+ }
+
+ if (m_drawDepthTex)
+ {
+ ctx->DelTex( m_drawDepthTex );
+ m_drawDepthTex = NULL;
+ }
+}
+
+
+void GLMTester::Clear( void )
+{
+ GLMContext *ctx = m_params.m_ctx;
+ ctx->MakeCurrent();
+
+ glViewport(0, 0, (GLsizei) m_drawWidth, (GLsizei) m_drawHeight );
+ glScissor( 0,0, (GLsizei) m_drawWidth, (GLsizei) m_drawHeight );
+ glOrtho( -1,1, -1,1, -1,1 );
+ CheckGLError("clearing viewport");
+
+ // clear to black
+ GLfloat clear_color[4] = { 0.0f, 0.0f, 0.0, 1.0f };
+ glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
+ CheckGLError("clearing color");
+
+ glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT+GL_STENCIL_BUFFER_BIT);
+ CheckGLError("clearing");
+
+ //glFinish();
+ //CheckGLError("clear finish");
+}
+
+void GLMTester::Present( int seed )
+{
+ GLMContext *ctx = m_params.m_ctx;
+ ctx->Present( m_drawColorTex );
+
+}
+
+void GLMTester::CheckGLError( const char *comment )
+{
+ char errbuf[1024];
+
+ //borrowed from GLMCheckError.. slightly different
+
+ if (!comment)
+ {
+ comment = "";
+ }
+
+ GLenum errorcode = (GLenum)glGetError();
+ GLenum errorcode2 = 0;
+ if ( errorcode != GL_NO_ERROR )
+ {
+ const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
+ const char *decodedStr2 = "";
+
+ if ( errorcode == GL_INVALID_FRAMEBUFFER_OPERATION_EXT )
+ {
+ // dig up the more detailed FBO status
+ errorcode2 = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
+
+ decodedStr2 = GLMDecode( eGL_ERROR, errorcode2 );
+
+ sprintf( errbuf, "\n%s - GL Error %08x/%08x = '%s / %s'", comment, errorcode, errorcode2, decodedStr, decodedStr2 );
+ }
+ else
+ {
+ sprintf( errbuf, "\n%s - GL Error %08x = '%s'", comment, errorcode, decodedStr );
+ }
+
+ if ( m_params.m_glErrToConsole )
+ {
+ printf("%s", errbuf );
+ }
+
+ if ( m_params.m_glErrToDebugger )
+ {
+ Debugger();
+ }
+ }
+}
+
+void GLMTester::InternalError( int errcode, const char *comment )
+{
+ if (errcode)
+ {
+ if (m_params.m_intlErrToConsole)
+ {
+ printf("\%s - error %d", comment, errcode );
+ }
+
+ if (m_params.m_intlErrToDebugger)
+ {
+ Debugger();
+ }
+ }
+}
+
+
+void GLMTester::RunTests( void )
+{
+ int *testList = m_params.m_testList;
+
+ while( (*testList >=0) && (*testList < 20) )
+ {
+ RunOneTest( *testList++ );
+ }
+}
+
+void GLMTester::RunOneTest( int testindex )
+{
+ // this might be better with 'ptmf' style
+ switch(testindex)
+ {
+ case 0: Test0(); break;
+ case 1: Test1(); break;
+ case 2: Test2(); break;
+ case 3: Test3(); break;
+
+ default:
+ Debugger(); // unrecognized
+ }
+}
+
+// #####################################################################################################################
+
+// some fixed lists which may be useful to all tests
+
+D3DFORMAT g_drawTexFormatsGLMT[] = // -1 terminated
+{
+ D3DFMT_A8R8G8B8,
+ D3DFMT_A4R4G4B4,
+ D3DFMT_X8R8G8B8,
+ D3DFMT_X1R5G5B5,
+ D3DFMT_A1R5G5B5,
+ D3DFMT_L8,
+ D3DFMT_A8L8,
+ D3DFMT_R8G8B8,
+ D3DFMT_A8,
+ D3DFMT_R5G6B5,
+ D3DFMT_DXT1,
+ D3DFMT_DXT3,
+ D3DFMT_DXT5,
+ D3DFMT_A32B32G32R32F,
+ D3DFMT_A16B16G16R16,
+
+ (D3DFORMAT)-1
+};
+
+D3DFORMAT g_fboColorTexFormatsGLMT[] = // -1 terminated
+{
+ D3DFMT_A8R8G8B8,
+ //D3DFMT_A4R4G4B4, //unsupported
+ D3DFMT_X8R8G8B8,
+ D3DFMT_X1R5G5B5,
+ //D3DFMT_A1R5G5B5, //unsupported
+ D3DFMT_A16B16G16R16F,
+ D3DFMT_A32B32G32R32F,
+ D3DFMT_R5G6B5,
+
+ (D3DFORMAT)-1
+};
+
+D3DFORMAT g_fboDepthTexFormatsGLMT[] = // -1 terminated, but note 0 for "no depth" mode
+{
+ (D3DFORMAT)0,
+ D3DFMT_D16,
+ D3DFMT_D24X8,
+ D3DFMT_D24S8,
+
+ (D3DFORMAT)-1
+};
+
+
+// #####################################################################################################################
+
+void GLMTester::Test0( void )
+{
+ // make and delete a bunch of textures.
+ // lock and unlock them.
+ // use various combos of -
+
+ // √texel format
+ // √2D | 3D | cube map
+ // √mipped / not
+ // √POT / NPOT
+ // large / small / square / rect
+ // square / rect
+
+ GLMContext *ctx = m_params.m_ctx;
+ ctx->MakeCurrent();
+
+ std::vector< CGLMTex* > testTextures; // will hold all the built textures
+
+ // test stage loop
+ // 0 is creation
+ // 1 is lock/unlock
+ // 2 is deletion
+
+ for( int teststage = 0; teststage < 3; teststage++)
+ {
+ int innerindex = 0; // increment at stage switch
+ // format loop
+ for( D3DFORMAT *fmtPtr = g_drawTexFormatsGLMT; *fmtPtr != ((D3DFORMAT)-1); fmtPtr++ )
+ {
+ // form loop
+ GLenum forms[] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, (GLenum)-1 };
+
+ for( GLenum *formPtr = forms; *formPtr != ((GLenum)-1); formPtr++ )
+ {
+ // mip loop
+ for( int mipped = 0; mipped < 2; mipped++ )
+ {
+ // large / square / pot loop
+ // &4 == large &2 == square &1 == POT
+ // NOTE you *have to be square* for cube maps.
+
+ for( int aspect = 0; aspect < 8; aspect++ )
+ {
+ switch( teststage )
+ {
+ case 0:
+ {
+ GLMTexLayoutKey key;
+ memset( &key, 0, sizeof(key) );
+
+ key.m_texGLTarget = *formPtr;
+ key.m_texFormat = *fmtPtr;
+ if (mipped)
+ key.m_texFlags |= kGLMTexMipped;
+
+ // assume big, square, POT, and 3D, then adjust as needed
+ key.m_xSize = key.m_ySize = key.m_zSize = 256;
+
+ if ( !(aspect&4) ) // big or little ?
+ {
+ // little
+ key.m_xSize >>= 2;
+ key.m_ySize >>= 2;
+ key.m_zSize >>= 2;
+ }
+
+ if ( key.m_texGLTarget != GL_TEXTURE_CUBE_MAP )
+ {
+ if ( !(aspect & 2) ) // square or rect?
+ {
+ // rect
+ key.m_ySize >>= 1;
+ key.m_zSize >>= 2;
+ }
+ }
+
+ if ( !(aspect&1) ) // POT or NPOT?
+ {
+ // NPOT
+ key.m_xSize += 56;
+ key.m_ySize += 56;
+ key.m_zSize += 56;
+ }
+
+ // 2D, 3D, cube map ?
+ if (key.m_texGLTarget!=GL_TEXTURE_3D)
+ {
+ // 2D or cube map: flatten Z extent to one texel
+ key.m_zSize = 1;
+ }
+ else
+ {
+ // 3D: knock down Z quite a bit so our test case does not run out of RAM
+ key.m_zSize >>= 3;
+ if (!key.m_zSize)
+ {
+ key.m_zSize = 1;
+ }
+ }
+
+ CGLMTex *newtex = ctx->NewTex( &key );
+ CheckGLError( "tex create test");
+ InternalError( newtex==NULL, "tex create test" );
+
+ testTextures.push_back( newtex );
+ printf("\n[%5d] created tex %s",innerindex,newtex->m_layout->m_layoutSummary );
+ }
+ break;
+
+ case 1:
+ {
+ CGLMTex *ptex = testTextures[innerindex];
+
+ for( int face=0; face m_layout->m_faceCount; face++)
+ {
+ for( int mip=0; mip m_layout->m_mipCount; mip++)
+ {
+ GLMTexLockParams lockreq;
+
+ lockreq.m_tex = ptex;
+ lockreq.m_face = face;
+ lockreq.m_mip = mip;
+
+ GLMTexLayoutSlice *slice = &ptex->m_layout->m_slices[ ptex->CalcSliceIndex( face, mip ) ];
+
+ lockreq.m_region.xmin = lockreq.m_region.ymin = lockreq.m_region.zmin = 0;
+ lockreq.m_region.xmax = slice->m_xSize;
+ lockreq.m_region.ymax = slice->m_ySize;
+ lockreq.m_region.zmax = slice->m_zSize;
+
+ char *lockAddress;
+ int yStride;
+ int zStride;
+
+ ptex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
+ CheckGLError( "tex lock test");
+ InternalError( lockAddress==NULL, "null lock address");
+
+ // write some texels of this flavor:
+ // red 75% green 40% blue 15% alpha 80%
+
+ GLMGenTexelParams gtp;
+
+ gtp.m_format = ptex->m_layout->m_format->m_d3dFormat;
+ gtp.m_dest = lockAddress;
+ gtp.m_chunkCount = (slice->m_xSize * slice->m_ySize * slice->m_zSize) / (ptex->m_layout->m_format->m_chunkSize * ptex->m_layout->m_format->m_chunkSize);
+ gtp.m_byteCountLimit = slice->m_storageSize;
+ gtp.r = 0.75;
+ gtp.g = 0.40;
+ gtp.b = 0.15;
+ gtp.a = 0.80;
+
+ GLMGenTexels( >p );
+
+ InternalError( gtp.m_bytesWritten != gtp.m_byteCountLimit, "byte count mismatch from GLMGenTexels" );
+ }
+ }
+
+ for( int face=0; face m_layout->m_faceCount; face++)
+ {
+ for( int mip=0; mip m_layout->m_mipCount; mip++)
+ {
+ GLMTexLockParams unlockreq;
+
+ unlockreq.m_tex = ptex;
+ unlockreq.m_face = face;
+ unlockreq.m_mip = mip;
+
+ // region need not matter for unlocks
+ unlockreq.m_region.xmin = unlockreq.m_region.ymin = unlockreq.m_region.zmin = 0;
+ unlockreq.m_region.xmax = unlockreq.m_region.ymax = unlockreq.m_region.zmax = 0;
+
+ char *lockAddress;
+ int yStride;
+ int zStride;
+
+ ptex->Unlock( &unlockreq );
+
+ CheckGLError( "tex unlock test");
+ }
+ }
+ printf("\n[%5d] locked/wrote/unlocked tex %s",innerindex, ptex->m_layout->m_layoutSummary );
+ }
+ break;
+
+ case 2:
+ {
+ CGLMTex *dtex = testTextures[innerindex];
+
+ printf("\n[%5d] deleting tex %s",innerindex, dtex->m_layout->m_layoutSummary );
+ ctx->DelTex( dtex );
+ CheckGLError( "tex delete test");
+ }
+ break;
+ } // end stage switch
+ innerindex++;
+ } // end aspect loop
+ } // end mip loop
+ } // end form loop
+ } // end format loop
+ } // end stage loop
+}
+
+// #####################################################################################################################
+void GLMTester::Test1( void )
+{
+ // FBO exercises
+ GLMContext *ctx = m_params.m_ctx;
+ ctx->MakeCurrent();
+
+ // FBO color format loop
+ for( D3DFORMAT *colorFmtPtr = g_fboColorTexFormatsGLMT; *colorFmtPtr != ((D3DFORMAT)-1); colorFmtPtr++ )
+ {
+ // FBO depth format loop
+ for( D3DFORMAT *depthFmtPtr = g_fboDepthTexFormatsGLMT; *depthFmtPtr != ((D3DFORMAT)-1); depthFmtPtr++ )
+ {
+ // mip loop
+ for( int mipped = 0; mipped < 2; mipped++ )
+ {
+ GLenum forms[] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, (GLenum)-1 };
+
+ // form loop
+ for( GLenum *formPtr = forms; *formPtr != ((GLenum)-1); formPtr++ )
+ {
+ //=============================================== make an FBO
+ CGLMFBO *fbo = ctx->NewFBO();
+
+ //=============================================== make a color texture
+ GLMTexLayoutKey colorkey;
+ memset( &colorkey, 0, sizeof(colorkey) );
+
+ switch(*formPtr)
+ {
+ case GL_TEXTURE_2D:
+ colorkey.m_texGLTarget = GL_TEXTURE_2D;
+ colorkey.m_xSize = 800;
+ colorkey.m_ySize = 600;
+ colorkey.m_zSize = 1;
+ break;
+
+ case GL_TEXTURE_3D:
+ colorkey.m_texGLTarget = GL_TEXTURE_3D;
+ colorkey.m_xSize = 800;
+ colorkey.m_ySize = 600;
+ colorkey.m_zSize = 32;
+ break;
+
+ case GL_TEXTURE_CUBE_MAP:
+ colorkey.m_texGLTarget = GL_TEXTURE_CUBE_MAP;
+ colorkey.m_xSize = 800;
+ colorkey.m_ySize = 800; // heh, cube maps have to have square sides...
+ colorkey.m_zSize = 1;
+ break;
+ }
+
+ colorkey.m_texFormat = *colorFmtPtr;
+ colorkey.m_texFlags = kGLMTexRenderable;
+ // decide if we want mips
+ if (mipped)
+ {
+ colorkey.m_texFlags |= kGLMTexMipped;
+ }
+
+ CGLMTex *colorTex = ctx->NewTex( &colorkey );
+ // Note that GLM will notice the renderable flag, and force texels to be written
+ // so the FBO will be complete
+
+ //=============================================== attach color
+ GLMFBOTexAttachParams colorParams;
+ memset( &colorParams, 0, sizeof(colorParams) );
+
+ colorParams.m_tex = colorTex;
+ colorParams.m_face = (colorkey.m_texGLTarget == GL_TEXTURE_CUBE_MAP) ? 2 : 0; // just steer to an alternate face as a test
+
+ colorParams.m_mip = (colorkey.m_texFlags & kGLMTexMipped) ? 2 : 0; // pick non-base mip slice
+
+ colorParams.m_zslice= (colorkey.m_texGLTarget == GL_TEXTURE_3D) ? 3 : 0; // just steer to an alternate slice as a test;
+
+ fbo->TexAttach( &colorParams, kAttColor0 );
+
+
+ //=============================================== optional depth tex
+ CGLMTex *depthTex = NULL;
+
+ if (*depthFmtPtr > 0 )
+ {
+ GLMTexLayoutKey depthkey;
+ memset( &depthkey, 0, sizeof(depthkey) );
+
+ depthkey.m_texGLTarget = GL_TEXTURE_2D;
+ depthkey.m_xSize = colorkey.m_xSize >> colorParams.m_mip; // scale depth tex to match color tex
+ depthkey.m_ySize = colorkey.m_ySize >> colorParams.m_mip;
+ depthkey.m_zSize = 1;
+
+ depthkey.m_texFormat = *depthFmtPtr;
+ depthkey.m_texFlags = kGLMTexRenderable | kGLMTexIsDepth; // no mips.
+ if (depthkey.m_texFormat==D3DFMT_D24S8)
+ {
+ depthkey.m_texFlags |= kGLMTexIsStencil;
+ }
+
+ depthTex = ctx->NewTex( &depthkey );
+
+
+ //=============================================== attach depth
+ GLMFBOTexAttachParams depthParams;
+ memset( &depthParams, 0, sizeof(depthParams) );
+
+ depthParams.m_tex = depthTex;
+ depthParams.m_face = 0;
+ depthParams.m_mip = 0;
+ depthParams.m_zslice= 0;
+
+ EGLMFBOAttachment depthAttachIndex = (depthkey.m_texFlags & kGLMTexIsStencil) ? kAttDepthStencil : kAttDepth;
+ fbo->TexAttach( &depthParams, depthAttachIndex );
+ }
+
+ printf("\n FBO:\n color tex %s\n depth tex %s",
+ colorTex->m_layout->m_layoutSummary,
+ depthTex ? depthTex->m_layout->m_layoutSummary : "none"
+ );
+
+ // see if FBO is happy
+ bool ready = fbo->IsReady();
+
+ printf("\n -> %s\n", ready ? "pass" : "fail" );
+
+ // unbind
+ ctx->BindFBOToCtx( NULL, GL_READ_FRAMEBUFFER_EXT );
+ ctx->BindFBOToCtx( NULL, GL_DRAW_FRAMEBUFFER_EXT );
+
+ // del FBO
+ ctx->DelFBO(fbo);
+
+ // del texes
+ ctx->DelTex( colorTex );
+ if (depthTex) ctx->DelTex( depthTex );
+ } // end form loop
+ } // end mip loop
+ } // end depth loop
+ } // end color loop
+}
+
+// #####################################################################################################################
+
+static int selftest2_seed = 0; // inc this every run to force main thread to teardown/reset display view
+void GLMTester::Test2( void )
+{
+ GLMContext *ctx = m_params.m_ctx;
+ ctx->MakeCurrent();
+
+ this->StdSetup(); // default test case drawing setup
+
+ // draw stuff (loop...)
+ for( int i=0; iDrawDebugText( posx, posy, 0.0f, charwidth, charheight, text );
+ }
+ glFinish();
+ CheckGLError("test2 finish");
+
+ this->Present( selftest2_seed );
+ }
+
+ this->StdCleanup();
+
+ selftest2_seed++;
+}
+
+// #####################################################################################################################
+
+static char g_testVertexProgram01 [] =
+{
+ "!!ARBvp1.0 \n"
+ "TEMP vertexClip; \n"
+ "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.position; \n"
+ "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.position; \n"
+ "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.position; \n"
+ "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.position; \n"
+ "ADD vertexClip.y, vertexClip.x, vertexClip.y; \n"
+ "MOV result.position, vertexClip; \n"
+ "MOV result.color, vertex.color; \n"
+ "MOV result.texcoord[0], vertex.texcoord; \n"
+ "END \n"
+};
+
+static char g_testFragmentProgram01 [] =
+{
+ "!!ARBfp1.0 \n"
+ "TEMP color; \n"
+ "MUL color, fragment.texcoord[0].y, 2.0; \n"
+ "ADD color, 1.0, -color; \n"
+ "ABS color, color; \n"
+ "ADD result.color, 1.0, -color; \n"
+ "MOV result.color.a, 1.0; \n"
+ "END \n"
+};
+
+
+// generic attrib versions..
+
+static char g_testVertexProgram01_GA [] =
+{
+ "!!ARBvp1.0 \n"
+ "TEMP vertexClip; \n"
+ "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.attrib[0]; \n"
+ "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.attrib[0]; \n"
+ "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.attrib[0]; \n"
+ "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.attrib[0]; \n"
+ "ADD vertexClip.y, vertexClip.x, vertexClip.y; \n"
+ "MOV result.position, vertexClip; \n"
+ "MOV result.color, vertex.attrib[3]; \n"
+ "MOV result.texcoord[0], vertex.attrib[8]; \n"
+ "END \n"
+};
+
+static char g_testFragmentProgram01_GA [] =
+{
+ "!!ARBfp1.0 \n"
+ "TEMP color; \n"
+ "TEX color, fragment.texcoord[0], texture[0], 2D;"
+ //"MUL color, fragment.texcoord[0].y, 2.0; \n"
+ //"ADD color, 1.0, -color; \n"
+ //"ABS color, color; \n"
+ //"ADD result.color, 1.0, -color; \n"
+ //"MOV result.color.a, 1.0; \n"
+ "MOV result.color, color; \n"
+ "END \n"
+};
+
+
+void GLMTester::Test3( void )
+{
+ /**************************
+ XXXXXXXXXXXXXXXXXXXXXX stale test code until we revise the program interface
+
+ GLMContext *ctx = m_params.m_ctx;
+ ctx->MakeCurrent();
+
+ this->StdSetup(); // default test case drawing setup
+
+ // make vertex&pixel shader
+ CGLMProgram *vprog = ctx->NewProgram( kGLMVertexProgram, g_testVertexProgram01_GA );
+ ctx->BindProgramToCtx( kGLMVertexProgram, vprog );
+
+ CGLMProgram *fprog = ctx->NewProgram( kGLMFragmentProgram, g_testFragmentProgram01_GA );
+ ctx->BindProgramToCtx( kGLMFragmentProgram, fprog );
+
+ // draw stuff (loop...)
+ for( int i=0; iDrawDebugText( posx, posy, 0.0f, charwidth, charheight, text );
+ }
+ glFinish();
+ CheckGLError("test3 finish");
+
+ this->Present( 3333 );
+ }
+
+ this->StdCleanup();
+ *****************************/
+}
+
+
diff --git a/My project/sdk/glmgr/glmgr.h b/My project/sdk/glmgr/glmgr.h
new file mode 100644
index 000000000..4c55f8995
--- /dev/null
+++ b/My project/sdk/glmgr/glmgr.h
@@ -0,0 +1,1031 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// glmgr.h
+// singleton class, common basis for managing GL contexts
+// responsible for tracking adapters and contexts
+//
+//===============================================================================
+
+#ifndef GLMGR_H
+#define GLMGR_H
+
+#pragma once
+
+#include "glmdebug.h"
+#include "glmdisplay.h"
+#include "glmgrext.h"
+#include "glmgrbasics.h"
+#include "cglmtex.h"
+#include "cglmfbo.h"
+#include "cglmprogram.h"
+#include "cglmbuffer.h"
+#include "cglmquery.h"
+
+
+
+
+//===============================================================================
+// glue to call out to Obj-C land (these are in glmgrcocoa.mm)
+
+bool NewNSGLContext( unsigned long *attribs, PseudoNSGLContextPtr nsglShareCtx, PseudoNSGLContextPtr *nsglCtxOut, CGLContextObj *cglCtxOut );
+CGLContextObj GetCGLContextFromNSGL( PseudoNSGLContextPtr nsglCtx );
+void DelNSGLContext( PseudoNSGLContextPtr nsglCtx );
+
+
+//===============================================================================
+
+// parrot the D3D present parameters, more or less... "adapter" translates into "active display index" per the m_activeDisplayCount below.
+class GLMDisplayParams
+{
+ public:
+
+ // presumption, these indices are in sync with the current display DB that GLMgr has handy
+ //int m_rendererIndex; // index of renderer (-1 if root context)
+ //int m_displayIndex; // index of display in renderer - for FS
+ //int m_modeIndex; // index of mode in display - for FS
+
+ void *m_focusWindow; // (VD3DHWND aka WindowRef) - what window does this context display into
+
+ bool m_fsEnable; // fullscreen on or not
+ bool m_vsyncEnable; // vsync on or not
+
+ // height and width have to match the display mode info if full screen.
+
+ uint m_backBufferWidth; // pixel width (aka screen h-resolution if full screen)
+ uint m_backBufferHeight; // pixel height (aka screen v-resolution if full screen)
+ D3DFORMAT m_backBufferFormat; // pixel format
+ uint m_multiSampleCount; // 0 means no MSAA, 2 means 2x MSAA, etc
+ // uint m_multiSampleQuality; // no MSAA quality control yet
+
+ bool m_enableAutoDepthStencil; // generally set to 'TRUE' per CShaderDeviceDx8::SetPresentParameters
+ D3DFORMAT m_autoDepthStencilFormat;
+
+ uint m_fsRefreshHz; // if full screen, this refresh rate (likely 0 for LCD's)
+
+ //uint m_rootRendererID; // only used if m_rendererIndex is -1.
+ //uint m_rootDisplayMask; // only used if m_rendererIndex is -1.
+
+ bool m_mtgl; // enable multi threaded GL driver
+};
+
+//===============================================================================
+
+class GLMgr
+{
+public:
+
+ //===========================================================================
+ // class methods - singleton
+ static void NewGLMgr( void ); // instantiate singleton..
+ static GLMgr *aGLMgr( void ); // return singleton..
+ static void DelGLMgr( void ); // tear down singleton..
+
+ //===========================================================================
+ // plain methods
+
+ #if 0 // turned all these off while new approach is coded
+ void RefreshDisplayDB( void ); // blow away old display DB, make a new one
+ GLMDisplayDB *GetDisplayDB( void ); // get a ptr to the one GLMgr keeps. only valid til next refresh.
+
+ // eligible renderers will be ranked by desirability starting at index 0 within the db
+ // within each renderer, eligible displays will be ranked some kind of desirability (area? dist from menu bar?)
+ // within each display, eligible modes will be ranked by descending areas
+
+ // calls supplying indices are implicitly making reference to the current DB
+ bool CaptureDisplay( int rendIndex, int displayIndex, bool captureAll ); // capture one display or all displays
+ void ReleaseDisplays( void ); // release all captures
+
+ int GetDisplayMode( int rendIndex, int displayIndex ); // retrieve current display res (returns modeIndex)
+ void SetDisplayMode( GLMDisplayParams *params ); // set the display res (only useful for FS)
+ #endif
+
+ GLMContext *NewContext( GLMDisplayParams *params ); // this will have to change
+ void DelContext( GLMContext *context );
+
+ // with usage of CGLMacro.h we could dispense with the "current context" thing
+ // and just declare a member variable of GLMContext, allowing each glXXX call to be routed directly
+ // to the correct context
+ void SetCurrentContext( GLMContext *context ); // make current in calling thread only
+ GLMContext *GetCurrentContext( void );
+
+protected:
+ friend class GLMContext;
+
+ GLMgr();
+ ~GLMgr();
+};
+
+
+//===========================================================================//
+
+// helper function to do enable or disable in one step
+inline void glSetEnable( GLenum which, bool enable )
+{
+ if (enable)
+ glEnable(which);
+ else
+ glDisable(which);
+}
+
+// helper function for int vs enum clarity
+inline void glGetEnumv( GLenum which, GLenum *dst )
+{
+ glGetIntegerv( which, (int*)dst );
+}
+
+//===========================================================================//
+//
+// types to support the GLMContext
+//
+//===========================================================================//
+
+// Each state set/get path we are providing caching for, needs its own struct and a comparison operator.
+// we also provide an enum of how many such types there are, handy for building dirty masks etc.
+
+// shorthand macros
+#define EQ(fff) ( (src.fff) == (fff) )
+
+//rasterizer
+struct GLAlphaTestEnable_t { GLint enable; bool operator==(const GLAlphaTestEnable_t& src) const { return EQ(enable); } };
+struct GLAlphaTestFunc_t { GLenum func; GLclampf ref; bool operator==(const GLAlphaTestFunc_t& src) const { return EQ(func) && EQ(ref); } };
+struct GLCullFaceEnable_t { GLint enable; bool operator==(const GLCullFaceEnable_t& src) const { return EQ(enable); } };
+struct GLCullFrontFace_t { GLenum value; bool operator==(const GLCullFrontFace_t& src) const { return EQ(value); } };
+struct GLPolygonMode_t { GLenum values[2]; bool operator==(const GLPolygonMode_t& src) const { return EQ(values[0]) && EQ(values[1]); } };
+struct GLDepthBias_t { GLfloat factor; GLfloat units; bool operator==(const GLDepthBias_t& src) const { return EQ(factor) && EQ(units); } };
+struct GLScissorEnable_t { GLint enable; bool operator==(const GLScissorEnable_t& src) const { return EQ(enable); } };
+struct GLScissorBox_t { GLint x,y; GLsizei width, height; bool operator==(const GLScissorBox_t& src) const { return EQ(x) && EQ(y) && EQ(width) && EQ(height); } };
+struct GLAlphaToCoverageEnable_t{ GLint enable; bool operator==(const GLAlphaToCoverageEnable_t& src) const { return EQ(enable); } };
+struct GLViewportBox_t { GLint x,y; GLsizei width, height; bool operator==(const GLViewportBox_t& src) const { return EQ(x) && EQ(y) && EQ(width) && EQ(height); } };
+struct GLViewportDepthRange_t { GLdouble near,far; bool operator==(const GLViewportDepthRange_t& src) const { return EQ(near) && EQ(far); } };
+struct GLClipPlaneEnable_t { GLint enable; bool operator==(const GLClipPlaneEnable_t& src) const { return EQ(enable); } };
+struct GLClipPlaneEquation_t { GLfloat x,y,z,w; bool operator==(const GLClipPlaneEquation_t& src) const { return EQ(x) && EQ(y) && EQ(z) && EQ(w); } };
+
+//blend
+struct GLColorMaskSingle_t { char r,g,b,a; bool operator==(const GLColorMaskSingle_t& src) const { return EQ(r) && EQ(g) && EQ(b) && EQ(a); } };
+struct GLColorMaskMultiple_t { char r,g,b,a; bool operator==(const GLColorMaskMultiple_t& src) const { return EQ(r) && EQ(g) && EQ(b) && EQ(a); } };
+struct GLBlendEnable_t { GLint enable; bool operator==(const GLBlendEnable_t& src) const { return EQ(enable); } };
+struct GLBlendFactor_t { GLenum srcfactor,dstfactor; bool operator==(const GLBlendFactor_t& src) const { return EQ(srcfactor) && EQ(dstfactor); } };
+struct GLBlendEquation_t { GLenum equation; bool operator==(const GLBlendEquation_t& src) const { return EQ(equation); } };
+struct GLBlendColor_t { GLfloat r,g,b,a; bool operator==(const GLBlendColor_t& src) const { return EQ(r) && EQ(g) && EQ(b) && EQ(a); } };
+struct GLBlendEnableSRGB_t { GLint enable; bool operator==(const GLBlendEnableSRGB_t& src) const { return EQ(enable); } };
+
+//depth
+struct GLDepthTestEnable_t { GLint enable; bool operator==(const GLDepthTestEnable_t& src) const { return EQ(enable); } };
+struct GLDepthFunc_t { GLenum func; bool operator==(const GLDepthFunc_t& src) const { return EQ(func); } };
+struct GLDepthMask_t { char mask; bool operator==(const GLDepthMask_t& src) const { return EQ(mask); } };
+
+//stencil
+struct GLStencilTestEnable_t { GLint enable; bool operator==(const GLStencilTestEnable_t& src) const { return EQ(enable); } };
+struct GLStencilFunc_t { GLenum frontfunc, backfunc; GLint ref; GLuint mask; bool operator==(const GLStencilFunc_t& src) const { return EQ(frontfunc) && EQ(backfunc) && EQ(ref) && EQ(mask); } };
+struct GLStencilOp_t { GLenum sfail; GLenum dpfail; GLenum dppass; bool operator==(const GLStencilOp_t& src) const { return EQ(sfail) && EQ(dpfail) && EQ(dppass); } };
+struct GLStencilWriteMask_t { GLint mask; bool operator==(const GLStencilWriteMask_t& src) const { return EQ(mask); } };
+
+//clearing
+struct GLClearColor_t { GLfloat r,g,b,a; bool operator==(const GLClearColor_t& src) const { return EQ(r) && EQ(g) && EQ(b) && EQ(a); } };
+struct GLClearDepth_t { GLdouble d; bool operator==(const GLClearDepth_t& src) const { return EQ(d); } };
+struct GLClearStencil_t { GLint s; bool operator==(const GLClearStencil_t& src) const { return EQ(s); } };
+
+#undef EQ
+
+enum EGLMStateBlockType
+{
+ kGLAlphaTestEnable,
+ kGLAlphaTestFunc,
+
+ kGLCullFaceEnable,
+ kGLCullFrontFace,
+
+ kGLPolygonMode,
+
+ kGLDepthBias,
+
+ kGLScissorEnable,
+ kGLScissorBox,
+
+ kGLViewportBox,
+ kGLViewportDepthRange,
+
+ kGLClipPlaneEnable,
+ kGLClipPlaneEquation,
+
+ kGLColorMaskSingle,
+ kGLColorMaskMultiple,
+
+ kGLBlendEnable,
+ kGLBlendFactor,
+ kGLBlendEquation,
+ kGLBlendColor,
+ kGLBlendEnableSRGB,
+
+ kGLDepthTestEnable,
+ kGLDepthFunc,
+ kGLDepthMask,
+
+ kGLStencilTestEnable,
+ kGLStencilFunc,
+ kGLStencilOp,
+ kGLStencilWriteMask,
+
+ kGLClearColor,
+ kGLClearDepth,
+ kGLClearStencil,
+
+ kGLAlphaToCoverageEnable,
+
+ kGLMStateBlockLimit
+};
+
+//===========================================================================//
+
+// templated functions representing GL R/W bottlenecks
+// one set of set/get/getdefault is instantiated for each of the GL*** types above.
+
+// use these from the non array state objects
+template void GLContextSet( T *src );
+template void GLContextGet( T *dst );
+template void GLContextGetDefault( T *dst );
+
+// use these from the array state objects
+template void GLContextSetIndexed( T *src, int index );
+template void GLContextGetIndexed( T *dst, int index );
+template void GLContextGetDefaultIndexed( T *dst, int index );
+
+//===========================================================================//
+
+// caching state object template. One of these is instantiated in the context per unique struct type above
+template class GLState
+{
+ public:
+
+ GLState()
+ {
+ dirty = false;
+ memset( &data, 0, sizeof(data) );
+ };
+
+ // write: client src into cache
+ // common case is both false. dirty is calculated, context write is deferred.
+ void Write( T *src, bool noCompare=false, bool noDefer=false )
+ {
+ if (noCompare)
+ {
+ dirty = true;
+ }
+ else
+ {
+ // only == is implemented, so test for equal and negate
+ // note, you only set dirty if mismatch, you never clear it until flush
+ if ( !(data == *src) )
+ {
+ dirty = true;
+ }
+ }
+
+ data = *src;
+
+ if (noDefer)
+ {
+ Flush( true ); // dirty becomes false
+ }
+ };
+
+ // write cache->context if dirty or forced.
+ void Flush( bool noDefer=false )
+ {
+ if (dirty || noDefer)
+ {
+ GLContextSet( &data );
+ GLMCheckError();
+ // good place for some error checking here
+ dirty = false;
+ }
+ };
+
+ // default: write default value to cache, optionally write through
+ void Default( bool noDefer=false )
+ {
+ GLContextGetDefault( &data ); // read default values directly to our cache copy
+ dirty = true;
+ Flush(noDefer);
+ };
+
+ // read: sel = 0 for cache, 1 for context
+ void Read( T *dst, int sel )
+ {
+ if (sel==0)
+ {
+ *dst = data;
+ }
+ else
+ {
+ GLContextGet( dst );
+ GLMCheckError();
+ }
+ };
+
+ // check: verify that context equals cache, return true if mismatched or if illegal values seen
+ bool Check ( void )
+ {
+ T temp;
+ bool result;
+
+ GLContextGet( &temp );
+ GLMCheckError();
+ result = !(temp == data);
+ return result;
+ };
+
+ protected:
+ T data;
+ bool dirty;
+};
+
+// caching state object template - with multiple values behind it that are indexed
+template class GLStateArray
+{
+ public:
+
+ GLStateArray()
+ {
+ memset( &dirty, 0, sizeof(dirty) );
+ memset( &data, 0, sizeof(data) );
+ };
+
+ // write: client src into cache
+ // common case is both false. dirty is calculated, context write is deferred.
+ void WriteIndex( T *src, int index, bool noCompare=false, bool noDefer=false )
+ {
+ if (noCompare)
+ {
+ dirty[index] = true;
+ }
+ else
+ {
+ // only == is implemented, so test for equal and negate
+ // note, you only set dirty if mismatch, you never clear it until flush
+ if (! (data[index] == *src) )
+ {
+ dirty[index] = true;
+ }
+ }
+
+ data[index] = *src;
+
+ if (noDefer)
+ {
+ FlushIndex( index, true ); // dirty becomes false
+ }
+ };
+
+ // write cache->context if dirty or forced.
+ void FlushIndex( int index, bool noDefer=false )
+ {
+ if (dirty[index] || noDefer)
+ {
+ GLContextSetIndexed( &data[index], index );
+ GLMCheckError();
+ dirty[index] = false;
+ }
+ };
+
+ // write all slots in the array
+ void Flush( bool noDefer=false )
+ {
+ for( int i=0; i m_AlphaTestEnable;
+
+ GLState m_AlphaTestFunc;
+
+ GLState m_CullFaceEnable;
+ GLState m_CullFrontFace;
+ GLState m_PolygonMode;
+
+ GLState m_DepthBias;
+
+ GLStateArray m_ClipPlaneEnable;
+ GLStateArray m_ClipPlaneEquation; // dxabstract puts them directly into param slot 253(0) and 254(1)
+
+ GLState m_ScissorEnable;
+ GLState m_ScissorBox;
+
+ GLState m_AlphaToCoverageEnable;
+
+ GLState m_ViewportBox;
+ GLState m_ViewportDepthRange;
+
+ GLState m_ColorMaskSingle;
+ GLStateArray m_ColorMaskMultiple; // need an official constant for the color buffers limit
+
+ GLState m_BlendEnable;
+ GLState m_BlendFactor;
+ GLState m_BlendEquation;
+ GLState m_BlendColor;
+ GLState m_BlendEnableSRGB; // write to this one to transmit intent to write SRGB encoded pixels to drawing FB
+ bool m_FakeBlendEnableSRGB; // writes to above will be shunted here if fake SRGB is in effect.
+
+ GLState m_DepthTestEnable;
+ GLState m_DepthFunc;
+ GLState m_DepthMask;
+
+ GLState m_StencilTestEnable; // global stencil test enable
+ GLState m_StencilFunc; // holds front and back stencil funcs
+ GLStateArray m_StencilOp; // indexed: 0=front 1=back
+ GLState m_StencilWriteMask;
+
+ GLState m_ClearColor;
+ GLState m_ClearDepth;
+ GLState m_ClearStencil;
+
+ // texture bindings and sampler setup
+ int m_activeTexture; // mirror for glActiveTexture
+ GLMTexSampler m_samplers[GLM_SAMPLER_COUNT];
+
+ // texture lock tracking - CGLMTex objects share usage of this
+ std::vector< GLMTexLockDesc > m_texLocks;
+
+ // render target binding - check before draw
+ // similar to tex sampler mechanism, we track "bound" from "chosen for drawing" separately,
+ // so binding for creation/setup need not disrupt any notion of what will be used at draw time
+
+ CGLMFBO *m_boundDrawFBO; // FBO on GL_DRAW_FRAMEBUFFER bind point
+ CGLMFBO *m_boundReadFBO; // FBO on GL_READ_FRAMEBUFFER bind point
+ // ^ both are set if you bind to GL_FRAMEBUFFER_EXT
+
+ CGLMFBO *m_drawingFBO; // what FBO should be bound at draw time (to both read/draw bp's).
+
+ CGLMFBO *m_blitReadFBO;
+ CGLMFBO *m_blitDrawFBO; // scratch FBO's for framebuffer blit
+
+ CGLMFBO *m_scratchFBO[ kGLMScratchFBOCount ]; // general purpose FBO's for internal use
+
+ std::vector< CGLMFBO* > m_fboTable; // each live FBO goes in the table
+
+ // program bindings
+ EGLMProgramLang m_drawingLangAtFrameStart; // selector for start of frame (spills into m_drawingLang)
+ EGLMProgramLang m_drawingLang; // selector for which language we desire to draw with on the next batch
+ CGLMProgram *m_drawingProgram[ kGLMNumProgramTypes ];
+
+ GLMProgramParamsF m_programParamsF[ kGLMNumProgramTypes ];
+ GLMProgramParamsB m_programParamsB[ kGLMNumProgramTypes ]; // two banks, but only the vertex one is used
+ GLMProgramParamsI m_programParamsI[ kGLMNumProgramTypes ]; // two banks, but only the vertex one is used
+ EGLMParamWriteMode m_paramWriteMode;
+
+ CGLMProgram *m_nullFragmentProgram; // write opaque black. Activate when caller asks for null FP
+
+ CGLMProgram *m_preloadTexVertexProgram; // programs to help preload textures (dummies)
+ CGLMProgram *m_preload2DTexFragmentProgram;
+ CGLMProgram *m_preload3DTexFragmentProgram;
+ CGLMProgram *m_preloadCubeTexFragmentProgram;
+
+ CGLMProgram *m_boundProgram[ kGLMNumProgramTypes ];
+
+ CGLMShaderPairCache *m_pairCache; // GLSL only
+ CGLMShaderPair *m_boundPair; // GLSL only
+ uint m_boundPairRevision; // GLSL only
+ GLhandleARB m_boundPairProgram; // GLSL only
+
+ // buffer bindings
+ CGLMBuffer *m_lastKnownBufferBinds[ kGLMNumBufferTypes ]; // tracked per bind point for dupe-bind-absorb
+ GLMVertexAttributeDesc m_lastKnownVertexAttribs[ kGLMVertexAttributeIndexMax ]; // tracked per attrib for dupe-set-absorb
+ uint m_lastKnownVertexAttribMask; // tracked for dupe-enable-absorb
+
+ CGLMBuffer *m_drawIndexBuffer; // ... ? do we need dupe tracking for index buffer setup? ?
+
+ GLMVertexSetup m_drawVertexSetup;
+
+ EGLMAttribWriteMode m_attribWriteMode;
+
+ bool m_slowCheckEnable; // turn this on or no native checking is done ("-glmassertslow" or "-glmsspewslow")
+ bool m_slowAssertEnable; // turn this on to assert on a non-native batch "-glmassertslow"
+ bool m_slowSpewEnable; // turn this on to log non-native batches to stdout "-glmspewslow"
+
+ // debug font texture
+ CGLMTex *m_debugFontTex; // might be NULL unless you call GenDebugFontTex
+ CGLMBuffer *m_debugFontIndices; // up to 1024 indices (256 chars times 4)
+ CGLMBuffer *m_debugFontVertices; // up to 1024 verts
+
+ // batch/frame debugging support
+ int m_debugFrameIndex; // init to -1. Increment at BeginFrame
+ int m_debugBatchIndex; // init to -1. Increment at any draw call
+
+#if GLMDEBUG
+ // interactive (DebugHook) debug support
+
+ // using these you can implement frame advance, batch single step, and batch rewind (let it run til next frame and hold on prev batch #)
+ int m_holdFrameBegin; // -1 if no hold req'd, otherwise # of frame to hold at (at beginframe time)
+ int m_holdFrameEnd; // -1 if no hold req'd, otherwise # of frame to hold at (at endframe time)
+
+ int m_holdBatch,m_holdBatchFrame; // -1 if no hold, else # of batch&frame to hold at (both must be set)
+ // these can be expired/cleared to -1 if the frame passes without a hit
+ // may be desirable to re-pause in that event, as user was expecting a hold to occur
+
+ bool m_debugDelayEnable; // allow sleep delay
+ uint m_debugDelay; // sleep time per hook call in microseconds (for usleep())
+
+ // pre-draw global toggles / options
+ bool m_autoClearColor,m_autoClearDepth,m_autoClearStencil;
+ float m_autoClearColorValues[4];
+
+ // debug knobs
+ int m_selKnobIndex;
+ float m_selKnobMinValue,m_selKnobMaxValue,m_selKnobIncrement;
+#endif
+
+};
+
+struct GLMTestParams
+{
+ GLMContext *m_ctx;
+ int *m_testList; // -1 termed
+
+ bool m_glErrToDebugger;
+ bool m_glErrToConsole;
+
+ bool m_intlErrToDebugger;
+ bool m_intlErrToConsole;
+
+ int m_frameCount; // how many frames to test.
+};
+
+class GLMTester
+{
+ public:
+
+ GLMTester(GLMTestParams *params);
+ ~GLMTester();
+
+
+ // optionally callable by test routines to get basic drawables wired up
+ void StdSetup( void );
+ void StdCleanup( void );
+
+ // callable by test routines to clear the frame or present it
+ void Clear( void );
+ void Present( int seed );
+
+ // error reporting
+ void CheckGLError( const char *comment ); // obey m_params setting for console / debugger response
+ void InternalError( int errcode, const char *comment ); // if errcode!=0, obey m_params setting for console / debugger response
+
+ void RunTests();
+
+ void RunOneTest( int testindex );
+
+ // test routines themselves
+ void Test0();
+ void Test1();
+ void Test2();
+ void Test3();
+
+ GLMTestParams m_params; // copy of caller's params, do not mutate...
+
+ // std-setup stuff
+ int m_drawWidth, m_drawHeight;
+ CGLMFBO *m_drawFBO;
+ CGLMTex *m_drawColorTex;
+ CGLMTex *m_drawDepthTex;
+};
+
+
+#endif
diff --git a/My project/sdk/glmgr/glmgrbasics.cpp b/My project/sdk/glmgr/glmgrbasics.cpp
new file mode 100644
index 000000000..1f8dc9ccb
--- /dev/null
+++ b/My project/sdk/glmgr/glmgrbasics.cpp
@@ -0,0 +1,4082 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// glmgrbasics.cpp
+//
+//===============================================================================
+
+#include "glmgrbasics.h"
+#include "dxabstract.h"
+
+#ifdef OSX
+// Debugger - 10.8
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED <= __MAC_10_6
+#include
+#include
+#else
+#define kCGLCPComment ((CGLContextParameter)1232)
+/* param is a pointer to a NULL-terminated C-style string. */
+/* Inserts a context-specific comment into the function trace stream. */
+/* Availability: set only, get is ignored. */
+
+#define kCGLCPDumpState ((CGLContextParameter)1233)
+/* param ignored. Dumps all the gl state. */
+/* Availability: set only, get is ignored. */
+
+#define kCGLCPEnableForceFlush ((CGLContextParameter)1234)
+/* param is GL_TRUE to enable "force flush" mode or GL_FALSE to disable. */
+/* Availability: set and get. */
+
+#define kCGLGOComment ((CGLGlobalOption)1506)
+/* param is a pointer to a NULL-terminated C-style string. */
+/* Inserts a comment in the trace steam that applies to all contexts. */
+/* Availability: set only, get is ignored. */
+
+#define kCGLGOEnableFunctionTrace ((CGLGlobalOption)1507)
+/* param is GL_TRUE or GL_FALSE */
+/* Turns GL function call tracing on and off */
+/* Availability: set and get */
+
+#define kCGLGOResetFunctionTrace ((CGLGlobalOption)1509)
+/* param is ignored */
+/* Erases current function trace and starts a new one */
+/* Availability: set only, get is ignored. */
+
+#define kCGLGOEnableBreakpoint ((CGLGlobalOption)1514)
+/* param is an array of 3 GLints:
+ param[0] is function ID (see CGLProfilerFunctionEnum.h)
+ param[1] is the logical OR of kCGLProfBreakBefore or kCGLProfBreakAfter, indicating how
+ you want the breakpoint to stop: before entering OpenGL, on return from OpenGL, or both.
+ param[2] is a boolean which turns the breakpoint on or off.
+ */
+/* Availability: set and get. */
+
+#define kCGLProfBreakBefore 0x0001
+#define kCGLProfBreakAfter 0x0002
+
+#define kCGLFEglColor4sv 98
+
+#endif
+
+//===============================================================================
+#define TOLOWERC( x ) (( ( x >= 'A' ) && ( x <= 'Z' ) )?( x + 32 ) : x )
+int V_stricmp(const char *s1, const char *s2 )
+{
+ uint8 const *pS1 = ( uint8 const * ) s1;
+ uint8 const *pS2 = ( uint8 const * ) s2;
+ for(;;)
+ {
+ int c1 = *( pS1++ );
+ int c2 = *( pS2++ );
+ if ( c1 == c2 )
+ {
+ if ( !c1 ) return 0;
+ }
+ else
+ {
+ if ( ! c2 )
+ {
+ return c1 - c2;
+ }
+ c1 = TOLOWERC( c1 );
+ c2 = TOLOWERC( c2 );
+ if ( c1 != c2 )
+ {
+ return c1 - c2;
+ }
+ }
+ c1 = *( pS1++ );
+ c2 = *( pS2++ );
+ if ( c1 == c2 )
+ {
+ if ( !c1 ) return 0;
+ }
+ else
+ {
+ if ( ! c2 )
+ {
+ return c1 - c2;
+ }
+ c1 = TOLOWERC( c1 );
+ c2 = TOLOWERC( c2 );
+ if ( c1 != c2 )
+ {
+ return c1 - c2;
+ }
+ }
+ }
+}
+
+inline unsigned char tolower_fast(unsigned char c)
+{
+ if ( (c >= 'A') && (c <= 'Z') )
+ return c + ('a' - 'A');
+ return c;
+}
+
+//-----------------------------------------------------------------------------
+// Finds a string in another string with a case insensitive test
+//-----------------------------------------------------------------------------
+char const* V_stristr( char const* pStr, char const* pSearch )
+{
+ //AssertValidStringPtr(pStr);
+ //AssertValidStringPtr(pSearch);
+
+ if (!pStr || !pSearch)
+ return 0;
+
+ char const* pLetter = pStr;
+
+ // Check the entire string
+ while (*pLetter != 0)
+ {
+ // Skip over non-matches
+ if (tolower_fast((unsigned char)*pLetter) == tolower_fast((unsigned char)*pSearch))
+ {
+ // Check for match
+ char const* pMatch = pLetter + 1;
+ char const* pTest = pSearch + 1;
+ while (*pTest != 0)
+ {
+ // We've run off the end; don't bother.
+ if (*pMatch == 0)
+ return 0;
+
+ if (tolower_fast((unsigned char)*pMatch) != tolower_fast((unsigned char)*pTest))
+ break;
+
+ ++pMatch;
+ ++pTest;
+ }
+
+ // Found a match!
+ if (*pTest == 0)
+ return pLetter;
+ }
+
+ ++pLetter;
+ }
+
+ return 0;
+}
+
+char* V_stristr( char* pStr, char const* pSearch )
+{
+ //AssertValidStringPtr( pStr );
+ //AssertValidStringPtr( pSearch );
+
+ return (char*)V_stristr( (char const*)pStr, pSearch );
+}
+
+//===============================================================================
+
+// convars for GLM
+
+//ConVar gl_errorcheckall ( "gl_errorcheckall", "0" );
+//ConVar gl_errorcheckqueries ( "gl_errorcheckqueries", "0" );
+
+int gl_errorcheckall = 0;
+int gl_errorcheckqueries = 0;
+
+// this one overrides the other two.
+// i.e. you can set this one true, and no errors will be checked, period.
+//ConVar gl_errorchecknone ( "gl_errorchecknone", "0" );
+int gl_errorchecknone = 0;
+
+// this decides whether the engine will try to use fast context mode on 10.6.3 or later.
+// fast context mode means that a single GL context is used both for the window and the engine, saving on sync and flushes.
+// it's only a suggestion; if the OS is below 10.6.2 it will be ignored.
+//ConVar gl_singlecontext ( "gl_singlecontext", "1" );
+int gl_singlecontext = 1;
+
+//===============================================================================
+// decoding tables for debug
+
+typedef struct
+{
+ unsigned long value;
+ const char *name;
+} GLMValueEntry_t;
+
+#define TERMVALUE 0x31415926
+ // terminator for value tables
+
+#define VE( x ) { x, #x }
+ // "value entry"
+
+GLMValueEntry_t g_d3d_devtypes[] =
+{
+ VE( D3DDEVTYPE_HAL ),
+ VE( D3DDEVTYPE_REF ),
+
+ VE( TERMVALUE )
+};
+
+GLMValueEntry_t g_d3d_formats[] =
+{
+ VE( D3DFMT_INDEX16 ),
+ VE( D3DFMT_D16 ),
+ VE( D3DFMT_D24S8 ),
+ VE( D3DFMT_A8R8G8B8 ),
+ VE( D3DFMT_A4R4G4B4 ),
+ VE( D3DFMT_X8R8G8B8 ),
+ VE( D3DFMT_R5G6R5 ),
+ VE( D3DFMT_X1R5G5B5 ),
+ VE( D3DFMT_A1R5G5B5 ),
+ VE( D3DFMT_L8 ),
+ VE( D3DFMT_A8L8 ),
+ VE( D3DFMT_A ),
+ VE( D3DFMT_DXT1 ),
+ VE( D3DFMT_DXT3 ),
+ VE( D3DFMT_DXT5 ),
+ VE( D3DFMT_V8U8 ),
+ VE( D3DFMT_Q8W8V8U8 ),
+ VE( D3DFMT_X8L8V8U8 ),
+ VE( D3DFMT_A16B16G16R16F ),
+ VE( D3DFMT_A16B16G16R16 ),
+ VE( D3DFMT_R32F ),
+ VE( D3DFMT_A32B32G32R32F ),
+ VE( D3DFMT_R8G8B8 ),
+ VE( D3DFMT_D24X4S4 ),
+ VE( D3DFMT_A8 ),
+ VE( D3DFMT_R5G6B5 ),
+ VE( D3DFMT_D15S1 ),
+ VE( D3DFMT_D24X8 ),
+ VE( D3DFMT_VERTEXDATA ),
+ VE( D3DFMT_INDEX32 ),
+
+ // vendor specific formats (fourcc's)
+ VE( D3DFMT_NV_INTZ ),
+ VE( D3DFMT_NV_RAWZ ),
+ VE( D3DFMT_NV_NULL ),
+ VE( D3DFMT_ATI_D16 ),
+ VE( D3DFMT_ATI_D24S8 ),
+ VE( D3DFMT_ATI_2N ),
+ VE( D3DFMT_ATI_1N ),
+
+ VE( D3DFMT_UNKNOWN ),
+
+ VE( TERMVALUE )
+};
+
+GLMValueEntry_t g_d3d_rtypes[] =
+{
+ VE( D3DRTYPE_SURFACE ),
+ VE( D3DRTYPE_TEXTURE ),
+ VE( D3DRTYPE_VOLUMETEXTURE ),
+ VE( D3DRTYPE_CUBETEXTURE ),
+ VE( D3DRTYPE_VERTEXBUFFER ),
+ VE( D3DRTYPE_INDEXBUFFER ),
+
+ VE( TERMVALUE )
+};
+
+GLMValueEntry_t g_d3d_usages[] =
+{
+ VE( D3DUSAGE_RENDERTARGET ),
+ VE( D3DUSAGE_DEPTHSTENCIL ),
+ VE( D3DUSAGE_DYNAMIC ),
+ VE( D3DUSAGE_AUTOGENMIPMAP ),
+ //VE( D3DUSAGE_DMAP ),
+ //VE( D3DUSAGE_QUERY_LEGACYBUMPMAP ),
+ VE( D3DUSAGE_QUERY_SRGBREAD ),
+ VE( D3DUSAGE_QUERY_FILTER ),
+ VE( D3DUSAGE_QUERY_SRGBWRITE ),
+ VE( D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING ),
+ VE( D3DUSAGE_QUERY_VERTEXTEXTURE ),
+ //VE( D3DUSAGE_QUERY_WRAPANDMIP ),
+ VE( D3DUSAGE_WRITEONLY ),
+ VE( D3DUSAGE_SOFTWAREPROCESSING ),
+ VE( D3DUSAGE_DONOTCLIP ),
+ VE( D3DUSAGE_POINTS ),
+ VE( D3DUSAGE_RTPATCHES ),
+ VE( D3DUSAGE_NPATCHES ),
+
+ VE( TERMVALUE )
+};
+
+GLMValueEntry_t g_d3d_rstates[] =
+{
+ VE( D3DRS_ZENABLE ),
+ VE( D3DRS_FILLMODE ),
+ VE( D3DRS_SHADEMODE ),
+ VE( D3DRS_ZWRITEENABLE ),
+ VE( D3DRS_ALPHATESTENABLE ),
+ VE( D3DRS_LASTPIXEL ),
+ VE( D3DRS_SRCBLEND ),
+ VE( D3DRS_DESTBLEND ),
+ VE( D3DRS_CULLMODE ),
+ VE( D3DRS_ZFUNC ),
+ VE( D3DRS_ALPHAREF ),
+ VE( D3DRS_ALPHAFUNC ),
+ VE( D3DRS_DITHERENABLE ),
+ VE( D3DRS_ALPHABLENDENABLE ),
+ VE( D3DRS_FOGENABLE ),
+ VE( D3DRS_SPECULARENABLE ),
+ VE( D3DRS_FOGCOLOR ),
+ VE( D3DRS_FOGTABLEMODE ),
+ VE( D3DRS_FOGSTART ),
+ VE( D3DRS_FOGEND ),
+ VE( D3DRS_FOGDENSITY ),
+ VE( D3DRS_RANGEFOGENABLE ),
+ VE( D3DRS_STENCILENABLE ),
+ VE( D3DRS_STENCILFAIL ),
+ VE( D3DRS_STENCILZFAIL ),
+ VE( D3DRS_STENCILPASS ),
+ VE( D3DRS_STENCILFUNC ),
+ VE( D3DRS_STENCILREF ),
+ VE( D3DRS_STENCILMASK ),
+ VE( D3DRS_STENCILWRITEMASK ),
+ VE( D3DRS_TEXTUREFACTOR ),
+ VE( D3DRS_WRAP0 ),
+ VE( D3DRS_WRAP1 ),
+ VE( D3DRS_WRAP2 ),
+ VE( D3DRS_WRAP3 ),
+ VE( D3DRS_WRAP4 ),
+ VE( D3DRS_WRAP5 ),
+ VE( D3DRS_WRAP6 ),
+ VE( D3DRS_WRAP7 ),
+ VE( D3DRS_CLIPPING ),
+ VE( D3DRS_LIGHTING ),
+ VE( D3DRS_AMBIENT ),
+ VE( D3DRS_FOGVERTEXMODE ),
+ VE( D3DRS_COLORVERTEX ),
+ VE( D3DRS_LOCALVIEWER ),
+ VE( D3DRS_NORMALIZENORMALS ),
+ VE( D3DRS_DIFFUSEMATERIALSOURCE ),
+ VE( D3DRS_SPECULARMATERIALSOURCE ),
+ VE( D3DRS_AMBIENTMATERIALSOURCE ),
+ VE( D3DRS_EMISSIVEMATERIALSOURCE ),
+ VE( D3DRS_VERTEXBLEND ),
+ VE( D3DRS_CLIPPLANEENABLE ),
+ VE( D3DRS_POINTSIZE ),
+ VE( D3DRS_POINTSIZE_MIN ),
+ VE( D3DRS_POINTSPRITEENABLE ),
+ VE( D3DRS_POINTSCALEENABLE ),
+ VE( D3DRS_POINTSCALE_A ),
+ VE( D3DRS_POINTSCALE_B ),
+ VE( D3DRS_POINTSCALE_C ),
+ VE( D3DRS_MULTISAMPLEANTIALIAS ),
+ VE( D3DRS_MULTISAMPLEMASK ),
+ VE( D3DRS_PATCHEDGESTYLE ),
+ VE( D3DRS_DEBUGMONITORTOKEN ),
+ VE( D3DRS_POINTSIZE_MAX ),
+ VE( D3DRS_INDEXEDVERTEXBLENDENABLE ),
+ VE( D3DRS_COLORWRITEENABLE ),
+ VE( D3DRS_TWEENFACTOR ),
+ VE( D3DRS_BLENDOP ),
+ VE( D3DRS_POSITIONDEGREE ),
+ VE( D3DRS_NORMALDEGREE ),
+ VE( D3DRS_SCISSORTESTENABLE ),
+ VE( D3DRS_SLOPESCALEDEPTHBIAS ),
+ VE( D3DRS_ANTIALIASEDLINEENABLE ),
+ VE( D3DRS_MINTESSELLATIONLEVEL ),
+ VE( D3DRS_MAXTESSELLATIONLEVEL ),
+ VE( D3DRS_ADAPTIVETESS_X ),
+ VE( D3DRS_ADAPTIVETESS_Y ),
+ VE( D3DRS_ADAPTIVETESS_Z ),
+ VE( D3DRS_ADAPTIVETESS_W ),
+ VE( D3DRS_ENABLEADAPTIVETESSELLATION ),
+ VE( D3DRS_TWOSIDEDSTENCILMODE ),
+ VE( D3DRS_CCW_STENCILFAIL ),
+ VE( D3DRS_CCW_STENCILZFAIL ),
+ VE( D3DRS_CCW_STENCILPASS ),
+ VE( D3DRS_CCW_STENCILFUNC ),
+ VE( D3DRS_COLORWRITEENABLE1 ),
+ VE( D3DRS_COLORWRITEENABLE2 ),
+ VE( D3DRS_COLORWRITEENABLE3 ),
+ VE( D3DRS_BLENDFACTOR ),
+ VE( D3DRS_SRGBWRITEENABLE ),
+ VE( D3DRS_DEPTHBIAS ),
+ VE( D3DRS_WRAP8 ),
+ VE( D3DRS_WRAP9 ),
+ VE( D3DRS_WRAP10 ),
+ VE( D3DRS_WRAP11 ),
+ VE( D3DRS_WRAP12 ),
+ VE( D3DRS_WRAP13 ),
+ VE( D3DRS_WRAP14 ),
+ VE( D3DRS_WRAP15 ),
+ VE( D3DRS_SEPARATEALPHABLENDENABLE ),
+ VE( D3DRS_SRCBLENDALPHA ),
+ VE( D3DRS_DESTBLENDALPHA ),
+ VE( D3DRS_BLENDOPALPHA ),
+
+ VE( TERMVALUE )
+};
+
+GLMValueEntry_t g_d3d_opcodes[] =
+{
+ VE( D3DSIO_NOP ),
+ VE( D3DSIO_PHASE ),
+ VE( D3DSIO_RET ),
+ VE( D3DSIO_ELSE ),
+ VE( D3DSIO_ENDIF ),
+ VE( D3DSIO_ENDLOOP ),
+ VE( D3DSIO_ENDREP ),
+ VE( D3DSIO_BREAK ),
+ VE( D3DSIO_TEXDEPTH ),
+ VE( D3DSIO_TEXKILL ),
+ VE( D3DSIO_BEM ),
+ VE( D3DSIO_TEXBEM ),
+ VE( D3DSIO_TEXBEML ),
+ VE( D3DSIO_TEXDP3 ),
+ VE( D3DSIO_TEXDP3TEX ),
+ VE( D3DSIO_TEXM3x2DEPTH ),
+ VE( D3DSIO_TEXM3x2TEX ),
+ VE( D3DSIO_TEXM3x3 ),
+ VE( D3DSIO_TEXM3x3PAD ),
+ VE( D3DSIO_TEXM3x3TEX ),
+ VE( D3DSIO_TEXM3x3VSPEC ),
+ VE( D3DSIO_TEXREG2AR ),
+ VE( D3DSIO_TEXREG2GB ),
+ VE( D3DSIO_TEXREG2RGB ),
+ VE( D3DSIO_LABEL ),
+ VE( D3DSIO_CALL ),
+ VE( D3DSIO_IF ),
+ VE( D3DSIO_LOOP ),
+ VE( D3DSIO_REP ),
+ VE( D3DSIO_BREAKP ),
+ VE( D3DSIO_DSX ),
+ VE( D3DSIO_DSY ),
+ VE( D3DSIO_NRM ),
+ VE( D3DSIO_MOVA ),
+ VE( D3DSIO_MOV ),
+ VE( D3DSIO_RCP ),
+ VE( D3DSIO_RSQ ),
+ VE( D3DSIO_EXP ),
+ VE( D3DSIO_EXPP ),
+ VE( D3DSIO_LOG ),
+ VE( D3DSIO_LOGP ),
+ VE( D3DSIO_FRC ),
+ VE( D3DSIO_LIT ),
+ VE( D3DSIO_ABS ),
+ VE( D3DSIO_TEXM3x3SPEC ),
+ VE( D3DSIO_M4x4 ),
+ VE( D3DSIO_M4x3 ),
+ VE( D3DSIO_M3x4 ),
+ VE( D3DSIO_M3x3 ),
+ VE( D3DSIO_M3x2 ),
+ VE( D3DSIO_CALLNZ ),
+ VE( D3DSIO_IFC ),
+ VE( D3DSIO_BREAKC ),
+ VE( D3DSIO_SETP ),
+ VE( D3DSIO_TEXLDL ),
+ VE( D3DSIO_ADD ),
+ VE( D3DSIO_SUB ),
+ VE( D3DSIO_MUL ),
+ VE( D3DSIO_DP3 ),
+ VE( D3DSIO_DP4 ),
+ VE( D3DSIO_MIN ),
+ VE( D3DSIO_MAX ),
+ VE( D3DSIO_DST ),
+ VE( D3DSIO_SLT ),
+ VE( D3DSIO_SGE ),
+ VE( D3DSIO_CRS ),
+ VE( D3DSIO_POW ),
+ VE( D3DSIO_DP2ADD ),
+ VE( D3DSIO_LRP ),
+ VE( D3DSIO_SGN ),
+ VE( D3DSIO_CND ),
+ VE( D3DSIO_CMP ),
+ VE( D3DSIO_SINCOS ),
+ VE( D3DSIO_MAD ),
+ VE( D3DSIO_TEXLDD ),
+ VE( D3DSIO_TEXCOORD ),
+ VE( D3DSIO_TEX ),
+ VE( D3DSIO_DCL ),
+ VE( D3DSTT_UNKNOWN ),
+ VE( D3DSTT_2D ),
+ VE( D3DSTT_CUBE ),
+ VE( D3DSTT_VOLUME ),
+ VE( D3DSIO_DEFB ),
+ VE( D3DSIO_DEFI ),
+ VE( D3DSIO_DEF ),
+ VE( D3DSIO_COMMENT ),
+ VE( D3DSIO_END ),
+};
+
+
+GLMValueEntry_t g_d3d_vtxdeclusages[] =
+{
+ { D3DDECLUSAGE_POSITION ,"POSN" }, // P
+ { D3DDECLUSAGE_BLENDWEIGHT ,"BLWT" }, // W
+ { D3DDECLUSAGE_BLENDINDICES ,"BLIX" }, // I
+ { D3DDECLUSAGE_NORMAL ,"NORM" }, // N
+ { D3DDECLUSAGE_PSIZE ,"PSIZ" }, // S
+ { D3DDECLUSAGE_TEXCOORD ,"TEXC" }, // T
+ { D3DDECLUSAGE_TANGENT ,"TANG" }, // G
+ { D3DDECLUSAGE_BINORMAL ,"BINO" }, // B
+ { D3DDECLUSAGE_TESSFACTOR ,"TESS" }, // S
+ { D3DDECLUSAGE_PLUGH ,"????" }, // ?
+ { D3DDECLUSAGE_COLOR ,"COLR" }, // C
+ { D3DDECLUSAGE_FOG ,"FOG " }, // F
+ { D3DDECLUSAGE_DEPTH ,"DEPT" }, // D
+ { D3DDECLUSAGE_SAMPLE ,"SAMP" } // M
+};
+
+GLMValueEntry_t g_d3d_vtxdeclusages_short[] =
+{
+ { D3DDECLUSAGE_POSITION ,"P" },
+ { D3DDECLUSAGE_BLENDWEIGHT ,"W" },
+ { D3DDECLUSAGE_BLENDINDICES ,"I" },
+ { D3DDECLUSAGE_NORMAL ,"N" },
+ { D3DDECLUSAGE_PSIZE ,"S" },
+ { D3DDECLUSAGE_TEXCOORD ,"T" },
+ { D3DDECLUSAGE_TANGENT ,"G" },
+ { D3DDECLUSAGE_BINORMAL ,"B" },
+ { D3DDECLUSAGE_TESSFACTOR ,"S" },
+ { D3DDECLUSAGE_PLUGH ,"?" },
+ { D3DDECLUSAGE_COLOR ,"C" },
+ { D3DDECLUSAGE_FOG ,"F" },
+ { D3DDECLUSAGE_DEPTH ,"D" },
+ { D3DDECLUSAGE_SAMPLE ,"M" }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+GLMValueEntry_t g_cgl_rendids[] = // need to mask with 0xFFFFFF00 to match on these (ex: 8800GT == 0x00022608
+{
+ VE( kCGLRendererGenericID ),
+ VE( kCGLRendererGenericFloatID ),
+ VE( kCGLRendererAppleSWID ),
+ VE( kCGLRendererATIRage128ID ),
+ VE( kCGLRendererATIRadeonID ),
+ VE( kCGLRendererATIRageProID ),
+ VE( kCGLRendererATIRadeon8500ID ),
+ VE( kCGLRendererATIRadeon9700ID ),
+ VE( kCGLRendererATIRadeonX1000ID ),
+ VE( kCGLRendererATIRadeonX2000ID ),
+ VE( kCGLRendererGeForce2MXID ),
+ VE( kCGLRendererGeForce3ID ),
+ VE( kCGLRendererGeForceFXID ), // also for GF6 and GF7
+ VE( kCGLRendererGeForce8xxxID ),
+ VE( kCGLRendererVTBladeXP2ID ),
+ VE( kCGLRendererIntel900ID ),
+ VE( kCGLRendererMesa3DFXID ),
+
+ VE( TERMVALUE )
+};
+#pragma clang diagnostic pop
+
+GLMValueEntry_t g_gl_errors[] =
+{
+ VE( GL_INVALID_ENUM ),
+ VE( GL_INVALID_VALUE ),
+ VE( GL_INVALID_OPERATION ),
+ VE( GL_STACK_OVERFLOW ),
+ VE( GL_STACK_UNDERFLOW ),
+ VE( GL_OUT_OF_MEMORY ),
+ VE( GL_INVALID_FRAMEBUFFER_OPERATION_EXT ),
+ VE( GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT ),
+ VE( GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT ),
+ VE( GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT ),
+ VE( GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT ),
+ VE( GL_FRAMEBUFFER_UNSUPPORTED_EXT ),
+ VE( GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT ),
+ VE( GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT )
+};
+
+// there are some ARB/EXT dupes in this table but that doesn't matter too much
+GLMValueEntry_t g_gl_enums[] =
+{
+ { 0x0000, "GL_ZERO" },
+ { 0x0001, "GL_ONE" },
+ { 0x0004, "GL_TRIANGLES" },
+ { 0x0005, "GL_TRIANGLE_STRIP" },
+ { 0x0006, "GL_TRIANGLE_FAN" },
+ { 0x0007, "GL_QUADS" },
+ { 0x0008, "GL_QUAD_STRIP" },
+ { 0x0009, "GL_POLYGON" },
+ { 0x0200, "GL_NEVER" },
+ { 0x0201, "GL_LESS" },
+ { 0x0202, "GL_EQUAL" },
+ { 0x0203, "GL_LEQUAL" },
+ { 0x0204, "GL_GREATER" },
+ { 0x0205, "GL_NOTEQUAL" },
+ { 0x0206, "GL_GEQUAL" },
+ { 0x0207, "GL_ALWAYS" },
+ { 0x0300, "GL_SRC_COLOR" },
+ { 0x0301, "GL_ONE_MINUS_SRC_COLOR" },
+ { 0x0302, "GL_SRC_ALPHA" },
+ { 0x0303, "GL_ONE_MINUS_SRC_ALPHA" },
+ { 0x0304, "GL_DST_ALPHA" },
+ { 0x0305, "GL_ONE_MINUS_DST_ALPHA" },
+ { 0x0306, "GL_DST_COLOR" },
+ { 0x0307, "GL_ONE_MINUS_DST_COLOR" },
+ { 0x0308, "GL_SRC_ALPHA_SATURATE" },
+ { 0x0400, "GL_FRONT_LEFT" },
+ { 0x0401, "GL_FRONT_RIGHT" },
+ { 0x0402, "GL_BACK_LEFT" },
+ { 0x0403, "GL_BACK_RIGHT" },
+ { 0x0404, "GL_FRONT" },
+ { 0x0405, "GL_BACK" },
+ { 0x0406, "GL_LEFT" },
+ { 0x0407, "GL_RIGHT" },
+ { 0x0408, "GL_FRONT_AND_BACK" },
+ { 0x0409, "GL_AUX0" },
+ { 0x040A, "GL_AUX1" },
+ { 0x040B, "GL_AUX2" },
+ { 0x040C, "GL_AUX3" },
+ { 0x0500, "GL_INVALID_ENUM" },
+ { 0x0501, "GL_INVALID_VALUE" },
+ { 0x0502, "GL_INVALID_OPERATION" },
+ { 0x0503, "GL_STACK_OVERFLOW" },
+ { 0x0504, "GL_STACK_UNDERFLOW" },
+ { 0x0505, "GL_OUT_OF_MEMORY" },
+ { 0x0506, "GL_INVALID_FRAMEBUFFER_OPERATION" },
+ { 0x0600, "GL_2D" },
+ { 0x0601, "GL_3D" },
+ { 0x0602, "GL_3D_COLOR" },
+ { 0x0603, "GL_3D_COLOR_TEXTURE" },
+ { 0x0604, "GL_4D_COLOR_TEXTURE" },
+ { 0x0700, "GL_PASS_THROUGH_TOKEN" },
+ { 0x0701, "GL_POINT_TOKEN" },
+ { 0x0702, "GL_LINE_TOKEN" },
+ { 0x0703, "GL_POLYGON_TOKEN" },
+ { 0x0704, "GL_BITMAP_TOKEN" },
+ { 0x0705, "GL_DRAW_PIXEL_TOKEN" },
+ { 0x0706, "GL_COPY_PIXEL_TOKEN" },
+ { 0x0707, "GL_LINE_RESET_TOKEN" },
+ { 0x0800, "GL_EXP" },
+ { 0x0801, "GL_EXP2" },
+ { 0x0900, "GL_CW" },
+ { 0x0901, "GL_CCW" },
+ { 0x0A00, "GL_COEFF" },
+ { 0x0A01, "GL_ORDER" },
+ { 0x0A02, "GL_DOMAIN" },
+ { 0x0B00, "GL_CURRENT_COLOR" },
+ { 0x0B01, "GL_CURRENT_INDEX" },
+ { 0x0B02, "GL_CURRENT_NORMAL" },
+ { 0x0B03, "GL_CURRENT_TEXTURE_COORDS" },
+ { 0x0B04, "GL_CURRENT_RASTER_COLOR" },
+ { 0x0B05, "GL_CURRENT_RASTER_INDEX" },
+ { 0x0B06, "GL_CURRENT_RASTER_TEXTURE_COORDS" },
+ { 0x0B07, "GL_CURRENT_RASTER_POSITION" },
+ { 0x0B08, "GL_CURRENT_RASTER_POSITION_VALID" },
+ { 0x0B09, "GL_CURRENT_RASTER_DISTANCE" },
+ { 0x0B10, "GL_POINT_SMOOTH" },
+ { 0x0B11, "GL_POINT_SIZE" },
+ { 0x0B12, "GL_POINT_SIZE_RANGE" },
+ { 0x0B12, "GL_SMOOTH_POINT_SIZE_RANGE" },
+ { 0x0B13, "GL_POINT_SIZE_GRANULARITY" },
+ { 0x0B13, "GL_SMOOTH_POINT_SIZE_GRANULARITY" },
+ { 0x0B20, "GL_LINE_SMOOTH" },
+ { 0x0B21, "GL_LINE_WIDTH" },
+ { 0x0B22, "GL_LINE_WIDTH_RANGE" },
+ { 0x0B22, "GL_SMOOTH_LINE_WIDTH_RANGE" },
+ { 0x0B23, "GL_LINE_WIDTH_GRANULARITY" },
+ { 0x0B23, "GL_SMOOTH_LINE_WIDTH_GRANULARITY" },
+ { 0x0B24, "GL_LINE_STIPPLE" },
+ { 0x0B25, "GL_LINE_STIPPLE_PATTERN" },
+ { 0x0B26, "GL_LINE_STIPPLE_REPEAT" },
+ { 0x0B30, "GL_LIST_MODE" },
+ { 0x0B31, "GL_MAX_LIST_NESTING" },
+ { 0x0B32, "GL_LIST_BASE" },
+ { 0x0B33, "GL_LIST_INDEX" },
+ { 0x0B40, "GL_POLYGON_MODE" },
+ { 0x0B41, "GL_POLYGON_SMOOTH" },
+ { 0x0B42, "GL_POLYGON_STIPPLE" },
+ { 0x0B43, "GL_EDGE_FLAG" },
+ { 0x0B44, "GL_CULL_FACE" },
+ { 0x0B45, "GL_CULL_FACE_MODE" },
+ { 0x0B46, "GL_FRONT_FACE" },
+ { 0x0B50, "GL_LIGHTING" },
+ { 0x0B51, "GL_LIGHT_MODEL_LOCAL_VIEWER" },
+ { 0x0B52, "GL_LIGHT_MODEL_TWO_SIDE" },
+ { 0x0B53, "GL_LIGHT_MODEL_AMBIENT" },
+ { 0x0B54, "GL_SHADE_MODEL" },
+ { 0x0B55, "GL_COLOR_MATERIAL_FACE" },
+ { 0x0B56, "GL_COLOR_MATERIAL_PARAMETER" },
+ { 0x0B57, "GL_COLOR_MATERIAL" },
+ { 0x0B60, "GL_FOG" },
+ { 0x0B61, "GL_FOG_INDEX" },
+ { 0x0B62, "GL_FOG_DENSITY" },
+ { 0x0B63, "GL_FOG_START" },
+ { 0x0B64, "GL_FOG_END" },
+ { 0x0B65, "GL_FOG_MODE" },
+ { 0x0B66, "GL_FOG_COLOR" },
+ { 0x0B70, "GL_DEPTH_RANGE" },
+ { 0x0B71, "GL_DEPTH_TEST" },
+ { 0x0B72, "GL_DEPTH_WRITEMASK" },
+ { 0x0B73, "GL_DEPTH_CLEAR_VALUE" },
+ { 0x0B74, "GL_DEPTH_FUNC" },
+ { 0x0B80, "GL_ACCUM_CLEAR_VALUE" },
+ { 0x0B90, "GL_STENCIL_TEST" },
+ { 0x0B91, "GL_STENCIL_CLEAR_VALUE" },
+ { 0x0B92, "GL_STENCIL_FUNC" },
+ { 0x0B93, "GL_STENCIL_VALUE_MASK" },
+ { 0x0B94, "GL_STENCIL_FAIL" },
+ { 0x0B95, "GL_STENCIL_PASS_DEPTH_FAIL" },
+ { 0x0B96, "GL_STENCIL_PASS_DEPTH_PASS" },
+ { 0x0B97, "GL_STENCIL_REF" },
+ { 0x0B98, "GL_STENCIL_WRITEMASK" },
+ { 0x0BA0, "GL_MATRIX_MODE" },
+ { 0x0BA1, "GL_NORMALIZE" },
+ { 0x0BA2, "GL_VIEWPORT" },
+ { 0x0BA3, "GL_MODELVIEW_STACK_DEPTH" },
+ { 0x0BA4, "GL_PROJECTION_STACK_DEPTH" },
+ { 0x0BA5, "GL_TEXTURE_STACK_DEPTH" },
+ { 0x0BA6, "GL_MODELVIEW_MATRIX" },
+ { 0x0BA7, "GL_PROJECTION_MATRIX" },
+ { 0x0BA8, "GL_TEXTURE_MATRIX" },
+ { 0x0BB0, "GL_ATTRIB_STACK_DEPTH" },
+ { 0x0BB1, "GL_CLIENT_ATTRIB_STACK_DEPTH" },
+ { 0x0BC0, "GL_ALPHA_TEST" },
+ { 0x0BC1, "GL_ALPHA_TEST_FUNC" },
+ { 0x0BC2, "GL_ALPHA_TEST_REF" },
+ { 0x0BD0, "GL_DITHER" },
+ { 0x0BE0, "GL_BLEND_DST" },
+ { 0x0BE1, "GL_BLEND_SRC" },
+ { 0x0BE2, "GL_BLEND" },
+ { 0x0BF0, "GL_LOGIC_OP_MODE" },
+ { 0x0BF1, "GL_INDEX_LOGIC_OP" },
+ { 0x0BF2, "GL_COLOR_LOGIC_OP" },
+ { 0x0C00, "GL_AUX_BUFFERS" },
+ { 0x0C01, "GL_DRAW_BUFFER" },
+ { 0x0C02, "GL_READ_BUFFER" },
+ { 0x0C10, "GL_SCISSOR_BOX" },
+ { 0x0C11, "GL_SCISSOR_TEST" },
+ { 0x0C20, "GL_INDEX_CLEAR_VALUE" },
+ { 0x0C21, "GL_INDEX_WRITEMASK" },
+ { 0x0C22, "GL_COLOR_CLEAR_VALUE" },
+ { 0x0C23, "GL_COLOR_WRITEMASK" },
+ { 0x0C30, "GL_INDEX_MODE" },
+ { 0x0C31, "GL_RGBA_MODE" },
+ { 0x0C32, "GL_DOUBLEBUFFER" },
+ { 0x0C33, "GL_STEREO" },
+ { 0x0C40, "GL_RENDER_MODE" },
+ { 0x0C50, "GL_PERSPECTIVE_CORRECTION_HINT" },
+ { 0x0C51, "GL_POINT_SMOOTH_HINT" },
+ { 0x0C52, "GL_LINE_SMOOTH_HINT" },
+ { 0x0C53, "GL_POLYGON_SMOOTH_HINT" },
+ { 0x0C54, "GL_FOG_HINT" },
+ { 0x0C60, "GL_TEXTURE_GEN_S" },
+ { 0x0C61, "GL_TEXTURE_GEN_T" },
+ { 0x0C62, "GL_TEXTURE_GEN_R" },
+ { 0x0C63, "GL_TEXTURE_GEN_Q" },
+ { 0x0C70, "GL_PIXEL_MAP_I_TO_I" },
+ { 0x0C71, "GL_PIXEL_MAP_S_TO_S" },
+ { 0x0C72, "GL_PIXEL_MAP_I_TO_R" },
+ { 0x0C73, "GL_PIXEL_MAP_I_TO_G" },
+ { 0x0C74, "GL_PIXEL_MAP_I_TO_B" },
+ { 0x0C75, "GL_PIXEL_MAP_I_TO_A" },
+ { 0x0C76, "GL_PIXEL_MAP_R_TO_R" },
+ { 0x0C77, "GL_PIXEL_MAP_G_TO_G" },
+ { 0x0C78, "GL_PIXEL_MAP_B_TO_B" },
+ { 0x0C79, "GL_PIXEL_MAP_A_TO_A" },
+ { 0x0CB0, "GL_PIXEL_MAP_I_TO_I_SIZE" },
+ { 0x0CB1, "GL_PIXEL_MAP_S_TO_S_SIZE" },
+ { 0x0CB2, "GL_PIXEL_MAP_I_TO_R_SIZE" },
+ { 0x0CB3, "GL_PIXEL_MAP_I_TO_G_SIZE" },
+ { 0x0CB4, "GL_PIXEL_MAP_I_TO_B_SIZE" },
+ { 0x0CB5, "GL_PIXEL_MAP_I_TO_A_SIZE" },
+ { 0x0CB6, "GL_PIXEL_MAP_R_TO_R_SIZE" },
+ { 0x0CB7, "GL_PIXEL_MAP_G_TO_G_SIZE" },
+ { 0x0CB8, "GL_PIXEL_MAP_B_TO_B_SIZE" },
+ { 0x0CB9, "GL_PIXEL_MAP_A_TO_A_SIZE" },
+ { 0x0CF0, "GL_UNPACK_SWAP_BYTES" },
+ { 0x0CF1, "GL_UNPACK_LSB_FIRST" },
+ { 0x0CF2, "GL_UNPACK_ROW_LENGTH" },
+ { 0x0CF3, "GL_UNPACK_SKIP_ROWS" },
+ { 0x0CF4, "GL_UNPACK_SKIP_PIXELS" },
+ { 0x0CF5, "GL_UNPACK_ALIGNMENT" },
+ { 0x0D00, "GL_PACK_SWAP_BYTES" },
+ { 0x0D01, "GL_PACK_LSB_FIRST" },
+ { 0x0D02, "GL_PACK_ROW_LENGTH" },
+ { 0x0D03, "GL_PACK_SKIP_ROWS" },
+ { 0x0D04, "GL_PACK_SKIP_PIXELS" },
+ { 0x0D05, "GL_PACK_ALIGNMENT" },
+ { 0x0D10, "GL_MAP_COLOR" },
+ { 0x0D11, "GL_MAP_STENCIL" },
+ { 0x0D12, "GL_INDEX_SHIFT" },
+ { 0x0D13, "GL_INDEX_OFFSET" },
+ { 0x0D14, "GL_RED_SCALE" },
+ { 0x0D15, "GL_RED_BIAS" },
+ { 0x0D16, "GL_ZOOM_X" },
+ { 0x0D17, "GL_ZOOM_Y" },
+ { 0x0D18, "GL_GREEN_SCALE" },
+ { 0x0D19, "GL_GREEN_BIAS" },
+ { 0x0D1A, "GL_BLUE_SCALE" },
+ { 0x0D1B, "GL_BLUE_BIAS" },
+ { 0x0D1C, "GL_ALPHA_SCALE" },
+ { 0x0D1D, "GL_ALPHA_BIAS" },
+ { 0x0D1E, "GL_DEPTH_SCALE" },
+ { 0x0D1F, "GL_DEPTH_BIAS" },
+ { 0x0D30, "GL_MAX_EVAL_ORDER" },
+ { 0x0D31, "GL_MAX_LIGHTS" },
+ { 0x0D32, "GL_MAX_CLIP_PLANES" },
+ { 0x0D33, "GL_MAX_TEXTURE_SIZE" },
+ { 0x0D34, "GL_MAX_PIXEL_MAP_TABLE" },
+ { 0x0D35, "GL_MAX_ATTRIB_STACK_DEPTH" },
+ { 0x0D36, "GL_MAX_MODELVIEW_STACK_DEPTH" },
+ { 0x0D37, "GL_MAX_NAME_STACK_DEPTH" },
+ { 0x0D38, "GL_MAX_PROJECTION_STACK_DEPTH" },
+ { 0x0D39, "GL_MAX_TEXTURE_STACK_DEPTH" },
+ { 0x0D3A, "GL_MAX_VIEWPORT_DIMS" },
+ { 0x0D3B, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH" },
+ { 0x0D50, "GL_SUBPIXEL_BITS" },
+ { 0x0D51, "GL_INDEX_BITS" },
+ { 0x0D52, "GL_RED_BITS" },
+ { 0x0D53, "GL_GREEN_BITS" },
+ { 0x0D54, "GL_BLUE_BITS" },
+ { 0x0D55, "GL_ALPHA_BITS" },
+ { 0x0D56, "GL_DEPTH_BITS" },
+ { 0x0D57, "GL_STENCIL_BITS" },
+ { 0x0D58, "GL_ACCUM_RED_BITS" },
+ { 0x0D59, "GL_ACCUM_GREEN_BITS" },
+ { 0x0D5A, "GL_ACCUM_BLUE_BITS" },
+ { 0x0D5B, "GL_ACCUM_ALPHA_BITS" },
+ { 0x0D70, "GL_NAME_STACK_DEPTH" },
+ { 0x0D80, "GL_AUTO_NORMAL" },
+ { 0x0D90, "GL_MAP1_COLOR_4" },
+ { 0x0D91, "GL_MAP1_INDEX" },
+ { 0x0D92, "GL_MAP1_NORMAL" },
+ { 0x0D93, "GL_MAP1_TEXTURE_COORD_1" },
+ { 0x0D94, "GL_MAP1_TEXTURE_COORD_2" },
+ { 0x0D95, "GL_MAP1_TEXTURE_COORD_3" },
+ { 0x0D96, "GL_MAP1_TEXTURE_COORD_4" },
+ { 0x0D97, "GL_MAP1_VERTEX_3" },
+ { 0x0D98, "GL_MAP1_VERTEX_4" },
+ { 0x0DB0, "GL_MAP2_COLOR_4" },
+ { 0x0DB1, "GL_MAP2_INDEX" },
+ { 0x0DB2, "GL_MAP2_NORMAL" },
+ { 0x0DB3, "GL_MAP2_TEXTURE_COORD_1" },
+ { 0x0DB4, "GL_MAP2_TEXTURE_COORD_2" },
+ { 0x0DB5, "GL_MAP2_TEXTURE_COORD_3" },
+ { 0x0DB6, "GL_MAP2_TEXTURE_COORD_4" },
+ { 0x0DB7, "GL_MAP2_VERTEX_3" },
+ { 0x0DB8, "GL_MAP2_VERTEX_4" },
+ { 0x0DD0, "GL_MAP1_GRID_DOMAIN" },
+ { 0x0DD1, "GL_MAP1_GRID_SEGMENTS" },
+ { 0x0DD2, "GL_MAP2_GRID_DOMAIN" },
+ { 0x0DD3, "GL_MAP2_GRID_SEGMENTS" },
+ { 0x0DE0, "GL_TEXTURE_1D" },
+ { 0x0DE1, "GL_TEXTURE_2D" },
+ { 0x0DF0, "GL_FEEDBACK_BUFFER_POINTER" },
+ { 0x0DF1, "GL_FEEDBACK_BUFFER_SIZE" },
+ { 0x0DF2, "GL_FEEDBACK_BUFFER_TYPE" },
+ { 0x0DF3, "GL_SELECTION_BUFFER_POINTER" },
+ { 0x0DF4, "GL_SELECTION_BUFFER_SIZE" },
+ { 0x1000, "GL_TEXTURE_WIDTH" },
+ { 0x1001, "GL_TEXTURE_HEIGHT" },
+ { 0x1003, "GL_TEXTURE_INTERNAL_FORMAT" },
+ { 0x1004, "GL_TEXTURE_BORDER_COLOR" },
+ { 0x1005, "GL_TEXTURE_BORDER" },
+ { 0x1100, "GL_DONT_CARE" },
+ { 0x1101, "GL_FASTEST" },
+ { 0x1102, "GL_NICEST" },
+ { 0x1200, "GL_AMBIENT" },
+ { 0x1201, "GL_DIFFUSE" },
+ { 0x1202, "GL_SPECULAR" },
+ { 0x1203, "GL_POSITION" },
+ { 0x1204, "GL_SPOT_DIRECTION" },
+ { 0x1205, "GL_SPOT_EXPONENT" },
+ { 0x1206, "GL_SPOT_CUTOFF" },
+ { 0x1207, "GL_CONSTANT_ATTENUATION" },
+ { 0x1208, "GL_LINEAR_ATTENUATION" },
+ { 0x1209, "GL_QUADRATIC_ATTENUATION" },
+ { 0x1300, "GL_COMPILE" },
+ { 0x1301, "GL_COMPILE_AND_EXECUTE" },
+ { 0x1400, "GL_BYTE " },
+ { 0x1401, "GL_UBYTE" },
+ { 0x1402, "GL_SHORT" },
+ { 0x1403, "GL_USHRT" },
+ { 0x1404, "GL_INT " },
+ { 0x1405, "GL_UINT " },
+ { 0x1406, "GL_FLOAT" },
+ { 0x1407, "GL_2_BYTES" },
+ { 0x1408, "GL_3_BYTES" },
+ { 0x1409, "GL_4_BYTES" },
+ { 0x140A, "GL_DOUBLE" },
+ { 0x140B, "GL_HALF_FLOAT" },
+ { 0x1500, "GL_CLEAR" },
+ { 0x1501, "GL_AND" },
+ { 0x1502, "GL_AND_REVERSE" },
+ { 0x1503, "GL_COPY" },
+ { 0x1504, "GL_AND_INVERTED" },
+ { 0x1505, "GL_NOOP" },
+ { 0x1506, "GL_XOR" },
+ { 0x1507, "GL_OR" },
+ { 0x1508, "GL_NOR" },
+ { 0x1509, "GL_EQUIV" },
+ { 0x150A, "GL_INVERT" },
+ { 0x150B, "GL_OR_REVERSE" },
+ { 0x150C, "GL_COPY_INVERTED" },
+ { 0x150D, "GL_OR_INVERTED" },
+ { 0x150E, "GL_NAND" },
+ { 0x150F, "GL_SET" },
+ { 0x1600, "GL_EMISSION" },
+ { 0x1601, "GL_SHININESS" },
+ { 0x1602, "GL_AMBIENT_AND_DIFFUSE" },
+ { 0x1603, "GL_COLOR_INDEXES" },
+ { 0x1700, "GL_MODELVIEW" },
+ { 0x1700, "GL_MODELVIEW0_ARB" },
+ { 0x1701, "GL_PROJECTION" },
+ { 0x1702, "GL_TEXTURE" },
+ { 0x1800, "GL_COLOR" },
+ { 0x1801, "GL_DEPTH" },
+ { 0x1802, "GL_STENCIL" },
+ { 0x1900, "GL_COLOR_INDEX" },
+ { 0x1901, "GL_STENCIL_INDEX" },
+ { 0x1902, "GL_DEPTH_COMPONENT" },
+ { 0x1903, "GL_RED" },
+ { 0x1904, "GL_GREEN" },
+ { 0x1905, "GL_BLUE" },
+ { 0x1906, "GL_ALPHA" },
+ { 0x1907, "GL_RGB" },
+ { 0x1908, "GL_RGBA" },
+ { 0x1909, "GL_LUMINANCE" },
+ { 0x190A, "GL_LUMINANCE_ALPHA" },
+ { 0x1A00, "GL_BITMAP" },
+ { 0x1B00, "GL_POINT" },
+ { 0x1B01, "GL_LINE" },
+ { 0x1B02, "GL_FILL" },
+ { 0x1C00, "GL_RENDER" },
+ { 0x1C01, "GL_FEEDBACK" },
+ { 0x1C02, "GL_SELECT" },
+ { 0x1D00, "GL_FLAT" },
+ { 0x1D01, "GL_SMOOTH" },
+ { 0x1E00, "GL_KEEP" },
+ { 0x1E01, "GL_REPLACE" },
+ { 0x1E02, "GL_INCR" },
+ { 0x1E03, "GL_DECR" },
+ { 0x1F00, "GL_VENDOR" },
+ { 0x1F01, "GL_RENDERER" },
+ { 0x1F02, "GL_VERSION" },
+ { 0x1F03, "GL_EXTENSIONS" },
+ { 0x2000, "GL_S" },
+ { 0x2001, "GL_T" },
+ { 0x2002, "GL_R" },
+ { 0x2003, "GL_Q" },
+ { 0x2100, "GL_MODULATE" },
+ { 0x2101, "GL_DECAL" },
+ { 0x2200, "GL_TEXTURE_ENV_MODE" },
+ { 0x2201, "GL_TEXTURE_ENV_COLOR" },
+ { 0x2300, "GL_TEXTURE_ENV" },
+ { 0x2400, "GL_EYE_LINEAR" },
+ { 0x2401, "GL_OBJECT_LINEAR" },
+ { 0x2402, "GL_SPHERE_MAP" },
+ { 0x2500, "GL_TEXTURE_GEN_MODE" },
+ { 0x2501, "GL_OBJECT_PLANE" },
+ { 0x2502, "GL_EYE_PLANE" },
+ { 0x2600, "GL_NEAREST" },
+ { 0x2601, "GL_LINEAR" },
+ { 0x2700, "GL_NEAREST_MIPMAP_NEAREST" },
+ { 0x2701, "GL_LINEAR_MIPMAP_NEAREST" },
+ { 0x2702, "GL_NEAREST_MIPMAP_LINEAR" },
+ { 0x2703, "GL_LINEAR_MIPMAP_LINEAR" },
+ { 0x2800, "GL_TEXTURE_MAG_FILTER" },
+ { 0x2801, "GL_TEXTURE_MIN_FILTER" },
+ { 0x2802, "GL_TEXTURE_WRAP_S" },
+ { 0x2803, "GL_TEXTURE_WRAP_T" },
+ { 0x2900, "GL_CLAMP" },
+ { 0x2901, "GL_REPEAT" },
+ { 0x2A00, "GL_POLYGON_OFFSET_UNITS" },
+ { 0x2A01, "GL_POLYGON_OFFSET_POINT" },
+ { 0x2A02, "GL_POLYGON_OFFSET_LINE" },
+ { 0x2A10, "GL_R3_G3_B2" },
+ { 0x2A20, "GL_V2F" },
+ { 0x2A21, "GL_V3F" },
+ { 0x2A22, "GL_C4UB_V2F" },
+ { 0x2A23, "GL_C4UB_V3F" },
+ { 0x2A24, "GL_C3F_V3F" },
+ { 0x2A25, "GL_N3F_V3F" },
+ { 0x2A26, "GL_C4F_N3F_V3F" },
+ { 0x2A27, "GL_T2F_V3F" },
+ { 0x2A28, "GL_T4F_V4F" },
+ { 0x2A29, "GL_T2F_C4UB_V3F" },
+ { 0x2A2A, "GL_T2F_C3F_V3F" },
+ { 0x2A2B, "GL_T2F_N3F_V3F" },
+ { 0x2A2C, "GL_T2F_C4F_N3F_V3F" },
+ { 0x2A2D, "GL_T4F_C4F_N3F_V4F" },
+ { 0x3000, "GL_CLIP_PLANE0" },
+ { 0x3001, "GL_CLIP_PLANE1" },
+ { 0x3002, "GL_CLIP_PLANE2" },
+ { 0x3003, "GL_CLIP_PLANE3" },
+ { 0x3004, "GL_CLIP_PLANE4" },
+ { 0x3005, "GL_CLIP_PLANE5" },
+ { 0x4000, "GL_LIGHT0" },
+ { 0x4001, "GL_LIGHT1" },
+ { 0x4002, "GL_LIGHT2" },
+ { 0x4003, "GL_LIGHT3" },
+ { 0x4004, "GL_LIGHT4" },
+ { 0x4005, "GL_LIGHT5" },
+ { 0x4006, "GL_LIGHT6" },
+ { 0x4007, "GL_LIGHT7" },
+ { 0x8000, "GL_ABGR_EXT" },
+ { 0x8001, "GL_CONSTANT_COLOR" },
+ { 0x8002, "GL_ONE_MINUS_CONSTANT_COLOR" },
+ { 0x8003, "GL_CONSTANT_ALPHA" },
+ { 0x8004, "GL_ONE_MINUS_CONSTANT_ALPHA" },
+ { 0x8005, "GL_BLEND_COLOR" },
+ { 0x8006, "GL_FUNC_ADD" },
+ { 0x8007, "GL_MIN" },
+ { 0x8008, "GL_MAX" },
+ { 0x8009, "GL_BLEND_EQUATION_RGB" },
+ { 0x8009, "GL_BLEND_EQUATION" },
+ { 0x800A, "GL_FUNC_SUBTRACT" },
+ { 0x800B, "GL_FUNC_REVERSE_SUBTRACT" },
+ { 0x8010, "GL_CONVOLUTION_1D" },
+ { 0x8011, "GL_CONVOLUTION_2D" },
+ { 0x8012, "GL_SEPARABLE_2D" },
+ { 0x8013, "GL_CONVOLUTION_BORDER_MODE" },
+ { 0x8014, "GL_CONVOLUTION_FILTER_SCALE" },
+ { 0x8015, "GL_CONVOLUTION_FILTER_BIAS" },
+ { 0x8016, "GL_REDUCE" },
+ { 0x8017, "GL_CONVOLUTION_FORMAT" },
+ { 0x8018, "GL_CONVOLUTION_WIDTH" },
+ { 0x8019, "GL_CONVOLUTION_HEIGHT" },
+ { 0x801A, "GL_MAX_CONVOLUTION_WIDTH" },
+ { 0x801B, "GL_MAX_CONVOLUTION_HEIGHT" },
+ { 0x801C, "GL_POST_CONVOLUTION_RED_SCALE" },
+ { 0x801D, "GL_POST_CONVOLUTION_GREEN_SCALE" },
+ { 0x801E, "GL_POST_CONVOLUTION_BLUE_SCALE" },
+ { 0x801F, "GL_POST_CONVOLUTION_ALPHA_SCALE" },
+ { 0x8020, "GL_POST_CONVOLUTION_RED_BIAS" },
+ { 0x8021, "GL_POST_CONVOLUTION_GREEN_BIAS" },
+ { 0x8022, "GL_POST_CONVOLUTION_BLUE_BIAS" },
+ { 0x8023, "GL_POST_CONVOLUTION_ALPHA_BIAS" },
+ { 0x8024, "GL_HISTOGRAM" },
+ { 0x8025, "GL_PROXY_HISTOGRAM" },
+ { 0x8026, "GL_HISTOGRAM_WIDTH" },
+ { 0x8027, "GL_HISTOGRAM_FORMAT" },
+ { 0x8028, "GL_HISTOGRAM_RED_SIZE" },
+ { 0x8029, "GL_HISTOGRAM_GREEN_SIZE" },
+ { 0x802A, "GL_HISTOGRAM_BLUE_SIZE" },
+ { 0x802B, "GL_HISTOGRAM_ALPHA_SIZE" },
+ { 0x802C, "GL_HISTOGRAM_LUMINANCE_SIZE" },
+ { 0x802D, "GL_HISTOGRAM_SINK" },
+ { 0x802E, "GL_MINMAX" },
+ { 0x802F, "GL_MINMAX_FORMAT" },
+ { 0x8030, "GL_MINMAX_SINK" },
+ { 0x8031, "GL_TABLE_TOO_LARGE" },
+ { 0x8032, "GL_UNSIGNED_BYTE_3_3_2" },
+ { 0x8033, "GL_UNSIGNED_SHORT_4_4_4_4" },
+ { 0x8034, "GL_UNSIGNED_SHORT_5_5_5_1" },
+ { 0x8035, "GL_UNSIGNED_INT_8_8_8_8" },
+ { 0x8036, "GL_UNSIGNED_INT_10_10_10_2" },
+ { 0x8037, "GL_POLYGON_OFFSET_FILL" },
+ { 0x8038, "GL_POLYGON_OFFSET_FACTOR" },
+ { 0x803A, "GL_RESCALE_NORMAL" },
+ { 0x803B, "GL_ALPHA4" },
+ { 0x803C, "GL_ALPHA8" },
+ { 0x803D, "GL_ALPHA12" },
+ { 0x803E, "GL_ALPHA16" },
+ { 0x803F, "GL_LUMINANCE4" },
+ { 0x8040, "GL_LUMINANCE8" },
+ { 0x8041, "GL_LUMINANCE12" },
+ { 0x8042, "GL_LUMINANCE16" },
+ { 0x8043, "GL_LUMINANCE4_ALPHA4" },
+ { 0x8044, "GL_LUMINANCE6_ALPHA2" },
+ { 0x8045, "GL_LUMINANCE8_ALPHA8" },
+ { 0x8046, "GL_LUMINANCE12_ALPHA4" },
+ { 0x8047, "GL_LUMINANCE12_ALPHA12" },
+ { 0x8048, "GL_LUMINANCE16_ALPHA16" },
+ { 0x8049, "GL_INTENSITY" },
+ { 0x804A, "GL_INTENSITY4" },
+ { 0x804B, "GL_INTENSITY8" },
+ { 0x804C, "GL_INTENSITY12" },
+ { 0x804D, "GL_INTENSITY16" },
+ { 0x804F, "GL_RGB4" },
+ { 0x8050, "GL_RGB5" },
+ { 0x8051, "GL_RGB8" },
+ { 0x8052, "GL_RGB10" },
+ { 0x8053, "GL_RGB12" },
+ { 0x8054, "GL_RGB16" },
+ { 0x8055, "GL_RGBA2" },
+ { 0x8056, "GL_RGBA4" },
+ { 0x8057, "GL_RGB5_A1" },
+ { 0x8058, "GL_RGBA8" },
+ { 0x8059, "GL_RGB10_A2" },
+ { 0x805A, "GL_RGBA12" },
+ { 0x805B, "GL_RGBA16" },
+ { 0x805C, "GL_TEXTURE_RED_SIZE" },
+ { 0x805D, "GL_TEXTURE_GREEN_SIZE" },
+ { 0x805E, "GL_TEXTURE_BLUE_SIZE" },
+ { 0x805F, "GL_TEXTURE_ALPHA_SIZE" },
+ { 0x8060, "GL_TEXTURE_LUMINANCE_SIZE" },
+ { 0x8061, "GL_TEXTURE_INTENSITY_SIZE" },
+ { 0x8063, "GL_PROXY_TEXTURE_1D" },
+ { 0x8064, "GL_PROXY_TEXTURE_2D" },
+ { 0x8066, "GL_TEXTURE_PRIORITY" },
+ { 0x8067, "GL_TEXTURE_RESIDENT" },
+ { 0x8068, "GL_TEXTURE_BINDING_1D" },
+ { 0x8069, "GL_TEXTURE_BINDING_2D" },
+ { 0x806A, "GL_TEXTURE_BINDING_3D" },
+ { 0x806B, "GL_PACK_SKIP_IMAGES" },
+ { 0x806C, "GL_PACK_IMAGE_HEIGHT" },
+ { 0x806D, "GL_UNPACK_SKIP_IMAGES" },
+ { 0x806E, "GL_UNPACK_IMAGE_HEIGHT" },
+ { 0x806F, "GL_TEXTURE_3D" },
+ { 0x8070, "GL_PROXY_TEXTURE_3D" },
+ { 0x8071, "GL_TEXTURE_DEPTH" },
+ { 0x8072, "GL_TEXTURE_WRAP_R" },
+ { 0x8073, "GL_MAX_3D_TEXTURE_SIZE" },
+ { 0x8074, "GL_VERTEX_ARRAY" },
+ { 0x8075, "GL_NORMAL_ARRAY" },
+ { 0x8076, "GL_COLOR_ARRAY" },
+ { 0x8077, "GL_INDEX_ARRAY" },
+ { 0x8078, "GL_TEXTURE_COORD_ARRAY" },
+ { 0x8079, "GL_EDGE_FLAG_ARRAY" },
+ { 0x807A, "GL_VERTEX_ARRAY_SIZE" },
+ { 0x807B, "GL_VERTEX_ARRAY_TYPE" },
+ { 0x807C, "GL_VERTEX_ARRAY_STRIDE" },
+ { 0x807E, "GL_NORMAL_ARRAY_TYPE" },
+ { 0x807F, "GL_NORMAL_ARRAY_STRIDE" },
+ { 0x8081, "GL_COLOR_ARRAY_SIZE" },
+ { 0x8082, "GL_COLOR_ARRAY_TYPE" },
+ { 0x8083, "GL_COLOR_ARRAY_STRIDE" },
+ { 0x8085, "GL_INDEX_ARRAY_TYPE" },
+ { 0x8086, "GL_INDEX_ARRAY_STRIDE" },
+ { 0x8088, "GL_TEXTURE_COORD_ARRAY_SIZE" },
+ { 0x8089, "GL_TEXTURE_COORD_ARRAY_TYPE" },
+ { 0x808A, "GL_TEXTURE_COORD_ARRAY_STRIDE" },
+ { 0x808C, "GL_EDGE_FLAG_ARRAY_STRIDE" },
+ { 0x808E, "GL_VERTEX_ARRAY_POINTER" },
+ { 0x808F, "GL_NORMAL_ARRAY_POINTER" },
+ { 0x8090, "GL_COLOR_ARRAY_POINTER" },
+ { 0x8091, "GL_INDEX_ARRAY_POINTER" },
+ { 0x8092, "GL_TEXTURE_COORD_ARRAY_POINTER" },
+ { 0x8093, "GL_EDGE_FLAG_ARRAY_POINTER" },
+ { 0x809D, "GL_MULTISAMPLE_ARB" },
+ { 0x809D, "GL_MULTISAMPLE" },
+ { 0x809E, "GL_SAMPLE_ALPHA_TO_COVERAGE_ARB" },
+ { 0x809E, "GL_SAMPLE_ALPHA_TO_COVERAGE" },
+ { 0x809F, "GL_SAMPLE_ALPHA_TO_ONE_ARB" },
+ { 0x809F, "GL_SAMPLE_ALPHA_TO_ONE" },
+ { 0x80A0, "GL_SAMPLE_COVERAGE_ARB" },
+ { 0x80A0, "GL_SAMPLE_COVERAGE" },
+ { 0x80A0, "GL_SAMPLE_MASK_EXT" },
+ { 0x80A1, "GL_1PASS_EXT" },
+ { 0x80A2, "GL_2PASS_0_EXT" },
+ { 0x80A3, "GL_2PASS_1_EXT" },
+ { 0x80A4, "GL_4PASS_0_EXT" },
+ { 0x80A5, "GL_4PASS_1_EXT" },
+ { 0x80A6, "GL_4PASS_2_EXT" },
+ { 0x80A7, "GL_4PASS_3_EXT" },
+ { 0x80A8, "GL_SAMPLE_BUFFERS" },
+ { 0x80A9, "GL_SAMPLES" },
+ { 0x80AA, "GL_SAMPLE_COVERAGE_VALUE" },
+ { 0x80AB, "GL_SAMPLE_COVERAGE_INVERT" },
+ { 0x80AC, "GL_SAMPLE_PATTERN_EXT" },
+ { 0x80B1, "GL_COLOR_MATRIX" },
+ { 0x80B2, "GL_COLOR_MATRIX_STACK_DEPTH" },
+ { 0x80B3, "GL_MAX_COLOR_MATRIX_STACK_DEPTH" },
+ { 0x80B4, "GL_POST_COLOR_MATRIX_RED_SCALE" },
+ { 0x80B5, "GL_POST_COLOR_MATRIX_GREEN_SCALE" },
+ { 0x80B6, "GL_POST_COLOR_MATRIX_BLUE_SCALE" },
+ { 0x80B7, "GL_POST_COLOR_MATRIX_ALPHA_SCALE" },
+ { 0x80B8, "GL_POST_COLOR_MATRIX_RED_BIAS" },
+ { 0x80B9, "GL_POST_COLOR_MATRIX_GREEN_BIAS" },
+ { 0x80BA, "GL_POST_COLOR_MATRIX_BLUE_BIAS" },
+ { 0x80BB, "GL_POST_COLOR_MATRIX_ALPHA_BIAS" },
+ { 0x80BF, "GL_TEXTURE_COMPARE_FAIL_VALUE_ARB" },
+ { 0x80C8, "GL_BLEND_DST_RGB" },
+ { 0x80C9, "GL_BLEND_SRC_RGB" },
+ { 0x80CA, "GL_BLEND_DST_ALPHA" },
+ { 0x80CB, "GL_BLEND_SRC_ALPHA" },
+ { 0x80CC, "GL_422_EXT" },
+ { 0x80CD, "GL_422_REV_EXT" },
+ { 0x80CE, "GL_422_AVERAGE_EXT" },
+ { 0x80CF, "GL_422_REV_AVERAGE_EXT" },
+ { 0x80D0, "GL_COLOR_TABLE" },
+ { 0x80D1, "GL_POST_CONVOLUTION_COLOR_TABLE" },
+ { 0x80D2, "GL_POST_COLOR_MATRIX_COLOR_TABLE" },
+ { 0x80D3, "GL_PROXY_COLOR_TABLE" },
+ { 0x80D4, "GL_PROXY_POST_CONVOLUTION_COLOR_TABLE" },
+ { 0x80D5, "GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE" },
+ { 0x80D6, "GL_COLOR_TABLE_SCALE" },
+ { 0x80D7, "GL_COLOR_TABLE_BIAS" },
+ { 0x80D8, "GL_COLOR_TABLE_FORMAT" },
+ { 0x80D9, "GL_COLOR_TABLE_WIDTH" },
+ { 0x80DA, "GL_COLOR_TABLE_RED_SIZE" },
+ { 0x80DB, "GL_COLOR_TABLE_GREEN_SIZE" },
+ { 0x80DC, "GL_COLOR_TABLE_BLUE_SIZE" },
+ { 0x80DD, "GL_COLOR_TABLE_ALPHA_SIZE" },
+ { 0x80DE, "GL_COLOR_TABLE_LUMINANCE_SIZE" },
+ { 0x80DF, "GL_COLOR_TABLE_INTENSITY_SIZE" },
+ { 0x80E0, "GL_BGR_EXT" },
+ { 0x80E0, "GL_BGR" },
+ { 0x80E1, "GL_BGRA_EXT" },
+ { 0x80E1, "GL_BGRA" },
+ { 0x80E1, "GL_BGRA" },
+ { 0x80E2, "GL_COLOR_INDEX1_EXT" },
+ { 0x80E3, "GL_COLOR_INDEX2_EXT" },
+ { 0x80E4, "GL_COLOR_INDEX4_EXT" },
+ { 0x80E5, "GL_COLOR_INDEX8_EXT" },
+ { 0x80E6, "GL_COLOR_INDEX12_EXT" },
+ { 0x80E7, "GL_COLOR_INDEX16_EXT" },
+ { 0x80E8, "GL_MAX_ELEMENTS_VERTICES_EXT" },
+ { 0x80E8, "GL_MAX_ELEMENTS_VERTICES" },
+ { 0x80E9, "GL_MAX_ELEMENTS_INDICES_EXT" },
+ { 0x80E9, "GL_MAX_ELEMENTS_INDICES" },
+ { 0x80ED, "GL_TEXTURE_INDEX_SIZE_EXT" },
+ { 0x80F0, "GL_CLIP_VOLUME_CLIPPING_HINT_EXT" },
+ { 0x8126, "GL_POINT_SIZE_MIN_ARB" },
+ { 0x8126, "GL_POINT_SIZE_MIN" },
+ { 0x8127, "GL_POINT_SIZE_MAX_ARB" },
+ { 0x8127, "GL_POINT_SIZE_MAX" },
+ { 0x8128, "GL_POINT_FADE_THRESHOLD_SIZE_ARB" },
+ { 0x8128, "GL_POINT_FADE_THRESHOLD_SIZE" },
+ { 0x8129, "GL_POINT_DISTANCE_ATTENUATION_ARB" },
+ { 0x8129, "GL_POINT_DISTANCE_ATTENUATION" },
+ { 0x812D, "GL_CLAMP_TO_BORDER_ARB" },
+ { 0x812D, "GL_CLAMP_TO_BORDER" },
+ { 0x812F, "GL_CLAMP_TO_EDGE" },
+ { 0x813A, "GL_TEXTURE_MIN_LOD" },
+ { 0x813B, "GL_TEXTURE_MAX_LOD" },
+ { 0x813C, "GL_TEXTURE_BASE_LEVEL" },
+ { 0x813D, "GL_TEXTURE_MAX_LEVEL" },
+ { 0x8151, "GL_CONSTANT_BORDER" },
+ { 0x8153, "GL_REPLICATE_BORDER" },
+ { 0x8154, "GL_CONVOLUTION_BORDER_COLOR" },
+ { 0x8191, "GL_GENERATE_MIPMAP" },
+ { 0x8192, "GL_GENERATE_MIPMAP_HINT" },
+ { 0x81A5, "GL_DEPTH_COMPONENT16_ARB" },
+ { 0x81A5, "GL_DEPTH_COMPONENT16" },
+ { 0x81A6, "GL_DEPTH_COMPONENT24_ARB" },
+ { 0x81A6, "GL_DEPTH_COMPONENT24" },
+ { 0x81A7, "GL_DEPTH_COMPONENT32_ARB" },
+ { 0x81A7, "GL_DEPTH_COMPONENT32" },
+ { 0x81A8, "GL_ARRAY_ELEMENT_LOCK_FIRST_EXT" },
+ { 0x81A9, "GL_ARRAY_ELEMENT_LOCK_COUNT_EXT" },
+ { 0x81AA, "GL_CULL_VERTEX_EXT" },
+ { 0x81AB, "GL_CULL_VERTEX_EYE_POSITION_EXT" },
+ { 0x81AC, "GL_CULL_VERTEX_OBJECT_POSITION_EXT" },
+ { 0x81AD, "GL_IUI_V2F_EXT" },
+ { 0x81AE, "GL_IUI_V3F_EXT" },
+ { 0x81AF, "GL_IUI_N3F_V2F_EXT" },
+ { 0x81B0, "GL_IUI_N3F_V3F_EXT" },
+ { 0x81B1, "GL_T2F_IUI_V2F_EXT" },
+ { 0x81B2, "GL_T2F_IUI_V3F_EXT" },
+ { 0x81B3, "GL_T2F_IUI_N3F_V2F_EXT" },
+ { 0x81B4, "GL_T2F_IUI_N3F_V3F_EXT" },
+ { 0x81B5, "GL_INDEX_TEST_EXT" },
+ { 0x81B6, "GL_INDEX_TEST_FUNC_EXT" },
+ { 0x81B7, "GL_INDEX_TEST_REF_EXT" },
+ { 0x81B8, "GL_INDEX_MATERIAL_EXT" },
+ { 0x81B9, "GL_INDEX_MATERIAL_PARAMETER_EXT" },
+ { 0x81BA, "GL_INDEX_MATERIAL_FACE_EXT" },
+ { 0x81F8, "GL_LIGHT_MODEL_COLOR_CONTROL_EXT" },
+ { 0x81F8, "GL_LIGHT_MODEL_COLOR_CONTROL" },
+ { 0x81F9, "GL_SINGLE_COLOR_EXT" },
+ { 0x81F9, "GL_SINGLE_COLOR" },
+ { 0x81FA, "GL_SEPARATE_SPECULAR_COLOR_EXT" },
+ { 0x81FA, "GL_SEPARATE_SPECULAR_COLOR" },
+ { 0x81FB, "GL_SHARED_TEXTURE_PALETTE_EXT" },
+ { 0x8210, "GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING" },
+ { 0x8211, "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE" },
+ { 0x8212, "GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE" },
+ { 0x8213, "GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE" },
+ { 0x8214, "GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE" },
+ { 0x8215, "GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE" },
+ { 0x8216, "GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE" },
+ { 0x8217, "GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE" },
+ { 0x8218, "GL_FRAMEBUFFER_DEFAULT" },
+ { 0x8219, "GL_FRAMEBUFFER_UNDEFINED" },
+ { 0x821A, "GL_DEPTH_STENCIL_ATTACHMENT" },
+ { 0x8225, "GL_COMPRESSED_RED" },
+ { 0x8226, "GL_COMPRESSED_RG" },
+ { 0x8227, "GL_RG" },
+ { 0x8228, "GL_RG_INTEGER" },
+ { 0x8229, "GL_R8" },
+ { 0x822A, "GL_R16" },
+ { 0x822B, "GL_RG8" },
+ { 0x822C, "GL_RG16" },
+ { 0x822D, "GL_R16F" },
+ { 0x822E, "GL_R32F" },
+ { 0x822F, "GL_RG16F" },
+ { 0x8230, "GL_RG32F" },
+ { 0x8231, "GL_R8I" },
+ { 0x8232, "GL_R8UI" },
+ { 0x8233, "GL_R16I" },
+ { 0x8234, "GL_R16UI" },
+ { 0x8235, "GL_R32I" },
+ { 0x8236, "GL_R32UI" },
+ { 0x8237, "GL_RG8I" },
+ { 0x8238, "GL_RG8UI" },
+ { 0x8239, "GL_RG16I" },
+ { 0x823A, "GL_RG16UI" },
+ { 0x823B, "GL_RG32I" },
+ { 0x823C, "GL_RG32UI" },
+ { 0x8330, "GL_PIXEL_TRANSFORM_2D_EXT" },
+ { 0x8331, "GL_PIXEL_MAG_FILTER_EXT" },
+ { 0x8332, "GL_PIXEL_MIN_FILTER_EXT" },
+ { 0x8333, "GL_PIXEL_CUBIC_WEIGHT_EXT" },
+ { 0x8334, "GL_CUBIC_EXT" },
+ { 0x8335, "GL_AVERAGE_EXT" },
+ { 0x8336, "GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT" },
+ { 0x8337, "GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT" },
+ { 0x8338, "GL_PIXEL_TRANSFORM_2D_MATRIX_EXT" },
+ { 0x8349, "GL_FRAGMENT_MATERIAL_EXT" },
+ { 0x834A, "GL_FRAGMENT_NORMAL_EXT" },
+ { 0x834C, "GL_FRAGMENT_COLOR_EXT" },
+ { 0x834D, "GL_ATTENUATION_EXT" },
+ { 0x834E, "GL_SHADOW_ATTENUATION_EXT" },
+ { 0x834F, "GL_TEXTURE_APPLICATION_MODE_EXT" },
+ { 0x8350, "GL_TEXTURE_LIGHT_EXT" },
+ { 0x8351, "GL_TEXTURE_MATERIAL_FACE_EXT" },
+ { 0x8352, "GL_TEXTURE_MATERIAL_PARAMETER_EXT" },
+ { 0x8362, "GL_UNSIGNED_BYTE_2_3_3_REV" },
+ { 0x8363, "GL_UNSIGNED_SHORT_5_6_5" },
+ { 0x8364, "GL_UNSIGNED_SHORT_5_6_5_REV" },
+ { 0x8365, "GL_UNSIGNED_SHORT_4_4_4_4_REV" },
+ { 0x8366, "GL_UNSIGNED_SHORT_1_5_5_5_REV" },
+ { 0x8367, "GL_UNSIGNED_INT_8_8_8_8_REV" },
+ { 0x8368, "GL_UNSIGNED_INT_2_10_10_10_REV" },
+ { 0x8370, "GL_MIRRORED_REPEAT_ARB" },
+ { 0x8370, "GL_MIRRORED_REPEAT" },
+ { 0x83F0, "GL_COMPRESSED_RGB_S3TC_DXT1_EXT" },
+ { 0x83F1, "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT" },
+ { 0x83F2, "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT" },
+ { 0x83F3, "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT" },
+ { 0x8439, "GL_TANGENT_ARRAY_EXT" },
+ { 0x843A, "GL_BINORMAL_ARRAY_EXT" },
+ { 0x843B, "GL_CURRENT_TANGENT_EXT" },
+ { 0x843C, "GL_CURRENT_BINORMAL_EXT" },
+ { 0x843E, "GL_TANGENT_ARRAY_TYPE_EXT" },
+ { 0x843F, "GL_TANGENT_ARRAY_STRIDE_EXT" },
+ { 0x8440, "GL_BINORMAL_ARRAY_TYPE_EXT" },
+ { 0x8441, "GL_BINORMAL_ARRAY_STRIDE_EXT" },
+ { 0x8442, "GL_TANGENT_ARRAY_POINTER_EXT" },
+ { 0x8443, "GL_BINORMAL_ARRAY_POINTER_EXT" },
+ { 0x8444, "GL_MAP1_TANGENT_EXT" },
+ { 0x8445, "GL_MAP2_TANGENT_EXT" },
+ { 0x8446, "GL_MAP1_BINORMAL_EXT" },
+ { 0x8447, "GL_MAP2_BINORMAL_EXT" },
+ { 0x8450, "GL_FOG_COORD_SRC" },
+ { 0x8450, "GL_FOG_COORDINATE_SOURCE_EXT" },
+ { 0x8450, "GL_FOG_COORDINATE_SOURCE" },
+ { 0x8451, "GL_FOG_COORD" },
+ { 0x8451, "GL_FOG_COORDINATE_EXT" },
+ { 0x8451, "GL_FOG_COORDINATE" },
+ { 0x8452, "GL_FRAGMENT_DEPTH_EXT" },
+ { 0x8452, "GL_FRAGMENT_DEPTH" },
+ { 0x8453 , "GL_CURRENT_FOG_COORD" },
+ { 0x8453 , "GL_CURRENT_FOG_COORDINATE" },
+ { 0x8453, "GL_CURRENT_FOG_COORDINATE_EXT" },
+ { 0x8454, "GL_FOG_COORD_ARRAY_TYPE" },
+ { 0x8454, "GL_FOG_COORDINATE_ARRAY_TYPE_EXT" },
+ { 0x8454, "GL_FOG_COORDINATE_ARRAY_TYPE" },
+ { 0x8455, "GL_FOG_COORD_ARRAY_STRIDE" },
+ { 0x8455, "GL_FOG_COORDINATE_ARRAY_STRIDE_EXT" },
+ { 0x8455, "GL_FOG_COORDINATE_ARRAY_STRIDE" },
+ { 0x8456, "GL_FOG_COORD_ARRAY_POINTER" },
+ { 0x8456, "GL_FOG_COORDINATE_ARRAY_POINTER_EXT" },
+ { 0x8456, "GL_FOG_COORDINATE_ARRAY_POINTER" },
+ { 0x8457, "GL_FOG_COORD_ARRAY" },
+ { 0x8457, "GL_FOG_COORDINATE_ARRAY_EXT" },
+ { 0x8457, "GL_FOG_COORDINATE_ARRAY" },
+ { 0x8458, "GL_COLOR_SUM_ARB" },
+ { 0x8458, "GL_COLOR_SUM_EXT" },
+ { 0x8458, "GL_COLOR_SUM" },
+ { 0x8459, "GL_CURRENT_SECONDARY_COLOR_EXT" },
+ { 0x8459, "GL_CURRENT_SECONDARY_COLOR" },
+ { 0x845A, "GL_SECONDARY_COLOR_ARRAY_SIZE_EXT" },
+ { 0x845A, "GL_SECONDARY_COLOR_ARRAY_SIZE" },
+ { 0x845B, "GL_SECONDARY_COLOR_ARRAY_TYPE_EXT" },
+ { 0x845B, "GL_SECONDARY_COLOR_ARRAY_TYPE" },
+ { 0x845C, "GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT" },
+ { 0x845C, "GL_SECONDARY_COLOR_ARRAY_STRIDE" },
+ { 0x845D, "GL_SECONDARY_COLOR_ARRAY_POINTER_EXT" },
+ { 0x845D, "GL_SECONDARY_COLOR_ARRAY_POINTER" },
+ { 0x845E, "GL_SECONDARY_COLOR_ARRAY_EXT" },
+ { 0x845E, "GL_SECONDARY_COLOR_ARRAY" },
+ { 0x845F, "GL_CURRENT_RASTER_SECONDARY_COLOR" },
+ { 0x846D, "GL_ALIASED_POINT_SIZE_RANGE" },
+ { 0x846E, "GL_ALIASED_LINE_WIDTH_RANGE" },
+ { 0x84C0, "GL_TEXTURE0" },
+ { 0x84C1, "GL_TEXTURE1" },
+ { 0x84C2, "GL_TEXTURE2" },
+ { 0x84C3, "GL_TEXTURE3" },
+ { 0x84C4, "GL_TEXTURE4" },
+ { 0x84C5, "GL_TEXTURE5" },
+ { 0x84C6, "GL_TEXTURE6" },
+ { 0x84C7, "GL_TEXTURE7" },
+ { 0x84C8, "GL_TEXTURE8" },
+ { 0x84C9, "GL_TEXTURE9" },
+ { 0x84CA, "GL_TEXTURE10" },
+ { 0x84CB, "GL_TEXTURE11" },
+ { 0x84CC, "GL_TEXTURE12" },
+ { 0x84CD, "GL_TEXTURE13" },
+ { 0x84CE, "GL_TEXTURE14" },
+ { 0x84CF, "GL_TEXTURE15" },
+ { 0x84D0, "GL_TEXTURE16" },
+ { 0x84D1, "GL_TEXTURE17" },
+ { 0x84D2, "GL_TEXTURE18" },
+ { 0x84D3, "GL_TEXTURE19" },
+ { 0x84D4, "GL_TEXTURE20" },
+ { 0x84D5, "GL_TEXTURE21" },
+ { 0x84D6, "GL_TEXTURE22" },
+ { 0x84D7, "GL_TEXTURE23" },
+ { 0x84D8, "GL_TEXTURE24" },
+ { 0x84D9, "GL_TEXTURE25" },
+ { 0x84DA, "GL_TEXTURE26" },
+ { 0x84DB, "GL_TEXTURE27" },
+ { 0x84DC, "GL_TEXTURE28" },
+ { 0x84DD, "GL_TEXTURE29" },
+ { 0x84DE, "GL_TEXTURE30" },
+ { 0x84DF, "GL_TEXTURE31" },
+ { 0x84E0, "GL_ACTIVE_TEXTURE" },
+ { 0x84E1, "GL_CLIENT_ACTIVE_TEXTURE" },
+ { 0x84E2, "GL_MAX_TEXTURE_UNITS" },
+ { 0x84E3, "GL_TRANSPOSE_MODELVIEW_MATRIX" },
+ { 0x84E4, "GL_TRANSPOSE_PROJECTION_MATRIX" },
+ { 0x84E5, "GL_TRANSPOSE_TEXTURE_MATRIX" },
+ { 0x84E6, "GL_TRANSPOSE_COLOR_MATRIX" },
+ { 0x84E7, "GL_SUBTRACT" },
+ { 0x84E8, "GL_MAX_RENDERBUFFER_SIZE" },
+ { 0x84E9, "GL_COMPRESSED_ALPHA" },
+ { 0x84EA, "GL_COMPRESSED_LUMINANCE" },
+ { 0x84EB, "GL_COMPRESSED_LUMINANCE_ALPHA" },
+ { 0x84EC, "GL_COMPRESSED_INTENSITY" },
+ { 0x84ED, "GL_COMPRESSED_RGB" },
+ { 0x84EE, "GL_COMPRESSED_RGBA" },
+ { 0x84EF, "GL_TEXTURE_COMPRESSION_HINT" },
+ { 0x84F5, "GL_TEXTURE_RECTANGLE_EXT" },
+ { 0x84F6, "GL_TEXTURE_BINDING_RECTANGLE_EXT" },
+ { 0x84F7, "GL_PROXY_TEXTURE_RECTANGLE_EXT" },
+ { 0x84F8, "GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT" },
+ { 0x84F9, "GL_DEPTH_STENCIL" },
+ { 0x84FA, "GL_UNSIGNED_INT_24_8" },
+ { 0x84FD, "GL_MAX_TEXTURE_LOD_BIAS" },
+ { 0x84FE, "GL_TEXTURE_MAX_ANISOTROPY_EXT" },
+ { 0x84FF, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" },
+ { 0x8500, "GL_TEXTURE_FILTER_CONTROL" },
+ { 0x8501, "GL_TEXTURE_LOD_BIAS" },
+ { 0x8502, "GL_MODELVIEW1_STACK_DEPTH_EXT" },
+ { 0x8506, "GL_MODELVIEW_MATRIX1_EXT" },
+ { 0x8507, "GL_INCR_WRAP" },
+ { 0x8508, "GL_DECR_WRAP" },
+ { 0x8509, "GL_VERTEX_WEIGHTING_EXT" },
+ { 0x850A, "GL_MODELVIEW1_ARB" },
+ { 0x850B, "GL_CURRENT_VERTEX_WEIGHT_EXT" },
+ { 0x850C, "GL_VERTEX_WEIGHT_ARRAY_EXT" },
+ { 0x850D, "GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT" },
+ { 0x850E, "GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT" },
+ { 0x850F, "GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT" },
+ { 0x8510, "GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT" },
+ { 0x8511, "GL_NORMAL_MAP_ARB" },
+ { 0x8511, "GL_NORMAL_MAP_EXT" },
+ { 0x8511, "GL_NORMAL_MAP" },
+ { 0x8512, "GL_REFLECTION_MAP_ARB" },
+ { 0x8512, "GL_REFLECTION_MAP_EXT" },
+ { 0x8512, "GL_REFLECTION_MAP" },
+ { 0x8513, "GL_TEXTURE_CUBE_MAP_ARB" },
+ { 0x8513, "GL_TEXTURE_CUBE_MAP_EXT" },
+ { 0x8513, "GL_TEXTURE_CUBE_MAP" },
+ { 0x8514, "GL_TEXTURE_BINDING_CUBE_MAP_ARB" },
+ { 0x8514, "GL_TEXTURE_BINDING_CUBE_MAP_EXT" },
+ { 0x8514, "GL_TEXTURE_BINDING_CUBE_MAP" },
+ { 0x8515, "GL_TEXTURE_CUBE_MAP_POSITIVE_X" },
+ { 0x8516, "GL_TEXTURE_CUBE_MAP_NEGATIVE_X" },
+ { 0x8517, "GL_TEXTURE_CUBE_MAP_POSITIVE_Y" },
+ { 0x8518, "GL_TEXTURE_CUBE_MAP_NEGATIVE_Y" },
+ { 0x8519, "GL_TEXTURE_CUBE_MAP_POSITIVE_Z" },
+ { 0x851A, "GL_TEXTURE_CUBE_MAP_NEGATIVE_Z" },
+ { 0x851B, "GL_PROXY_TEXTURE_CUBE_MAP" },
+ { 0x851C, "GL_MAX_CUBE_MAP_TEXTURE_SIZE" },
+ { 0x851D, "GL_VERTEX_ARRAY_RANGE_APPLE" },
+ { 0x851E, "GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE" },
+ { 0x851F, "GL_VERTEX_ARRAY_STORAGE_HINT_APPLE" },
+ { 0x8520, "GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_APPLE" },
+ { 0x8521, "GL_VERTEX_ARRAY_RANGE_POINTER_APPLE" },
+ { 0x8570, "GL_COMBINE_ARB" },
+ { 0x8570, "GL_COMBINE_EXT" },
+ { 0x8570, "GL_COMBINE" },
+ { 0x8571, "GL_COMBINE_RGB_ARB" },
+ { 0x8571, "GL_COMBINE_RGB_EXT" },
+ { 0x8571, "GL_COMBINE_RGB" },
+ { 0x8572, "GL_COMBINE_ALPHA_ARB" },
+ { 0x8572, "GL_COMBINE_ALPHA_EXT" },
+ { 0x8572, "GL_COMBINE_ALPHA" },
+ { 0x8573, "GL_RGB_SCALE_ARB" },
+ { 0x8573, "GL_RGB_SCALE_EXT" },
+ { 0x8573, "GL_RGB_SCALE" },
+ { 0x8574, "GL_ADD_SIGNED_ARB" },
+ { 0x8574, "GL_ADD_SIGNED_EXT" },
+ { 0x8574, "GL_ADD_SIGNED" },
+ { 0x8575, "GL_INTERPOLATE_ARB" },
+ { 0x8575, "GL_INTERPOLATE_EXT" },
+ { 0x8575, "GL_INTERPOLATE" },
+ { 0x8576, "GL_CONSTANT_ARB" },
+ { 0x8576, "GL_CONSTANT_EXT" },
+ { 0x8576, "GL_CONSTANT" },
+ { 0x8577, "GL_PRIMARY_COLOR_ARB" },
+ { 0x8577, "GL_PRIMARY_COLOR_EXT" },
+ { 0x8577, "GL_PRIMARY_COLOR" },
+ { 0x8578, "GL_PREVIOUS_ARB" },
+ { 0x8578, "GL_PREVIOUS_EXT" },
+ { 0x8578, "GL_PREVIOUS" },
+ { 0x8580, "GL_SOURCE0_RGB_ARB" },
+ { 0x8580, "GL_SOURCE0_RGB_EXT" },
+ { 0x8580, "GL_SOURCE0_RGB" },
+ { 0x8580, "GL_SRC0_RGB" },
+ { 0x8581, "GL_SOURCE1_RGB_ARB" },
+ { 0x8581, "GL_SOURCE1_RGB_EXT" },
+ { 0x8581, "GL_SOURCE1_RGB" },
+ { 0x8581, "GL_SRC1_RGB" },
+ { 0x8582, "GL_SOURCE2_RGB_ARB" },
+ { 0x8582, "GL_SOURCE2_RGB_EXT" },
+ { 0x8582, "GL_SOURCE2_RGB" },
+ { 0x8582, "GL_SRC2_RGB" },
+ { 0x8583, "GL_SOURCE3_RGB_ARB" },
+ { 0x8583, "GL_SOURCE3_RGB_EXT" },
+ { 0x8583, "GL_SOURCE3_RGB" },
+ { 0x8583, "GL_SRC3_RGB" },
+ { 0x8584, "GL_SOURCE4_RGB_ARB" },
+ { 0x8584, "GL_SOURCE4_RGB_EXT" },
+ { 0x8584, "GL_SOURCE4_RGB" },
+ { 0x8584, "GL_SRC4_RGB" },
+ { 0x8585, "GL_SOURCE5_RGB_ARB" },
+ { 0x8585, "GL_SOURCE5_RGB_EXT" },
+ { 0x8585, "GL_SOURCE5_RGB" },
+ { 0x8585, "GL_SRC5_RGB" },
+ { 0x8586, "GL_SOURCE6_RGB_ARB" },
+ { 0x8586, "GL_SOURCE6_RGB_EXT" },
+ { 0x8586, "GL_SOURCE6_RGB" },
+ { 0x8586, "GL_SRC6_RGB" },
+ { 0x8587, "GL_SOURCE7_RGB_ARB" },
+ { 0x8587, "GL_SOURCE7_RGB_EXT" },
+ { 0x8587, "GL_SOURCE7_RGB" },
+ { 0x8587, "GL_SRC7_RGB" },
+ { 0x8588, "GL_SOURCE0_ALPHA_ARB" },
+ { 0x8588, "GL_SOURCE0_ALPHA_EXT" },
+ { 0x8588, "GL_SOURCE0_ALPHA" },
+ { 0x8588, "GL_SRC0_ALPHA" },
+ { 0x8589, "GL_SOURCE1_ALPHA_ARB" },
+ { 0x8589, "GL_SOURCE1_ALPHA_EXT" },
+ { 0x8589, "GL_SOURCE1_ALPHA" },
+ { 0x8589, "GL_SRC1_ALPHA" },
+ { 0x858A, "GL_SOURCE2_ALPHA_ARB" },
+ { 0x858A, "GL_SOURCE2_ALPHA_EXT" },
+ { 0x858A, "GL_SOURCE2_ALPHA" },
+ { 0x858A, "GL_SRC2_ALPHA" },
+ { 0x858B, "GL_SOURCE3_ALPHA_ARB" },
+ { 0x858B, "GL_SOURCE3_ALPHA_EXT" },
+ { 0x858B, "GL_SOURCE3_ALPHA" },
+ { 0x858B, "GL_SRC3_ALPHA" },
+ { 0x858C, "GL_SOURCE4_ALPHA_ARB" },
+ { 0x858C, "GL_SOURCE4_ALPHA_EXT" },
+ { 0x858C, "GL_SOURCE4_ALPHA" },
+ { 0x858C, "GL_SRC4_ALPHA" },
+ { 0x858D, "GL_SOURCE5_ALPHA_ARB" },
+ { 0x858D, "GL_SOURCE5_ALPHA_EXT" },
+ { 0x858D, "GL_SOURCE5_ALPHA" },
+ { 0x858D, "GL_SRC5_ALPHA" },
+ { 0x858E, "GL_SOURCE6_ALPHA_ARB" },
+ { 0x858E, "GL_SOURCE6_ALPHA_EXT" },
+ { 0x858E, "GL_SOURCE6_ALPHA" },
+ { 0x858E, "GL_SRC6_ALPHA" },
+ { 0x858F, "GL_SOURCE7_ALPHA_ARB" },
+ { 0x858F, "GL_SOURCE7_ALPHA_EXT" },
+ { 0x858F, "GL_SOURCE7_ALPHA" },
+ { 0x858F, "GL_SRC7_ALPHA" },
+ { 0x8590, "GL_OPERAND0_RGB_ARB" },
+ { 0x8590, "GL_OPERAND0_RGB_EXT" },
+ { 0x8590, "GL_OPERAND0_RGB" },
+ { 0x8591, "GL_OPERAND1_RGB_ARB" },
+ { 0x8591, "GL_OPERAND1_RGB_EXT" },
+ { 0x8591, "GL_OPERAND1_RGB" },
+ { 0x8592, "GL_OPERAND2_RGB_ARB" },
+ { 0x8592, "GL_OPERAND2_RGB_EXT" },
+ { 0x8592, "GL_OPERAND2_RGB" },
+ { 0x8593, "GL_OPERAND3_RGB_ARB" },
+ { 0x8593, "GL_OPERAND3_RGB_EXT" },
+ { 0x8593, "GL_OPERAND3_RGB" },
+ { 0x8594, "GL_OPERAND4_RGB_ARB" },
+ { 0x8594, "GL_OPERAND4_RGB_EXT" },
+ { 0x8594, "GL_OPERAND4_RGB" },
+ { 0x8595, "GL_OPERAND5_RGB_ARB" },
+ { 0x8595, "GL_OPERAND5_RGB_EXT" },
+ { 0x8595, "GL_OPERAND5_RGB" },
+ { 0x8596, "GL_OPERAND6_RGB_ARB" },
+ { 0x8596, "GL_OPERAND6_RGB_EXT" },
+ { 0x8596, "GL_OPERAND6_RGB" },
+ { 0x8597, "GL_OPERAND7_RGB_ARB" },
+ { 0x8597, "GL_OPERAND7_RGB_EXT" },
+ { 0x8597, "GL_OPERAND7_RGB" },
+ { 0x8598, "GL_OPERAND0_ALPHA_ARB" },
+ { 0x8598, "GL_OPERAND0_ALPHA_EXT" },
+ { 0x8598, "GL_OPERAND0_ALPHA" },
+ { 0x8599, "GL_OPERAND1_ALPHA_ARB" },
+ { 0x8599, "GL_OPERAND1_ALPHA_EXT" },
+ { 0x8599, "GL_OPERAND1_ALPHA" },
+ { 0x859A, "GL_OPERAND2_ALPHA_ARB" },
+ { 0x859A, "GL_OPERAND2_ALPHA_EXT" },
+ { 0x859A, "GL_OPERAND2_ALPHA" },
+ { 0x859B, "GL_OPERAND3_ALPHA_ARB" },
+ { 0x859B, "GL_OPERAND3_ALPHA_EXT" },
+ { 0x859B, "GL_OPERAND3_ALPHA" },
+ { 0x859C, "GL_OPERAND4_ALPHA_ARB" },
+ { 0x859C, "GL_OPERAND4_ALPHA_EXT" },
+ { 0x859C, "GL_OPERAND4_ALPHA" },
+ { 0x859D, "GL_OPERAND5_ALPHA_ARB" },
+ { 0x859D, "GL_OPERAND5_ALPHA_EXT" },
+ { 0x859D, "GL_OPERAND5_ALPHA" },
+ { 0x859E, "GL_OPERAND6_ALPHA_ARB" },
+ { 0x859E, "GL_OPERAND6_ALPHA_EXT" },
+ { 0x859E, "GL_OPERAND6_ALPHA" },
+ { 0x859F, "GL_OPERAND7_ALPHA_ARB" },
+ { 0x859F, "GL_OPERAND7_ALPHA_EXT" },
+ { 0x859F, "GL_OPERAND7_ALPHA" },
+ { 0x85AE, "GL_PERTURB_EXT" },
+ { 0x85AF, "GL_TEXTURE_NORMAL_EXT" },
+ { 0x85B4, "GL_STORAGE_CLIENT_APPLE" },
+ { 0x85B5, "GL_VERTEX_ARRAY_BINDING_APPLE" },
+ { 0x85BD, "GL_STORAGE_PRIVATE_APPLE" },
+ { 0x85BE, "GL_STORAGE_CACHED_APPLE" },
+ { 0x85BF, "GL_STORAGE_SHARED_APPLE" },
+ { 0x8620, "GL_VERTEX_PROGRAM_ARB" },
+ { 0x8620, "GL_VERTEX_PROGRAM_NV" },
+ { 0x8621, "GL_VERTEX_STATE_PROGRAM_NV" },
+ { 0x8622, "GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB" },
+ { 0x8622, "GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB" },
+ { 0x8622, "GL_VERTEX_ATTRIB_ARRAY_ENABLED" },
+ { 0x8623, "GL_ATTRIB_ARRAY_SIZE_NV" },
+ { 0x8623, "GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB" },
+ { 0x8623, "GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB" },
+ { 0x8623, "GL_VERTEX_ATTRIB_ARRAY_SIZE" },
+ { 0x8624, "GL_ATTRIB_ARRAY_STRIDE_NV" },
+ { 0x8624, "GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB" },
+ { 0x8624, "GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB" },
+ { 0x8624, "GL_VERTEX_ATTRIB_ARRAY_STRIDE" },
+ { 0x8625, "GL_ATTRIB_ARRAY_TYPE_NV" },
+ { 0x8625, "GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB" },
+ { 0x8625, "GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB" },
+ { 0x8625, "GL_VERTEX_ATTRIB_ARRAY_TYPE" },
+ { 0x8626, "GL_CURRENT_ATTRIB_NV" },
+ { 0x8626, "GL_CURRENT_VERTEX_ATTRIB_ARB" },
+ { 0x8626, "GL_CURRENT_VERTEX_ATTRIB_ARB" },
+ { 0x8626, "GL_CURRENT_VERTEX_ATTRIB" },
+ { 0x8627, "GL_PROGRAM_LENGTH_ARB" },
+ { 0x8627, "GL_PROGRAM_LENGTH_NV" },
+ { 0x8628, "GL_PROGRAM_STRING_ARB" },
+ { 0x8628, "GL_PROGRAM_STRING_NV" },
+ { 0x8629, "GL_MODELVIEW_PROJECTION_NV" },
+ { 0x862A, "GL_IDENTITY_NV" },
+ { 0x862B, "GL_INVERSE_NV" },
+ { 0x862C, "GL_TRANSPOSE_NV" },
+ { 0x862D, "GL_INVERSE_TRANSPOSE_NV" },
+ { 0x862E, "GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB" },
+ { 0x862E, "GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV" },
+ { 0x862F, "GL_MAX_PROGRAM_MATRICES_ARB" },
+ { 0x862F, "GL_MAX_TRACK_MATRICES_NV" },
+ { 0x8630, "GL_MATRIX0_NV" },
+ { 0x8631, "GL_MATRIX1_NV" },
+ { 0x8632, "GL_MATRIX2_NV" },
+ { 0x8633, "GL_MATRIX3_NV" },
+ { 0x8634, "GL_MATRIX4_NV" },
+ { 0x8635, "GL_MATRIX5_NV" },
+ { 0x8636, "GL_MATRIX6_NV" },
+ { 0x8637, "GL_MATRIX7_NV" },
+ { 0x8640, "GL_CURRENT_MATRIX_STACK_DEPTH_ARB" },
+ { 0x8640, "GL_CURRENT_MATRIX_STACK_DEPTH_NV" },
+ { 0x8641, "GL_CURRENT_MATRIX_ARB" },
+ { 0x8641, "GL_CURRENT_MATRIX_NV" },
+ { 0x8642, "GL_PROGRAM_POINT_SIZE_EXT" },
+ { 0x8642, "GL_VERTEX_PROGRAM_POINT_SIZE_ARB" },
+ { 0x8642, "GL_VERTEX_PROGRAM_POINT_SIZE_ARB" },
+ { 0x8642, "GL_VERTEX_PROGRAM_POINT_SIZE_NV" },
+ { 0x8642, "GL_VERTEX_PROGRAM_POINT_SIZE" },
+ { 0x8643, "GL_VERTEX_PROGRAM_TWO_SIDE_ARB" },
+ { 0x8643, "GL_VERTEX_PROGRAM_TWO_SIDE_ARB" },
+ { 0x8643, "GL_VERTEX_PROGRAM_TWO_SIDE_NV" },
+ { 0x8643, "GL_VERTEX_PROGRAM_TWO_SIDE" },
+ { 0x8644, "GL_PROGRAM_PARAMETER_NV" },
+ { 0x8645, "GL_ATTRIB_ARRAY_POINTER_NV" },
+ { 0x8645, "GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB" },
+ { 0x8645, "GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB" },
+ { 0x8645, "GL_VERTEX_ATTRIB_ARRAY_POINTER" },
+ { 0x8646, "GL_PROGRAM_TARGET_NV" },
+ { 0x8647, "GL_PROGRAM_RESIDENT_NV" },
+ { 0x8648, "GL_TRACK_MATRIX_NV" },
+ { 0x8649, "GL_TRACK_MATRIX_TRANSFORM_NV" },
+ { 0x864A, "GL_VERTEX_PROGRAM_BINDING_NV" },
+ { 0x864B, "GL_PROGRAM_ERROR_POSITION_ARB" },
+ { 0x864B, "GL_PROGRAM_ERROR_POSITION_NV" },
+ { 0x8650, "GL_VERTEX_ATTRIB_ARRAY0_NV" },
+ { 0x8651, "GL_VERTEX_ATTRIB_ARRAY1_NV" },
+ { 0x8652, "GL_VERTEX_ATTRIB_ARRAY2_NV" },
+ { 0x8653, "GL_VERTEX_ATTRIB_ARRAY3_NV" },
+ { 0x8654, "GL_VERTEX_ATTRIB_ARRAY4_NV" },
+ { 0x8655, "GL_VERTEX_ATTRIB_ARRAY5_NV" },
+ { 0x8656, "GL_VERTEX_ATTRIB_ARRAY6_NV" },
+ { 0x8657, "GL_VERTEX_ATTRIB_ARRAY7_NV" },
+ { 0x8658, "GL_VERTEX_ATTRIB_ARRAY8_NV" },
+ { 0x8659, "GL_VERTEX_ATTRIB_ARRAY9_NV" },
+ { 0x865A, "GL_VERTEX_ATTRIB_ARRAY10_NV" },
+ { 0x865B, "GL_VERTEX_ATTRIB_ARRAY11_NV" },
+ { 0x865C, "GL_VERTEX_ATTRIB_ARRAY12_NV" },
+ { 0x865D, "GL_VERTEX_ATTRIB_ARRAY13_NV" },
+ { 0x865E, "GL_VERTEX_ATTRIB_ARRAY14_NV" },
+ { 0x865F, "GL_VERTEX_ATTRIB_ARRAY15_NV" },
+ { 0x8660, "GL_MAP1_VERTEX_ATTRIB0_4_NV" },
+ { 0x8661, "GL_MAP1_VERTEX_ATTRIB1_4_NV" },
+ { 0x8662, "GL_MAP1_VERTEX_ATTRIB2_4_NV" },
+ { 0x8663, "GL_MAP1_VERTEX_ATTRIB3_4_NV" },
+ { 0x8664, "GL_MAP1_VERTEX_ATTRIB4_4_NV" },
+ { 0x8665, "GL_MAP1_VERTEX_ATTRIB5_4_NV" },
+ { 0x8666, "GL_MAP1_VERTEX_ATTRIB6_4_NV" },
+ { 0x8667, "GL_MAP1_VERTEX_ATTRIB7_4_NV" },
+ { 0x8668, "GL_MAP1_VERTEX_ATTRIB8_4_NV" },
+ { 0x8669, "GL_MAP1_VERTEX_ATTRIB9_4_NV" },
+ { 0x866A, "GL_MAP1_VERTEX_ATTRIB10_4_NV" },
+ { 0x866B, "GL_MAP1_VERTEX_ATTRIB11_4_NV" },
+ { 0x866C, "GL_MAP1_VERTEX_ATTRIB12_4_NV" },
+ { 0x866D, "GL_MAP1_VERTEX_ATTRIB13_4_NV" },
+ { 0x866E, "GL_MAP1_VERTEX_ATTRIB14_4_NV" },
+ { 0x866F, "GL_MAP1_VERTEX_ATTRIB15_4_NV" },
+ { 0x8670, "GL_MAP2_VERTEX_ATTRIB0_4_NV" },
+ { 0x8671, "GL_MAP2_VERTEX_ATTRIB1_4_NV" },
+ { 0x8672, "GL_MAP2_VERTEX_ATTRIB2_4_NV" },
+ { 0x8673, "GL_MAP2_VERTEX_ATTRIB3_4_NV" },
+ { 0x8674, "GL_MAP2_VERTEX_ATTRIB4_4_NV" },
+ { 0x8675, "GL_MAP2_VERTEX_ATTRIB5_4_NV" },
+ { 0x8676, "GL_MAP2_VERTEX_ATTRIB6_4_NV" },
+ { 0x8677, "GL_MAP2_VERTEX_ATTRIB7_4_NV" },
+ { 0x8677, "GL_PROGRAM_BINDING_ARB" },
+ { 0x8677, "GL_PROGRAM_NAME_ARB" },
+ { 0x8678, "GL_MAP2_VERTEX_ATTRIB8_4_NV" },
+ { 0x8679, "GL_MAP2_VERTEX_ATTRIB9_4_NV" },
+ { 0x867A, "GL_MAP2_VERTEX_ATTRIB10_4_NV" },
+ { 0x867B, "GL_MAP2_VERTEX_ATTRIB11_4_NV" },
+ { 0x867C, "GL_MAP2_VERTEX_ATTRIB12_4_NV" },
+ { 0x867D, "GL_MAP2_VERTEX_ATTRIB13_4_NV" },
+ { 0x867E, "GL_MAP2_VERTEX_ATTRIB14_4_NV" },
+ { 0x867F, "GL_MAP2_VERTEX_ATTRIB15_4_NV" },
+ { 0x86A0, "GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB" },
+ { 0x86A0, "GL_TEXTURE_COMPRESSED_IMAGE_SIZE" },
+ { 0x86A1, "GL_TEXTURE_COMPRESSED_ARB" },
+ { 0x86A1, "GL_TEXTURE_COMPRESSED" },
+ { 0x86A2, "GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB" },
+ { 0x86A2, "GL_NUM_COMPRESSED_TEXTURE_FORMATS" },
+ { 0x86A3, "GL_COMPRESSED_TEXTURE_FORMATS_ARB" },
+ { 0x86A3, "GL_COMPRESSED_TEXTURE_FORMATS" },
+ { 0x86A4, "GL_MAX_VERTEX_UNITS_ARB" },
+ { 0x86A5, "GL_ACTIVE_VERTEX_UNITS_ARB" },
+ { 0x86A6, "GL_WEIGHT_SUM_UNITY_ARB" },
+ { 0x86A7, "GL_VERTEX_BLEND_ARB" },
+ { 0x86A8, "GL_CURRENT_WEIGHT_ARB" },
+ { 0x86A9, "GL_WEIGHT_ARRAY_TYPE_ARB" },
+ { 0x86AA, "GL_WEIGHT_ARRAY_STRIDE_ARB" },
+ { 0x86AB, "GL_WEIGHT_ARRAY_SIZE_ARB" },
+ { 0x86AC, "GL_WEIGHT_ARRAY_POINTER_ARB" },
+ { 0x86AD, "GL_WEIGHT_ARRAY_ARB" },
+ { 0x86AE, "GL_DOT3_RGB_ARB" },
+ { 0x86AE, "GL_DOT3_RGB" },
+ { 0x86AF, "GL_DOT3_RGBA_ARB" },
+ { 0x86AF, "GL_DOT3_RGBA" },
+ { 0x8722, "GL_MODELVIEW2_ARB" },
+ { 0x8723, "GL_MODELVIEW3_ARB" },
+ { 0x8724, "GL_MODELVIEW4_ARB" },
+ { 0x8725, "GL_MODELVIEW5_ARB" },
+ { 0x8726, "GL_MODELVIEW6_ARB" },
+ { 0x8727, "GL_MODELVIEW7_ARB" },
+ { 0x8728, "GL_MODELVIEW8_ARB" },
+ { 0x8729, "GL_MODELVIEW9_ARB" },
+ { 0x872A, "GL_MODELVIEW10_ARB" },
+ { 0x872B, "GL_MODELVIEW11_ARB" },
+ { 0x872C, "GL_MODELVIEW12_ARB" },
+ { 0x872D, "GL_MODELVIEW13_ARB" },
+ { 0x872E, "GL_MODELVIEW14_ARB" },
+ { 0x872F, "GL_MODELVIEW15_ARB" },
+ { 0x8730, "GL_MODELVIEW16_ARB" },
+ { 0x8731, "GL_MODELVIEW17_ARB" },
+ { 0x8732, "GL_MODELVIEW18_ARB" },
+ { 0x8733, "GL_MODELVIEW19_ARB" },
+ { 0x8734, "GL_MODELVIEW20_ARB" },
+ { 0x8735, "GL_MODELVIEW21_ARB" },
+ { 0x8736, "GL_MODELVIEW22_ARB" },
+ { 0x8737, "GL_MODELVIEW23_ARB" },
+ { 0x8738, "GL_MODELVIEW24_ARB" },
+ { 0x8739, "GL_MODELVIEW25_ARB" },
+ { 0x873A, "GL_MODELVIEW26_ARB" },
+ { 0x873B, "GL_MODELVIEW27_ARB" },
+ { 0x873C, "GL_MODELVIEW28_ARB" },
+ { 0x873D, "GL_MODELVIEW29_ARB" },
+ { 0x873E, "GL_MODELVIEW30_ARB" },
+ { 0x873F, "GL_MODELVIEW31_ARB" },
+ { 0x8742, "GL_MIRROR_CLAMP_EXT" },
+ { 0x8743, "GL_MIRROR_CLAMP_TO_EDGE_EXT" },
+ { 0x8764, "GL_BUFFER_SIZE_ARB" },
+ { 0x8764, "GL_BUFFER_SIZE" },
+ { 0x8765, "GL_BUFFER_USAGE_ARB" },
+ { 0x8765, "GL_BUFFER_USAGE" },
+ { 0x8780, "GL_VERTEX_SHADER_EXT" },
+ { 0x8781, "GL_VERTEX_SHADER_BINDING_EXT" },
+ { 0x8782, "GL_OP_INDEX_EXT" },
+ { 0x8783, "GL_OP_NEGATE_EXT" },
+ { 0x8784, "GL_OP_DOT3_EXT" },
+ { 0x8785, "GL_OP_DOT4_EXT" },
+ { 0x8786, "GL_OP_MUL_EXT" },
+ { 0x8787, "GL_OP_ADD_EXT" },
+ { 0x8788, "GL_OP_MADD_EXT" },
+ { 0x8789, "GL_OP_FRAC_EXT" },
+ { 0x878A, "GL_OP_MAX_EXT" },
+ { 0x878B, "GL_OP_MIN_EXT" },
+ { 0x878C, "GL_OP_SET_GE_EXT" },
+ { 0x878D, "GL_OP_SET_LT_EXT" },
+ { 0x878E, "GL_OP_CLAMP_EXT" },
+ { 0x878F, "GL_OP_FLOOR_EXT" },
+ { 0x8790, "GL_OP_ROUND_EXT" },
+ { 0x8791, "GL_OP_EXP_BASE_2_EXT" },
+ { 0x8792, "GL_OP_LOG_BASE_2_EXT" },
+ { 0x8793, "GL_OP_POWER_EXT" },
+ { 0x8794, "GL_OP_RECIP_EXT" },
+ { 0x8795, "GL_OP_RECIP_SQRT_EXT" },
+ { 0x8796, "GL_OP_SUB_EXT" },
+ { 0x8797, "GL_OP_CROSS_PRODUCT_EXT" },
+ { 0x8798, "GL_OP_MULTIPLY_MATRIX_EXT" },
+ { 0x8799, "GL_OP_MOV_EXT" },
+ { 0x879A, "GL_OUTPUT_VERTEX_EXT" },
+ { 0x879B, "GL_OUTPUT_COLOR0_EXT" },
+ { 0x879C, "GL_OUTPUT_COLOR1_EXT" },
+ { 0x879D, "GL_OUTPUT_TEXTURE_COORD0_EXT" },
+ { 0x879E, "GL_OUTPUT_TEXTURE_COORD1_EXT" },
+ { 0x879F, "GL_OUTPUT_TEXTURE_COORD2_EXT" },
+ { 0x87A0, "GL_OUTPUT_TEXTURE_COORD3_EXT" },
+ { 0x87A1, "GL_OUTPUT_TEXTURE_COORD4_EXT" },
+ { 0x87A2, "GL_OUTPUT_TEXTURE_COORD5_EXT" },
+ { 0x87A3, "GL_OUTPUT_TEXTURE_COORD6_EXT" },
+ { 0x87A4, "GL_OUTPUT_TEXTURE_COORD7_EXT" },
+ { 0x87A5, "GL_OUTPUT_TEXTURE_COORD8_EXT" },
+ { 0x87A6, "GL_OUTPUT_TEXTURE_COORD9_EXT" },
+ { 0x87A7, "GL_OUTPUT_TEXTURE_COORD10_EXT" },
+ { 0x87A8, "GL_OUTPUT_TEXTURE_COORD11_EXT" },
+ { 0x87A9, "GL_OUTPUT_TEXTURE_COORD12_EXT" },
+ { 0x87AA, "GL_OUTPUT_TEXTURE_COORD13_EXT" },
+ { 0x87AB, "GL_OUTPUT_TEXTURE_COORD14_EXT" },
+ { 0x87AC, "GL_OUTPUT_TEXTURE_COORD15_EXT" },
+ { 0x87AD, "GL_OUTPUT_TEXTURE_COORD16_EXT" },
+ { 0x87AE, "GL_OUTPUT_TEXTURE_COORD17_EXT" },
+ { 0x87AF, "GL_OUTPUT_TEXTURE_COORD18_EXT" },
+ { 0x87B0, "GL_OUTPUT_TEXTURE_COORD19_EXT" },
+ { 0x87B1, "GL_OUTPUT_TEXTURE_COORD20_EXT" },
+ { 0x87B2, "GL_OUTPUT_TEXTURE_COORD21_EXT" },
+ { 0x87B3, "GL_OUTPUT_TEXTURE_COORD22_EXT" },
+ { 0x87B4, "GL_OUTPUT_TEXTURE_COORD23_EXT" },
+ { 0x87B5, "GL_OUTPUT_TEXTURE_COORD24_EXT" },
+ { 0x87B6, "GL_OUTPUT_TEXTURE_COORD25_EXT" },
+ { 0x87B7, "GL_OUTPUT_TEXTURE_COORD26_EXT" },
+ { 0x87B8, "GL_OUTPUT_TEXTURE_COORD27_EXT" },
+ { 0x87B9, "GL_OUTPUT_TEXTURE_COORD28_EXT" },
+ { 0x87BA, "GL_OUTPUT_TEXTURE_COORD29_EXT" },
+ { 0x87BB, "GL_OUTPUT_TEXTURE_COORD30_EXT" },
+ { 0x87BC, "GL_OUTPUT_TEXTURE_COORD31_EXT" },
+ { 0x87BD, "GL_OUTPUT_FOG_EXT" },
+ { 0x87BE, "GL_SCALAR_EXT" },
+ { 0x87BF, "GL_VECTOR_EXT" },
+ { 0x87C0, "GL_MATRIX_EXT" },
+ { 0x87C1, "GL_VARIANT_EXT" },
+ { 0x87C2, "GL_INVARIANT_EXT" },
+ { 0x87C3, "GL_LOCAL_CONSTANT_EXT" },
+ { 0x87C4, "GL_LOCAL_EXT" },
+ { 0x87C5, "GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT" },
+ { 0x87C6, "GL_MAX_VERTEX_SHADER_VARIANTS_EXT" },
+ { 0x87C7, "GL_MAX_VERTEX_SHADER_INVARIANTS_EXT" },
+ { 0x87C8, "GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT" },
+ { 0x87C9, "GL_MAX_VERTEX_SHADER_LOCALS_EXT" },
+ { 0x87CA, "GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT" },
+ { 0x87CB, "GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT" },
+ { 0x87CC, "GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT" },
+ { 0x87CD, "GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT" },
+ { 0x87CE, "GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT" },
+ { 0x87CF, "GL_VERTEX_SHADER_INSTRUCTIONS_EXT" },
+ { 0x87D0, "GL_VERTEX_SHADER_VARIANTS_EXT" },
+ { 0x87D1, "GL_VERTEX_SHADER_INVARIANTS_EXT" },
+ { 0x87D2, "GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT" },
+ { 0x87D3, "GL_VERTEX_SHADER_LOCALS_EXT" },
+ { 0x87D4, "GL_VERTEX_SHADER_OPTIMIZED_EXT" },
+ { 0x87D5, "GL_X_EXT" },
+ { 0x87D6, "GL_Y_EXT" },
+ { 0x87D7, "GL_Z_EXT" },
+ { 0x87D8, "GL_W_EXT" },
+ { 0x87D9, "GL_NEGATIVE_X_EXT" },
+ { 0x87DA, "GL_NEGATIVE_Y_EXT" },
+ { 0x87DB, "GL_NEGATIVE_Z_EXT" },
+ { 0x87DC, "GL_NEGATIVE_W_EXT" },
+ { 0x87DF, "GL_NEGATIVE_ONE_EXT" },
+ { 0x87E0, "GL_NORMALIZED_RANGE_EXT" },
+ { 0x87E1, "GL_FULL_RANGE_EXT" },
+ { 0x87E2, "GL_CURRENT_VERTEX_EXT" },
+ { 0x87E3, "GL_MVP_MATRIX_EXT" },
+ { 0x87E4, "GL_VARIANT_VALUE_EXT" },
+ { 0x87E5, "GL_VARIANT_DATATYPE_EXT" },
+ { 0x87E6, "GL_VARIANT_ARRAY_STRIDE_EXT" },
+ { 0x87E7, "GL_VARIANT_ARRAY_TYPE_EXT" },
+ { 0x87E8, "GL_VARIANT_ARRAY_EXT" },
+ { 0x87E9, "GL_VARIANT_ARRAY_POINTER_EXT" },
+ { 0x87EA, "GL_INVARIANT_VALUE_EXT" },
+ { 0x87EB, "GL_INVARIANT_DATATYPE_EXT" },
+ { 0x87EC, "GL_LOCAL_CONSTANT_VALUE_EXT" },
+ { 0x87Ed, "GL_LOCAL_CONSTANT_DATATYPE_EXT" },
+ { 0x8800, "GL_STENCIL_BACK_FUNC_ATI" },
+ { 0x8800, "GL_STENCIL_BACK_FUNC" },
+ { 0x8801, "GL_STENCIL_BACK_FAIL_ATI" },
+ { 0x8801, "GL_STENCIL_BACK_FAIL" },
+ { 0x8802, "GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI" },
+ { 0x8802, "GL_STENCIL_BACK_PASS_DEPTH_FAIL" },
+ { 0x8803, "GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI" },
+ { 0x8803, "GL_STENCIL_BACK_PASS_DEPTH_PASS" },
+ { 0x8804, "GL_FRAGMENT_PROGRAM_ARB" },
+ { 0x8805, "GL_PROGRAM_ALU_INSTRUCTIONS_ARB" },
+ { 0x8806, "GL_PROGRAM_TEX_INSTRUCTIONS_ARB" },
+ { 0x8807, "GL_PROGRAM_TEX_INDIRECTIONS_ARB" },
+ { 0x8808, "GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB" },
+ { 0x8809, "GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB" },
+ { 0x880A, "GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB" },
+ { 0x880B, "GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB" },
+ { 0x880C, "GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB" },
+ { 0x880D, "GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB" },
+ { 0x880E, "GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB" },
+ { 0x880F, "GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB" },
+ { 0x8810, "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB" },
+ { 0x8814, "GL_RGBA_FLOAT32_APPLE" },
+ { 0x8814, "GL_RGBA_FLOAT32_ATI" },
+ { 0x8814, "GL_RGBA32F_ARB" },
+ { 0x8815, "GL_RGB_FLOAT32_APPLE" },
+ { 0x8815, "GL_RGB_FLOAT32_ATI" },
+ { 0x8815, "GL_RGB32F_ARB" },
+ { 0x8816, "GL_ALPHA_FLOAT32_APPLE" },
+ { 0x8816, "GL_ALPHA_FLOAT32_ATI" },
+ { 0x8816, "GL_ALPHA32F_ARB" },
+ { 0x8817, "GL_INTENSITY_FLOAT32_APPLE" },
+ { 0x8817, "GL_INTENSITY_FLOAT32_ATI" },
+ { 0x8817, "GL_INTENSITY32F_ARB" },
+ { 0x8818, "GL_LUMINANCE_FLOAT32_APPLE" },
+ { 0x8818, "GL_LUMINANCE_FLOAT32_ATI" },
+ { 0x8818, "GL_LUMINANCE32F_ARB" },
+ { 0x8819, "GL_LUMINANCE_ALPHA_FLOAT32_APPLE" },
+ { 0x8819, "GL_LUMINANCE_ALPHA_FLOAT32_ATI" },
+ { 0x8819, "GL_LUMINANCE_ALPHA32F_ARB" },
+ { 0x881A, "GL_RGBA_FLOAT16_APPLE" },
+ { 0x881A, "GL_RGBA_FLOAT16_ATI" },
+ { 0x881A, "GL_RGBA16F_ARB" },
+ { 0x881B, "GL_RGB_FLOAT16_APPLE" },
+ { 0x881B, "GL_RGB_FLOAT16_ATI" },
+ { 0x881B, "GL_RGB16F_ARB" },
+ { 0x881C, "GL_ALPHA_FLOAT16_APPLE" },
+ { 0x881C, "GL_ALPHA_FLOAT16_ATI" },
+ { 0x881C, "GL_ALPHA16F_ARB" },
+ { 0x881D, "GL_INTENSITY_FLOAT16_APPLE" },
+ { 0x881D, "GL_INTENSITY_FLOAT16_ATI" },
+ { 0x881D, "GL_INTENSITY16F_ARB" },
+ { 0x881E, "GL_LUMINANCE_FLOAT16_APPLE" },
+ { 0x881E, "GL_LUMINANCE_FLOAT16_ATI" },
+ { 0x881E, "GL_LUMINANCE16F_ARB" },
+ { 0x881F, "GL_LUMINANCE_ALPHA_FLOAT16_APPLE" },
+ { 0x881F, "GL_LUMINANCE_ALPHA_FLOAT16_ATI" },
+ { 0x881F, "GL_LUMINANCE_ALPHA16F_ARB" },
+ { 0x8820, "GL_RGBA_FLOAT_MODE_ARB" },
+ { 0x8824, "GL_MAX_DRAW_BUFFERS_ARB" },
+ { 0x8824, "GL_MAX_DRAW_BUFFERS" },
+ { 0x8825, "GL_DRAW_BUFFER0_ARB" },
+ { 0x8825, "GL_DRAW_BUFFER0" },
+ { 0x8826, "GL_DRAW_BUFFER1_ARB" },
+ { 0x8826, "GL_DRAW_BUFFER1" },
+ { 0x8827, "GL_DRAW_BUFFER2_ARB" },
+ { 0x8827, "GL_DRAW_BUFFER2" },
+ { 0x8828, "GL_DRAW_BUFFER3_ARB" },
+ { 0x8828, "GL_DRAW_BUFFER3" },
+ { 0x8829, "GL_DRAW_BUFFER4_ARB" },
+ { 0x8829, "GL_DRAW_BUFFER4" },
+ { 0x882A, "GL_DRAW_BUFFER5_ARB" },
+ { 0x882A, "GL_DRAW_BUFFER5" },
+ { 0x882B, "GL_DRAW_BUFFER6_ARB" },
+ { 0x882B, "GL_DRAW_BUFFER6" },
+ { 0x882C, "GL_DRAW_BUFFER7_ARB" },
+ { 0x882C, "GL_DRAW_BUFFER7" },
+ { 0x882D, "GL_DRAW_BUFFER8_ARB" },
+ { 0x882D, "GL_DRAW_BUFFER8" },
+ { 0x882E, "GL_DRAW_BUFFER9_ARB" },
+ { 0x882E, "GL_DRAW_BUFFER9" },
+ { 0x882F, "GL_DRAW_BUFFER10_ARB" },
+ { 0x882F, "GL_DRAW_BUFFER10" },
+ { 0x8830, "GL_DRAW_BUFFER11_ARB" },
+ { 0x8830, "GL_DRAW_BUFFER11" },
+ { 0x8831, "GL_DRAW_BUFFER12_ARB" },
+ { 0x8831, "GL_DRAW_BUFFER12" },
+ { 0x8832, "GL_DRAW_BUFFER13_ARB" },
+ { 0x8832, "GL_DRAW_BUFFER13" },
+ { 0x8833, "GL_DRAW_BUFFER14_ARB" },
+ { 0x8833, "GL_DRAW_BUFFER14" },
+ { 0x8834, "GL_DRAW_BUFFER15_ARB" },
+ { 0x8834, "GL_DRAW_BUFFER15" },
+ { 0x883D, "GL_ALPHA_BLEND_EQUATION_ATI" },
+ { 0x883D, "GL_BLEND_EQUATION_ALPHA_EXT" },
+ { 0x883D, "GL_BLEND_EQUATION_ALPHA" },
+ { 0x884A, "GL_TEXTURE_DEPTH_SIZE_ARB" },
+ { 0x884A, "GL_TEXTURE_DEPTH_SIZE" },
+ { 0x884B, "GL_DEPTH_TEXTURE_MODE_ARB" },
+ { 0x884B, "GL_DEPTH_TEXTURE_MODE" },
+ { 0x884C, "GL_TEXTURE_COMPARE_MODE_ARB" },
+ { 0x884C, "GL_TEXTURE_COMPARE_MODE" },
+ { 0x884D, "GL_TEXTURE_COMPARE_FUNC_ARB" },
+ { 0x884D, "GL_TEXTURE_COMPARE_FUNC" },
+ { 0x884E, "GL_COMPARE_R_TO_TEXTURE_ARB" },
+ { 0x884E, "GL_COMPARE_R_TO_TEXTURE" },
+ { 0x884E, "GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT" },
+ { 0x8861, "GL_POINT_SPRITE_ARB" },
+ { 0x8861, "GL_POINT_SPRITE" },
+ { 0x8862, "GL_COORD_REPLACE_ARB" },
+ { 0x8862, "GL_COORD_REPLACE" },
+ { 0x8864, "GL_QUERY_COUNTER_BITS_ARB" },
+ { 0x8864, "GL_QUERY_COUNTER_BITS" },
+ { 0x8865, "GL_CURRENT_QUERY_ARB" },
+ { 0x8865, "GL_CURRENT_QUERY" },
+ { 0x8866, "GL_QUERY_RESULT_ARB" },
+ { 0x8866, "GL_QUERY_RESULT" },
+ { 0x8867, "GL_QUERY_RESULT_AVAILABLE_ARB" },
+ { 0x8867, "GL_QUERY_RESULT_AVAILABLE" },
+ { 0x8869, "GL_MAX_VERTEX_ATTRIBS_ARB" },
+ { 0x8869, "GL_MAX_VERTEX_ATTRIBS_ARB" },
+ { 0x8869, "GL_MAX_VERTEX_ATTRIBS" },
+ { 0x886A, "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB" },
+ { 0x886A, "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB" },
+ { 0x886A, "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED" },
+ { 0x8871, "GL_MAX_TEXTURE_COORDS_ARB" },
+ { 0x8871, "GL_MAX_TEXTURE_COORDS_ARB" },
+ { 0x8871, "GL_MAX_TEXTURE_COORDS_ARB" },
+ { 0x8871, "GL_MAX_TEXTURE_COORDS" },
+ { 0x8872, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
+ { 0x8872, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
+ { 0x8872, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
+ { 0x8872, "GL_MAX_TEXTURE_IMAGE_UNITS" },
+ { 0x8874, "GL_PROGRAM_ERROR_STRING_ARB" },
+ { 0x8875, "GL_PROGRAM_FORMAT_ASCII_ARB" },
+ { 0x8876, "GL_PROGRAM_FORMAT_ARB" },
+ { 0x8890, "GL_DEPTH_BOUNDS_TEST_EXT" },
+ { 0x8891, "GL_DEPTH_BOUNDS_EXT" },
+ { 0x8892, "GL_ARRAY_BUFFER_ARB" },
+ { 0x8892, "GL_ARRAY_BUFFER" },
+ { 0x8893, "GL_ELEMENT_ARRAY_BUFFER_ARB" },
+ { 0x8893, "GL_ELEMENT_ARRAY_BUFFER" },
+ { 0x8894, "GL_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x8894, "GL_ARRAY_BUFFER_BINDING" },
+ { 0x8895, "GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x8895, "GL_ELEMENT_ARRAY_BUFFER_BINDING" },
+ { 0x8896, "GL_VERTEX_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x8896, "GL_VERTEX_ARRAY_BUFFER_BINDING" },
+ { 0x8897, "GL_NORMAL_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x8897, "GL_NORMAL_ARRAY_BUFFER_BINDING" },
+ { 0x8898, "GL_COLOR_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x8898, "GL_COLOR_ARRAY_BUFFER_BINDING" },
+ { 0x8899, "GL_INDEX_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x8899, "GL_INDEX_ARRAY_BUFFER_BINDING" },
+ { 0x889A, "GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x889A, "GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING" },
+ { 0x889B, "GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x889B, "GL_EDGE_FLAG_ARRAY_BUFFER_BINDING" },
+ { 0x889C, "GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x889C, "GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING" },
+ { 0x889D, "GL_FOG_COORD_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x889D, "GL_FOG_COORD_ARRAY_BUFFER_BINDING" },
+ { 0x889D, "GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x889D, "GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING" },
+ { 0x889E, "GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x889E, "GL_WEIGHT_ARRAY_BUFFER_BINDING" },
+ { 0x889F, "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB" },
+ { 0x889F, "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING" },
+ { 0x88A0, "GL_PROGRAM_INSTRUCTIONS_ARB" },
+ { 0x88A1, "GL_MAX_PROGRAM_INSTRUCTIONS_ARB" },
+ { 0x88A2, "GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB" },
+ { 0x88A3, "GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB" },
+ { 0x88A4, "GL_PROGRAM_TEMPORARIES_ARB" },
+ { 0x88A5, "GL_MAX_PROGRAM_TEMPORARIES_ARB" },
+ { 0x88A6, "GL_PROGRAM_NATIVE_TEMPORARIES_ARB" },
+ { 0x88A7, "GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB" },
+ { 0x88A8, "GL_PROGRAM_PARAMETERS_ARB" },
+ { 0x88A9, "GL_MAX_PROGRAM_PARAMETERS_ARB" },
+ { 0x88AA, "GL_PROGRAM_NATIVE_PARAMETERS_ARB" },
+ { 0x88AB, "GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB" },
+ { 0x88AC, "GL_PROGRAM_ATTRIBS_ARB" },
+ { 0x88AD, "GL_MAX_PROGRAM_ATTRIBS_ARB" },
+ { 0x88AE, "GL_PROGRAM_NATIVE_ATTRIBS_ARB" },
+ { 0x88AF, "GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB" },
+ { 0x88B0, "GL_PROGRAM_ADDRESS_REGISTERS_ARB" },
+ { 0x88B1, "GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB" },
+ { 0x88B2, "GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB" },
+ { 0x88B3, "GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB" },
+ { 0x88B4, "GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB" },
+ { 0x88B5, "GL_MAX_PROGRAM_ENV_PARAMETERS_ARB" },
+ { 0x88B6, "GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB" },
+ { 0x88B7, "GL_TRANSPOSE_CURRENT_MATRIX_ARB" },
+ { 0x88B8, "GL_READ_ONLY_ARB" },
+ { 0x88B8, "GL_READ_ONLY" },
+ { 0x88B9, "GL_WRITE_ONLY_ARB" },
+ { 0x88B9, "GL_WRITE_ONLY" },
+ { 0x88BA, "GL_READ_WRITE_ARB" },
+ { 0x88BA, "GL_READ_WRITE" },
+ { 0x88BB, "GL_BUFFER_ACCESS_ARB" },
+ { 0x88BB, "GL_BUFFER_ACCESS" },
+ { 0x88BC, "GL_BUFFER_MAPPED_ARB" },
+ { 0x88BC, "GL_BUFFER_MAPPED" },
+ { 0x88BD, "GL_BUFFER_MAP_POINTER_ARB" },
+ { 0x88BD, "GL_BUFFER_MAP_POINTER" },
+ { 0x88C0, "GL_MATRIX0_ARB" },
+ { 0x88C1, "GL_MATRIX1_ARB" },
+ { 0x88C2, "GL_MATRIX2_ARB" },
+ { 0x88C3, "GL_MATRIX3_ARB" },
+ { 0x88C4, "GL_MATRIX4_ARB" },
+ { 0x88C5, "GL_MATRIX5_ARB" },
+ { 0x88C6, "GL_MATRIX6_ARB" },
+ { 0x88C7, "GL_MATRIX7_ARB" },
+ { 0x88C8, "GL_MATRIX8_ARB" },
+ { 0x88C9, "GL_MATRIX9_ARB" },
+ { 0x88CA, "GL_MATRIX10_ARB" },
+ { 0x88CB, "GL_MATRIX11_ARB" },
+ { 0x88CC, "GL_MATRIX12_ARB" },
+ { 0x88CD, "GL_MATRIX13_ARB" },
+ { 0x88CE, "GL_MATRIX14_ARB" },
+ { 0x88CF, "GL_MATRIX15_ARB" },
+ { 0x88D0, "GL_MATRIX16_ARB" },
+ { 0x88D1, "GL_MATRIX17_ARB" },
+ { 0x88D2, "GL_MATRIX18_ARB" },
+ { 0x88D3, "GL_MATRIX19_ARB" },
+ { 0x88D4, "GL_MATRIX20_ARB" },
+ { 0x88D5, "GL_MATRIX21_ARB" },
+ { 0x88D6, "GL_MATRIX22_ARB" },
+ { 0x88D7, "GL_MATRIX23_ARB" },
+ { 0x88D8, "GL_MATRIX24_ARB" },
+ { 0x88D9, "GL_MATRIX25_ARB" },
+ { 0x88DA, "GL_MATRIX26_ARB" },
+ { 0x88DB, "GL_MATRIX27_ARB" },
+ { 0x88DC, "GL_MATRIX28_ARB" },
+ { 0x88DD, "GL_MATRIX29_ARB" },
+ { 0x88DE, "GL_MATRIX30_ARB" },
+ { 0x88DF, "GL_MATRIX31_ARB" },
+ { 0x88E0, "GL_STREAM_DRAW_ARB" },
+ { 0x88E0, "GL_STREAM_DRAW" },
+ { 0x88E1, "GL_STREAM_READ_ARB" },
+ { 0x88E1, "GL_STREAM_READ" },
+ { 0x88E2, "GL_STREAM_COPY_ARB" },
+ { 0x88E2, "GL_STREAM_COPY" },
+ { 0x88E4, "GL_STATIC_DRAW_ARB" },
+ { 0x88E4, "GL_STATIC_DRAW" },
+ { 0x88E5, "GL_STATIC_READ_ARB" },
+ { 0x88E5, "GL_STATIC_READ" },
+ { 0x88E6, "GL_STATIC_COPY_ARB" },
+ { 0x88E6, "GL_STATIC_COPY" },
+ { 0x88E8, "GL_DYNAMIC_DRAW_ARB" },
+ { 0x88E8, "GL_DYNAMIC_DRAW" },
+ { 0x88E9, "GL_DYNAMIC_READ_ARB" },
+ { 0x88E9, "GL_DYNAMIC_READ" },
+ { 0x88EA, "GL_DYNAMIC_COPY_ARB" },
+ { 0x88EA, "GL_DYNAMIC_COPY" },
+ { 0x88EB, "GL_PIXEL_PACK_BUFFER_ARB" },
+ { 0x88EB, "GL_PIXEL_PACK_BUFFER" },
+ { 0x88EC, "GL_PIXEL_UNPACK_BUFFER_ARB" },
+ { 0x88EC, "GL_PIXEL_UNPACK_BUFFER" },
+ { 0x88ED, "GL_PIXEL_PACK_BUFFER_BINDING_ARB" },
+ { 0x88ED, "GL_PIXEL_PACK_BUFFER_BINDING" },
+ { 0x88EF, "GL_PIXEL_UNPACK_BUFFER_BINDING_ARB" },
+ { 0x88EF, "GL_PIXEL_UNPACK_BUFFER_BINDING" },
+ { 0x88F0, "GL_DEPTH24_STENCIL8_EXT" },
+ { 0x88F0, "GL_DEPTH24_STENCIL8" },
+ { 0x88F1, "GL_TEXTURE_STENCIL_SIZE_EXT" },
+ { 0x88F1, "GL_TEXTURE_STENCIL_SIZE" },
+ { 0x88FD, "GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT" },
+ { 0x88FE, "GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB" },
+ { 0x88FF, "GL_MAX_ARRAY_TEXTURE_LAYERS_EXT" },
+ { 0x8904, "GL_MIN_PROGRAM_TEXEL_OFFSET_EXT" },
+ { 0x8905, "GL_MAX_PROGRAM_TEXEL_OFFSET_EXT" },
+ { 0x8910, "GL_STENCIL_TEST_TWO_SIDE_EXT" },
+ { 0x8911, "GL_ACTIVE_STENCIL_FACE_EXT" },
+ { 0x8912, "GL_MIRROR_CLAMP_TO_BORDER_EXT" },
+ { 0x8914, "GL_SAMPLES_PASSED_ARB" },
+ { 0x8914, "GL_SAMPLES_PASSED" },
+ { 0x891A, "GL_CLAMP_VERTEX_COLOR_ARB" },
+ { 0x891B, "GL_CLAMP_FRAGMENT_COLOR_ARB" },
+ { 0x891C, "GL_CLAMP_READ_COLOR_ARB" },
+ { 0x891D, "GL_FIXED_ONLY_ARB" },
+ { 0x8920, "GL_FRAGMENT_SHADER_EXT" },
+ { 0x896D, "GL_SECONDARY_INTERPOLATOR_EXT" },
+ { 0x896E, "GL_NUM_FRAGMENT_REGISTERS_EXT" },
+ { 0x896F, "GL_NUM_FRAGMENT_CONSTANTS_EXT" },
+ { 0x8A0C, "GL_ELEMENT_ARRAY_APPLE" },
+ { 0x8A0D, "GL_ELEMENT_ARRAY_TYPE_APPLE" },
+ { 0x8A0E, "GL_ELEMENT_ARRAY_POINTER_APPLE" },
+ { 0x8A0F, "GL_COLOR_FLOAT_APPLE" },
+ { 0x8A11, "GL_UNIFORM_BUFFER" },
+ { 0x8A28, "GL_UNIFORM_BUFFER_BINDING" },
+ { 0x8A29, "GL_UNIFORM_BUFFER_START" },
+ { 0x8A2A, "GL_UNIFORM_BUFFER_SIZE" },
+ { 0x8A2B, "GL_MAX_VERTEX_UNIFORM_BLOCKS" },
+ { 0x8A2C, "GL_MAX_GEOMETRY_UNIFORM_BLOCKS" },
+ { 0x8A2D, "GL_MAX_FRAGMENT_UNIFORM_BLOCKS" },
+ { 0x8A2E, "GL_MAX_COMBINED_UNIFORM_BLOCKS" },
+ { 0x8A2F, "GL_MAX_UNIFORM_BUFFER_BINDINGS" },
+ { 0x8A30, "GL_MAX_UNIFORM_BLOCK_SIZE" },
+ { 0x8A31, "GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS" },
+ { 0x8A32, "GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS" },
+ { 0x8A33, "GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS" },
+ { 0x8A34, "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT" },
+ { 0x8A35, "GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH" },
+ { 0x8A36, "GL_ACTIVE_UNIFORM_BLOCKS" },
+ { 0x8A37, "GL_UNIFORM_TYPE" },
+ { 0x8A38, "GL_UNIFORM_SIZE" },
+ { 0x8A39, "GL_UNIFORM_NAME_LENGTH" },
+ { 0x8A3A, "GL_UNIFORM_BLOCK_INDEX" },
+ { 0x8A3B, "GL_UNIFORM_OFFSET" },
+ { 0x8A3C, "GL_UNIFORM_ARRAY_STRIDE" },
+ { 0x8A3D, "GL_UNIFORM_MATRIX_STRIDE" },
+ { 0x8A3E, "GL_UNIFORM_IS_ROW_MAJOR" },
+ { 0x8A3F, "GL_UNIFORM_BLOCK_BINDING" },
+ { 0x8A40, "GL_UNIFORM_BLOCK_DATA_SIZE" },
+ { 0x8A41, "GL_UNIFORM_BLOCK_NAME_LENGTH" },
+ { 0x8A42, "GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS" },
+ { 0x8A43, "GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES" },
+ { 0x8A44, "GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER" },
+ { 0x8A45, "GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER" },
+ { 0x8A46, "GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER" },
+ { 0x8B30, "GL_FRAGMENT_SHADER_ARB" },
+ { 0x8B30, "GL_FRAGMENT_SHADER" },
+ { 0x8B31, "GL_VERTEX_SHADER_ARB" },
+ { 0x8B31, "GL_VERTEX_SHADER" },
+ { 0x8B40, "GL_PROGRAM_OBJECT_ARB" },
+ { 0x8B48, "GL_SHADER_OBJECT_ARB" },
+ { 0x8B49, "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB" },
+ { 0x8B49, "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS" },
+ { 0x8B4A, "GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB" },
+ { 0x8B4A, "GL_MAX_VERTEX_UNIFORM_COMPONENTS" },
+ { 0x8B4B, "GL_MAX_VARYING_COMPONENTS_EXT" },
+ { 0x8B4B, "GL_MAX_VARYING_FLOATS_ARB" },
+ { 0x8B4B, "GL_MAX_VARYING_FLOATS" },
+ { 0x8B4C, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB" },
+ { 0x8B4C, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS" },
+ { 0x8B4D, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB" },
+ { 0x8B4D, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS" },
+ { 0x8B4E, "GL_OBJECT_TYPE_ARB" },
+ { 0x8B4F, "GL_OBJECT_SUBTYPE_ARB" },
+ { 0x8B4F, "GL_SHADER_TYPE" },
+ { 0x8B50, "GL_FLOAT_VEC2_ARB" },
+ { 0x8B50, "GL_FLOAT_VEC2" },
+ { 0x8B51, "GL_FLOAT_VEC3_ARB" },
+ { 0x8B51, "GL_FLOAT_VEC3" },
+ { 0x8B52, "GL_FLOAT_VEC4_ARB" },
+ { 0x8B52, "GL_FLOAT_VEC4" },
+ { 0x8B53, "GL_INT_VEC2_ARB" },
+ { 0x8B53, "GL_INT_VEC2" },
+ { 0x8B54, "GL_INT_VEC3_ARB" },
+ { 0x8B54, "GL_INT_VEC3" },
+ { 0x8B55, "GL_INT_VEC4_ARB" },
+ { 0x8B55, "GL_INT_VEC4" },
+ { 0x8B56, "GL_BOOL_ARB" },
+ { 0x8B56, "GL_BOOL" },
+ { 0x8B57, "GL_BOOL_VEC2_ARB" },
+ { 0x8B57, "GL_BOOL_VEC2" },
+ { 0x8B58, "GL_BOOL_VEC3_ARB" },
+ { 0x8B58, "GL_BOOL_VEC3" },
+ { 0x8B59, "GL_BOOL_VEC4_ARB" },
+ { 0x8B59, "GL_BOOL_VEC4" },
+ { 0x8B5A, "GL_FLOAT_MAT2_ARB" },
+ { 0x8B5A, "GL_FLOAT_MAT2" },
+ { 0x8B5B, "GL_FLOAT_MAT3_ARB" },
+ { 0x8B5B, "GL_FLOAT_MAT3" },
+ { 0x8B5C, "GL_FLOAT_MAT4_ARB" },
+ { 0x8B5C, "GL_FLOAT_MAT4" },
+ { 0x8B5D, "GL_SAMPLER_1D_ARB" },
+ { 0x8B5D, "GL_SAMPLER_1D" },
+ { 0x8B5E, "GL_SAMPLER_2D_ARB" },
+ { 0x8B5E, "GL_SAMPLER_2D" },
+ { 0x8B5F, "GL_SAMPLER_3D_ARB" },
+ { 0x8B5F, "GL_SAMPLER_3D" },
+ { 0x8B60, "GL_SAMPLER_CUBE_ARB" },
+ { 0x8B60, "GL_SAMPLER_CUBE" },
+ { 0x8B61, "GL_SAMPLER_1D_SHADOW_ARB" },
+ { 0x8B61, "GL_SAMPLER_1D_SHADOW" },
+ { 0x8B62, "GL_SAMPLER_2D_SHADOW_ARB" },
+ { 0x8B62, "GL_SAMPLER_2D_SHADOW" },
+ { 0x8B63, "GL_SAMPLER_2D_RECT_ARB" },
+ { 0x8B64, "GL_SAMPLER_2D_RECT_SHADOW_ARB" },
+ { 0x8B65, "GL_FLOAT_MAT2x3" },
+ { 0x8B66, "GL_FLOAT_MAT2x4" },
+ { 0x8B67, "GL_FLOAT_MAT3x2" },
+ { 0x8B68, "GL_FLOAT_MAT3x4" },
+ { 0x8B69, "GL_FLOAT_MAT4x2" },
+ { 0x8B6A, "GL_FLOAT_MAT4x3" },
+ { 0x8B80, "GL_DELETE_STATUS" },
+ { 0x8B80, "GL_OBJECT_DELETE_STATUS_ARB" },
+ { 0x8B81, "GL_COMPILE_STATUS" },
+ { 0x8B81, "GL_OBJECT_COMPILE_STATUS_ARB" },
+ { 0x8B82, "GL_LINK_STATUS" },
+ { 0x8B82, "GL_OBJECT_LINK_STATUS_ARB" },
+ { 0x8B83, "GL_OBJECT_VALIDATE_STATUS_ARB" },
+ { 0x8B83, "GL_VALIDATE_STATUS" },
+ { 0x8B84, "GL_INFO_LOG_LENGTH" },
+ { 0x8B84, "GL_OBJECT_INFO_LOG_LENGTH_ARB" },
+ { 0x8B85, "GL_ATTACHED_SHADERS" },
+ { 0x8B85, "GL_OBJECT_ATTACHED_OBJECTS_ARB" },
+ { 0x8B86, "GL_ACTIVE_UNIFORMS" },
+ { 0x8B86, "GL_OBJECT_ACTIVE_UNIFORMS_ARB" },
+ { 0x8B87, "GL_ACTIVE_UNIFORM_MAX_LENGTH" },
+ { 0x8B87, "GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB" },
+ { 0x8B88, "GL_OBJECT_SHADER_SOURCE_LENGTH_ARB" },
+ { 0x8B88, "GL_SHADER_SOURCE_LENGTH" },
+ { 0x8B89, "GL_ACTIVE_ATTRIBUTES" },
+ { 0x8B89, "GL_OBJECT_ACTIVE_ATTRIBUTES_ARB" },
+ { 0x8B8A, "GL_ACTIVE_ATTRIBUTE_MAX_LENGTH" },
+ { 0x8B8A, "GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB" },
+ { 0x8B8B, "GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB" },
+ { 0x8B8B, "GL_FRAGMENT_SHADER_DERIVATIVE_HINT" },
+ { 0x8B8C, "GL_SHADING_LANGUAGE_VERSION_ARB" },
+ { 0x8B8C, "GL_SHADING_LANGUAGE_VERSION" },
+ { 0x8B8D, "GL_CURRENT_PROGRAM" },
+ { 0x8C10, "GL_TEXTURE_RED_TYPE_ARB" },
+ { 0x8C10, "GL_TEXTURE_RED_TYPE" },
+ { 0x8C11, "GL_TEXTURE_GREEN_TYPE_ARB" },
+ { 0x8C11, "GL_TEXTURE_GREEN_TYPE" },
+ { 0x8C12, "GL_TEXTURE_BLUE_TYPE_ARB" },
+ { 0x8C12, "GL_TEXTURE_BLUE_TYPE" },
+ { 0x8C13, "GL_TEXTURE_ALPHA_TYPE_ARB" },
+ { 0x8C13, "GL_TEXTURE_ALPHA_TYPE" },
+ { 0x8C14, "GL_TEXTURE_LUMINANCE_TYPE_ARB" },
+ { 0x8C15, "GL_TEXTURE_INTENSITY_TYPE_ARB" },
+ { 0x8C16, "GL_TEXTURE_DEPTH_TYPE_ARB" },
+ { 0x8C16, "GL_TEXTURE_DEPTH_TYPE" },
+ { 0x8C17, "GL_UNSIGNED_NORMALIZED_ARB" },
+ { 0x8C17, "GL_UNSIGNED_NORMALIZED" },
+ { 0x8C18, "GL_TEXTURE_1D_ARRAY_EXT" },
+ { 0x8C19, "GL_PROXY_TEXTURE_1D_ARRAY_EXT" },
+ { 0x8C1A, "GL_TEXTURE_2D_ARRAY_EXT" },
+ { 0x8C1B, "GL_PROXY_TEXTURE_2D_ARRAY_EXT" },
+ { 0x8C1C, "GL_TEXTURE_BINDING_1D_ARRAY_EXT" },
+ { 0x8C1D, "GL_TEXTURE_BINDING_2D_ARRAY_EXT" },
+ { 0x8C29, "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT" },
+ { 0x8C3A, "GL_R11F_G11F_B10F_EXT" },
+ { 0x8C3B, "GL_UNSIGNED_INT_10F_11F_11F_REV_EXT" },
+ { 0x8C3C, "GL_RGBA_SIGNED_COMPONENTS_EXT" },
+ { 0x8C3D, "GL_RGB9_E5_EXT" },
+ { 0x8C3E, "GL_UNSIGNED_INT_5_9_9_9_REV_EXT" },
+ { 0x8C3F, "GL_TEXTURE_SHARED_SIZE_EXT" },
+ { 0x8C40, "GL_SRGB_EXT" },
+ { 0x8C40, "GL_SRGB" },
+ { 0x8C41, "GL_SRGB8_EXT" },
+ { 0x8C41, "GL_SRGB8" },
+ { 0x8C42, "GL_SRGB_ALPHA_EXT" },
+ { 0x8C42, "GL_SRGB_ALPHA" },
+ { 0x8C43, "GL_SRGB8_ALPHA8_EXT" },
+ { 0x8C43, "GL_SRGB8_ALPHA8" },
+ { 0x8C44, "GL_SLUMINANCE_ALPHA_EXT" },
+ { 0x8C44, "GL_SLUMINANCE_ALPHA" },
+ { 0x8C45, "GL_SLUMINANCE8_ALPHA8_EXT" },
+ { 0x8C45, "GL_SLUMINANCE8_ALPHA8" },
+ { 0x8C46, "GL_SLUMINANCE_EXT" },
+ { 0x8C46, "GL_SLUMINANCE" },
+ { 0x8C47, "GL_SLUMINANCE8_EXT" },
+ { 0x8C47, "GL_SLUMINANCE8" },
+ { 0x8C48, "GL_COMPRESSED_SRGB_EXT" },
+ { 0x8C48, "GL_COMPRESSED_SRGB" },
+ { 0x8C49, "GL_COMPRESSED_SRGB_ALPHA_EXT" },
+ { 0x8C49, "GL_COMPRESSED_SRGB_ALPHA" },
+ { 0x8C4A, "GL_COMPRESSED_SLUMINANCE_EXT" },
+ { 0x8C4A, "GL_COMPRESSED_SLUMINANCE" },
+ { 0x8C4B, "GL_COMPRESSED_SLUMINANCE_ALPHA_EXT" },
+ { 0x8C4B, "GL_COMPRESSED_SLUMINANCE_ALPHA" },
+ { 0x8C4C, "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT" },
+ { 0x8C4D, "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT" },
+ { 0x8C4E, "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT" },
+ { 0x8C4F, "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT" },
+ { 0x8C76, "GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT" },
+ { 0x8C7F, "GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT" },
+ { 0x8C80, "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT" },
+ { 0x8C83, "GL_TRANSFORM_FEEDBACK_VARYINGS_EXT" },
+ { 0x8C84, "GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT" },
+ { 0x8C85, "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT" },
+ { 0x8C87, "GL_PRIMITIVES_GENERATED_EXT" },
+ { 0x8C88, "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT" },
+ { 0x8C89, "GL_RASTERIZER_DISCARD_EXT" },
+ { 0x8C8A, "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT" },
+ { 0x8C8B, "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT" },
+ { 0x8C8C, "GL_INTERLEAVED_ATTRIBS_EXT" },
+ { 0x8C8D, "GL_SEPARATE_ATTRIBS_EXT" },
+ { 0x8C8E, "GL_TRANSFORM_FEEDBACK_BUFFER_EXT" },
+ { 0x8C8F, "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT" },
+ { 0x8CA0, "GL_POINT_SPRITE_COORD_ORIGIN" },
+ { 0x8CA1, "GL_LOWER_LEFT" },
+ { 0x8CA2, "GL_UPPER_LEFT" },
+ { 0x8CA3, "GL_STENCIL_BACK_REF" },
+ { 0x8CA4, "GL_STENCIL_BACK_VALUE_MASK" },
+ { 0x8CA5, "GL_STENCIL_BACK_WRITEMASK" },
+ { 0x8CA6, "GL_DRAW_FRAMEBUFFER_BINDING_EXT" },
+ { 0x8CA6, "GL_FRAMEBUFFER_BINDING_EXT" },
+ { 0x8CA6, "GL_FRAMEBUFFER_BINDING" },
+ { 0x8CA7, "GL_RENDERBUFFER_BINDING_EXT" },
+ { 0x8CA7, "GL_RENDERBUFFER_BINDING" },
+ { 0x8CA8, "GL_READ_FRAMEBUFFER_EXT" },
+ { 0x8CA8, "GL_READ_FRAMEBUFFER" },
+ { 0x8CA9, "GL_DRAW_FRAMEBUFFER_EXT" },
+ { 0x8CA9, "GL_DRAW_FRAMEBUFFER" },
+ { 0x8CAA, "GL_READ_FRAMEBUFFER_BINDING_EXT" },
+ { 0x8CAA, "GL_READ_FRAMEBUFFER_BINDING" },
+ { 0x8CAB, "GL_RENDERBUFFER_SAMPLES_EXT" },
+ { 0x8CAB, "GL_RENDERBUFFER_SAMPLES" },
+ { 0x8CAC, "GL_DEPTH_COMPONENT32F" },
+ { 0x8CAD, "GL_DEPTH32F_STENCIL8" },
+ { 0x8CD0, "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT" },
+ { 0x8CD0, "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE" },
+ { 0x8CD1, "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT" },
+ { 0x8CD1, "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME" },
+ { 0x8CD2, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT" },
+ { 0x8CD2, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL" },
+ { 0x8CD3, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT" },
+ { 0x8CD3, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE" },
+ { 0x8CD4, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT" },
+ { 0x8CD4, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT" },
+ { 0x8CD4, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER" },
+ { 0x8CD5, "GL_FRAMEBUFFER_COMPLETE_EXT" },
+ { 0x8CD5, "GL_FRAMEBUFFER_COMPLETE" },
+ { 0x8CD6, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT" },
+ { 0x8CD6, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT" },
+ { 0x8CD7, "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT" },
+ { 0x8CD7, "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" },
+ { 0x8CD9, "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT" },
+ { 0x8CDA, "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT" },
+ { 0x8CDB, "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT" },
+ { 0x8CDB, "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER" },
+ { 0x8CDC, "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT" },
+ { 0x8CDC, "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER" },
+ { 0x8CDD, "GL_FRAMEBUFFER_UNSUPPORTED_EXT" },
+ { 0x8CDD, "GL_FRAMEBUFFER_UNSUPPORTED" },
+ { 0x8CDF, "GL_MAX_COLOR_ATTACHMENTS_EXT" },
+ { 0x8CDF, "GL_MAX_COLOR_ATTACHMENTS" },
+ { 0x8CE0, "GL_COLOR_ATTACHMENT0_EXT" },
+ { 0x8CE0, "GL_COLOR_ATTACHMENT0" },
+ { 0x8CE1, "GL_COLOR_ATTACHMENT1_EXT" },
+ { 0x8CE1, "GL_COLOR_ATTACHMENT1" },
+ { 0x8CE2, "GL_COLOR_ATTACHMENT2_EXT" },
+ { 0x8CE2, "GL_COLOR_ATTACHMENT2" },
+ { 0x8CE3, "GL_COLOR_ATTACHMENT3_EXT" },
+ { 0x8CE3, "GL_COLOR_ATTACHMENT3" },
+ { 0x8CE4, "GL_COLOR_ATTACHMENT4_EXT" },
+ { 0x8CE4, "GL_COLOR_ATTACHMENT4" },
+ { 0x8CE5, "GL_COLOR_ATTACHMENT5_EXT" },
+ { 0x8CE5, "GL_COLOR_ATTACHMENT5" },
+ { 0x8CE6, "GL_COLOR_ATTACHMENT6_EXT" },
+ { 0x8CE6, "GL_COLOR_ATTACHMENT6" },
+ { 0x8CE7, "GL_COLOR_ATTACHMENT7_EXT" },
+ { 0x8CE7, "GL_COLOR_ATTACHMENT7" },
+ { 0x8CE8, "GL_COLOR_ATTACHMENT8_EXT" },
+ { 0x8CE8, "GL_COLOR_ATTACHMENT8" },
+ { 0x8CE9, "GL_COLOR_ATTACHMENT9_EXT" },
+ { 0x8CE9, "GL_COLOR_ATTACHMENT9" },
+ { 0x8CEA, "GL_COLOR_ATTACHMENT10_EXT" },
+ { 0x8CEA, "GL_COLOR_ATTACHMENT10" },
+ { 0x8CEB, "GL_COLOR_ATTACHMENT11_EXT" },
+ { 0x8CEB, "GL_COLOR_ATTACHMENT11" },
+ { 0x8CEC, "GL_COLOR_ATTACHMENT12_EXT" },
+ { 0x8CEC, "GL_COLOR_ATTACHMENT12" },
+ { 0x8CED, "GL_COLOR_ATTACHMENT13_EXT" },
+ { 0x8CED, "GL_COLOR_ATTACHMENT13" },
+ { 0x8CEE, "GL_COLOR_ATTACHMENT14_EXT" },
+ { 0x8CEE, "GL_COLOR_ATTACHMENT14" },
+ { 0x8CEF, "GL_COLOR_ATTACHMENT15_EXT" },
+ { 0x8CEF, "GL_COLOR_ATTACHMENT15" },
+ { 0x8D00, "GL_DEPTH_ATTACHMENT_EXT" },
+ { 0x8D00, "GL_DEPTH_ATTACHMENT" },
+ { 0x8D20, "GL_STENCIL_ATTACHMENT_EXT" },
+ { 0x8D20, "GL_STENCIL_ATTACHMENT" },
+ { 0x8D40, "GL_FRAMEBUFFER_EXT" },
+ { 0x8D40, "GL_FRAMEBUFFER" },
+ { 0x8D41, "GL_RENDERBUFFER_EXT" },
+ { 0x8D41, "GL_RENDERBUFFER" },
+ { 0x8D42, "GL_RENDERBUFFER_WIDTH_EXT" },
+ { 0x8D42, "GL_RENDERBUFFER_WIDTH" },
+ { 0x8D43, "GL_RENDERBUFFER_HEIGHT_EXT" },
+ { 0x8D43, "GL_RENDERBUFFER_HEIGHT" },
+ { 0x8D44, "GL_RENDERBUFFER_INTERNAL_FORMAT_EXT" },
+ { 0x8D44, "GL_RENDERBUFFER_INTERNAL_FORMAT" },
+ { 0x8D46, "GL_STENCIL_INDEX1_EXT" },
+ { 0x8D46, "GL_STENCIL_INDEX1" },
+ { 0x8D47, "GL_STENCIL_INDEX4_EXT" },
+ { 0x8D47, "GL_STENCIL_INDEX4" },
+ { 0x8D48, "GL_STENCIL_INDEX8_EXT" },
+ { 0x8D48, "GL_STENCIL_INDEX8" },
+ { 0x8D49, "GL_STENCIL_INDEX16_EXT" },
+ { 0x8D49, "GL_STENCIL_INDEX16" },
+ { 0x8D50, "GL_RENDERBUFFER_RED_SIZE_EXT" },
+ { 0x8D50, "GL_RENDERBUFFER_RED_SIZE" },
+ { 0x8D51, "GL_RENDERBUFFER_GREEN_SIZE_EXT" },
+ { 0x8D51, "GL_RENDERBUFFER_GREEN_SIZE" },
+ { 0x8D52, "GL_RENDERBUFFER_BLUE_SIZE_EXT" },
+ { 0x8D52, "GL_RENDERBUFFER_BLUE_SIZE" },
+ { 0x8D53, "GL_RENDERBUFFER_ALPHA_SIZE_EXT" },
+ { 0x8D53, "GL_RENDERBUFFER_ALPHA_SIZE" },
+ { 0x8D54, "GL_RENDERBUFFER_DEPTH_SIZE_EXT" },
+ { 0x8D54, "GL_RENDERBUFFER_DEPTH_SIZE" },
+ { 0x8D55, "GL_RENDERBUFFER_STENCIL_SIZE_EXT" },
+ { 0x8D55, "GL_RENDERBUFFER_STENCIL_SIZE" },
+ { 0x8D56, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT" },
+ { 0x8D56, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE" },
+ { 0x8D57, "GL_MAX_SAMPLES_EXT" },
+ { 0x8D57, "GL_MAX_SAMPLES" },
+ { 0x8D70, "GL_RGBA32UI_EXT" },
+ { 0x8D71, "GL_RGB32UI_EXT" },
+ { 0x8D72, "GL_ALPHA32UI_EXT" },
+ { 0x8D73, "GL_INTENSITY32UI_EXT" },
+ { 0x8D74, "GL_LUMINANCE32UI_EXT" },
+ { 0x8D75, "GL_LUMINANCE_ALPHA32UI_EXT" },
+ { 0x8D76, "GL_RGBA16UI_EXT" },
+ { 0x8D77, "GL_RGB16UI_EXT" },
+ { 0x8D78, "GL_ALPHA16UI_EXT" },
+ { 0x8D79, "GL_INTENSITY16UI_EXT" },
+ { 0x8D7A, "GL_LUMINANCE16UI_EXT" },
+ { 0x8D7B, "GL_LUMINANCE_ALPHA16UI_EXT" },
+ { 0x8D7C, "GL_RGBA8UI_EXT" },
+ { 0x8D7D, "GL_RGB8UI_EXT" },
+ { 0x8D7E, "GL_ALPHA8UI_EXT" },
+ { 0x8D7F, "GL_INTENSITY8UI_EXT" },
+ { 0x8D80, "GL_LUMINANCE8UI_EXT" },
+ { 0x8D81, "GL_LUMINANCE_ALPHA8UI_EXT" },
+ { 0x8D82, "GL_RGBA32I_EXT" },
+ { 0x8D83, "GL_RGB32I_EXT" },
+ { 0x8D84, "GL_ALPHA32I_EXT" },
+ { 0x8D85, "GL_INTENSITY32I_EXT" },
+ { 0x8D86, "GL_LUMINANCE32I_EXT" },
+ { 0x8D87, "GL_LUMINANCE_ALPHA32I_EXT" },
+ { 0x8D88, "GL_RGBA16I_EXT" },
+ { 0x8D89, "GL_RGB16I_EXT" },
+ { 0x8D8A, "GL_ALPHA16I_EXT" },
+ { 0x8D8B, "GL_INTENSITY16I_EXT" },
+ { 0x8D8C, "GL_LUMINANCE16I_EXT" },
+ { 0x8D8D, "GL_LUMINANCE_ALPHA16I_EXT" },
+ { 0x8D8E, "GL_RGBA8I_EXT" },
+ { 0x8D8F, "GL_RGB8I_EXT" },
+ { 0x8D90, "GL_ALPHA8I_EXT" },
+ { 0x8D91, "GL_INTENSITY8I_EXT" },
+ { 0x8D92, "GL_LUMINANCE8I_EXT" },
+ { 0x8D93, "GL_LUMINANCE_ALPHA8I_EXT" },
+ { 0x8D94, "GL_RED_INTEGER_EXT" },
+ { 0x8D95, "GL_GREEN_INTEGER_EXT" },
+ { 0x8D96, "GL_BLUE_INTEGER_EXT" },
+ { 0x8D97, "GL_ALPHA_INTEGER_EXT" },
+ { 0x8D98, "GL_RGB_INTEGER_EXT" },
+ { 0x8D99, "GL_RGBA_INTEGER_EXT" },
+ { 0x8D9A, "GL_BGR_INTEGER_EXT" },
+ { 0x8D9B, "GL_BGRA_INTEGER_EXT" },
+ { 0x8D9C, "GL_LUMINANCE_INTEGER_EXT" },
+ { 0x8D9D, "GL_LUMINANCE_ALPHA_INTEGER_EXT" },
+ { 0x8D9E, "GL_RGBA_INTEGER_MODE_EXT" },
+ { 0x8DA7, "GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT" },
+ { 0x8DA8, "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT" },
+ { 0x8DA9, "GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT" },
+ { 0x8DAD, "GL_FLOAT_32_UNSIGNED_INT_24_8_REV" },
+ { 0x8DB9, "GL_FRAMEBUFFER_SRGB_EXT" },
+ { 0x8DBA, "GL_FRAMEBUFFER_SRGB_CAPABLE_EXT" },
+ { 0x8DBB, "GL_COMPRESSED_RED_RGTC1" },
+ { 0x8DBC, "GL_COMPRESSED_SIGNED_RED_RGTC1" },
+ { 0x8DBD, "GL_COMPRESSED_RG_RGTC2" },
+ { 0x8DBE, "GL_COMPRESSED_SIGNED_RG_RGTC2" },
+ { 0x8DC0, "GL_SAMPLER_1D_ARRAY_EXT" },
+ { 0x8DC1, "GL_SAMPLER_2D_ARRAY_EXT" },
+ { 0x8DC2, "GL_SAMPLER_BUFFER_EXT" },
+ { 0x8DC3, "GL_SAMPLER_1D_ARRAY_SHADOW_EXT" },
+ { 0x8DC4, "GL_SAMPLER_2D_ARRAY_SHADOW_EXT" },
+ { 0x8DC5, "GL_SAMPLER_CUBE_SHADOW_EXT" },
+ { 0x8DC6, "GL_UNSIGNED_INT_VEC2_EXT" },
+ { 0x8DC7, "GL_UNSIGNED_INT_VEC3_EXT" },
+ { 0x8DC8, "GL_UNSIGNED_INT_VEC4_EXT" },
+ { 0x8DC9, "GL_INT_SAMPLER_1D_EXT" },
+ { 0x8DCA, "GL_INT_SAMPLER_2D_EXT" },
+ { 0x8DCB, "GL_INT_SAMPLER_3D_EXT" },
+ { 0x8DCC, "GL_INT_SAMPLER_CUBE_EXT" },
+ { 0x8DCD, "GL_INT_SAMPLER_2D_RECT_EXT" },
+ { 0x8DCE, "GL_INT_SAMPLER_1D_ARRAY_EXT" },
+ { 0x8DCF, "GL_INT_SAMPLER_2D_ARRAY_EXT" },
+ { 0x8DD0, "GL_INT_SAMPLER_BUFFER_EXT" },
+ { 0x8DD1, "GL_UNSIGNED_INT_SAMPLER_1D_EXT" },
+ { 0x8DD2, "GL_UNSIGNED_INT_SAMPLER_2D_EXT" },
+ { 0x8DD3, "GL_UNSIGNED_INT_SAMPLER_3D_EXT" },
+ { 0x8DD4, "GL_UNSIGNED_INT_SAMPLER_CUBE_EXT" },
+ { 0x8DD5, "GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT" },
+ { 0x8DD6, "GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT" },
+ { 0x8DD7, "GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT" },
+ { 0x8DD8, "GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT" },
+ { 0x8DD9, "GL_GEOMETRY_SHADER_EXT" },
+ { 0x8DDA, "GL_GEOMETRY_VERTICES_OUT_EXT" },
+ { 0x8DDB, "GL_GEOMETRY_INPUT_TYPE_EXT" },
+ { 0x8DDC, "GL_GEOMETRY_OUTPUT_TYPE_EXT" },
+ { 0x8DDD, "GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT" },
+ { 0x8DDE, "GL_MAX_VERTEX_VARYING_COMPONENTS_EXT" },
+ { 0x8DDF, "GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT" },
+ { 0x8DE0, "GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT" },
+ { 0x8DE1, "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT" },
+ { 0x8DE2, "GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT" },
+ { 0x8DE3, "GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT" },
+ { 0x8DE4, "GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT" },
+ { 0x8DED, "GL_MAX_BINDABLE_UNIFORM_SIZE_EXT" },
+ { 0x8DEE, "GL_UNIFORM_BUFFER_EXT" },
+ { 0x8DEF, "GL_UNIFORM_BUFFER_BINDING_EXT" },
+ { 0x8E4C, "GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT" },
+ { 0x8E4D, "GL_FIRST_VERTEX_CONVENTION_EXT" },
+ { 0x8E4E, "GL_LAST_VERTEX_CONVENTION_EXT" },
+ { 0x8E4F, "GL_PROVOKING_VERTEX_EXT" },
+
+ VE( TERMVALUE )
+};
+
+GLMValueEntry_t g_gl_renderers[] =
+{
+ { 0x00020200, "Generic" },
+ { 0x00020400, "GenericFloat" },
+ { 0x00020600, "AppleSW" },
+ { 0x00021000, "ATIRage128" },
+ { 0x00021200, "ATIRadeon" },
+ { 0x00021400, "ATIRagePro" },
+ { 0x00021600, "ATIRadeon8500" },
+ { 0x00021800, "ATIRadeon9700" },
+ { 0x00021900, "ATIRadeonX1000" },
+ { 0x00021A00, "ATIRadeonX2000" },
+ { 0x00022000, "NVGeForce2MX" },
+ { 0x00022200, "NVGeForce3" },
+ { 0x00022400, "NVGeForceFX" },
+ { 0x00022600, "NVGeForce8xxx" },
+ { 0x00023000, "VTBladeXP2" },
+ { 0x00024000, "Intel900" },
+ { 0x00024200, "IntelX3100" },
+ { 0x00040000, "Mesa3DFX" },
+
+ VE( TERMVALUE )
+};
+
+
+//===============================================================================
+// decode helper funcs
+
+char s_glmStrScratch[65536];
+int s_glmStrCursor = 0;
+
+const char * GLMDecode( GLMThing_t thingtype, unsigned long value )
+{
+ GLMValueEntry_t *table = NULL;
+
+ switch( thingtype )
+ {
+ case eD3D_DEVTYPE: table = g_d3d_devtypes;
+ break;
+
+ case eD3D_FORMAT: table = g_d3d_formats;
+ break;
+
+ case eD3D_RTYPE: table = g_d3d_rtypes;
+ break;
+
+ case eD3D_USAGE: table = g_d3d_usages;
+ break;
+
+ case eD3D_RSTATE: table = g_d3d_rstates;
+ break;
+
+ case eD3D_SIO: table = g_d3d_opcodes;
+ break;
+
+ case eD3D_VTXDECLUSAGE: table = g_d3d_vtxdeclusages;
+ break;
+
+ case eCGL_RENDID: table = g_cgl_rendids;
+ break;
+
+ case eGL_ERROR: table = g_gl_errors;
+ break;
+
+ case eGL_ENUM: table = g_gl_enums;
+ break;
+
+ case eGL_RENDERER: table = g_gl_renderers;
+ break;
+
+ default:
+ GLMStop();
+ return "UNKNOWNTYPE";
+ break;
+ }
+
+ if (table)
+ {
+ while( table->value != TERMVALUE )
+ {
+ if (table->value == value)
+ {
+ return table->name;
+ }
+ table++;
+ }
+ }
+ return "UNKNOWN";
+}
+
+const char *GLMDecodeMask( GLMThing_t kind, unsigned long value )
+{
+ // if cursor to scratch buffer is within 1K of EOB, rewind
+ // nobody is going to decode 63K of flag string values in a single call..
+
+ // this means that strings returned by this function have a short lifetime.. print them and do not save the pointer..
+
+ if ( (sizeof(s_glmStrScratch) - s_glmStrCursor) < 1000 )
+ {
+ s_glmStrCursor = 0;
+ }
+
+ char *start = &s_glmStrScratch[ s_glmStrCursor ];
+ char *dest = start;
+ char first = 1;
+
+ DWORD mask = (1L<<31);
+ while(mask)
+ {
+ if (mask & value)
+ {
+ sprintf(dest,"%s%s", (first) ? "" : "|", GLMDecode( kind, value&mask ) );
+ first = 0;
+
+ dest += strlen(dest); // leaves dest pointing at the end null
+ }
+ mask >>= 1;
+ }
+ s_glmStrCursor = (dest - s_glmStrScratch) + 1; // +1 so the next decoded flag set doesn't land on the ending null
+ return start;
+
+}
+
+#undef VE
+#undef TERMVALUE
+
+//===============================================================================
+
+bool GLMDetectOGLP( void )
+{
+ bool result;
+
+ GLint forceFlush;
+ CGLError error = CGLGetParameter(CGLGetCurrentContext(), kCGLCPEnableForceFlush, &forceFlush);
+ result = error == 0;
+ if (result)
+ {
+ // enable a breakpoint on color4sv
+ GLint oglp_bkpt[3] = { kCGLFEglColor4sv, kCGLProfBreakBefore, 1 };
+
+ CGLSetGlobalOption( kCGLGOEnableBreakpoint, oglp_bkpt );
+ }
+
+ return result;
+}
+
+
+// from http://blog.timac.org/?p=190
+
+#include
+#include
+#include
+#include
+
+// From Technical Q&A QA1361
+// Returns true if the current process
+// is being debugged (either running
+// under the debugger or has a debugger
+// attached post facto).
+
+bool GLMDetectGDB( void ) // aka AmIBeingDebugged()
+{
+ bool result;
+ int junk;
+ int mib[4];
+ struct kinfo_proc info;
+ size_t size;
+
+ // Initialize the flags so that,
+ // if sysctl fails for some bizarre
+ // reason, we get a predictable result.
+
+ info.kp_proc.p_flag = 0;
+
+ // Initialize mib, which tells sysctl the info
+ // we want, in this case we're looking for
+ // information about a specific process ID.
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+
+ // Call sysctl.
+
+ size = sizeof(info);
+ junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
+ (void)junk;
+
+ assert(junk == 0);
+
+ // We're being debugged if the P_TRACED
+ // flag is set.
+
+ result = ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+
+ return result;
+}
+
+
+uint GLMDetectAvailableChannels( void )
+{
+ uint result = 0;
+
+ // printf is always available (except maybe in release... ?)
+ result |= (1 << ePrintf);
+
+ // gdb
+ if (GLMDetectGDB())
+ {
+ result |= (1 << eDebugger);
+ printf("\n############# GDB Detected");
+ }
+
+ // oglp
+ if (GLMDetectOGLP())
+ {
+ result |= (1 << eGLProfiler);
+ printf("\n############# OGLP Detected");
+ }
+
+ return result;
+}
+
+
+#if GLMDEBUG
+
+static bool g_debugInitDone = false;
+static uint g_glmDebugChannelMask = 0; // which output channels are available (can be more than one)
+static uint g_glmDebugFlavorMask = 0; // which message flavors are enabled for output (can be more than one)
+
+ // following funcs vanish if GLMDEBUG not set
+
+void GLMDebugInitialize( bool forceReinit )
+{
+ if ( !g_debugInitDone || forceReinit )
+ {
+ // detect channels
+ uint channelMask = GLMDetectAvailableChannels();
+
+ // finally, disable all of them if commandline did not say "enable spew"
+ if (0 /* !CommandLine()->FindParm("-glmspew") */) //FIXME change back to 1 later
+ {
+ channelMask = 0;
+ }
+
+ // set the output channel mask
+ GLMDebugChannelMask( &channelMask );
+
+ // if any channels are enabled, enable some output
+ if ( channelMask )
+ {
+ // start mostly quiet unless the -glmbootspew option is there
+ if ( 0 /*CommandLine()->FindParm( "-glmbootspew" )*/ )
+ {
+ g_glmDebugFlavorMask = 0xFFFFFFFF;
+ }
+ else
+ {
+ g_glmDebugFlavorMask =
+ (1< <
+ // | (1<-M- and it will indent and be filterable
+ {
+ // comment
+ flavor = eComment;
+ }
+ else if (strnstr(str, "-D-", 4))
+ {
+ // debug dump
+ flavor = eDebugDump;
+ }
+ else if (strnstr(str, "-M-", 4))
+ {
+ // matrix data
+ flavor = eMatrixData;
+ }
+ else if (strnstr(str, "-S-", 4))
+ {
+ // shader data
+ flavor = eShaderData;
+ }
+ else if (strnstr(str, "-F-", 4))
+ {
+ // framebuf data
+ flavor = eFrameBufData;
+ }
+ else if (strnstr(str, "-X-", 4))
+ {
+ // DirectX data
+ flavor = eDXStuff;
+ }
+ else if (strnstr(str, "-A-", 4))
+ {
+ // allocation data
+ flavor = eAllocations;
+ }
+ else if (strnstr(str, "-Z-", 4))
+ {
+ // allocation data
+ flavor = eSlowness;
+ }
+ else if (str[0] == '<' || str[0] == '>')
+ {
+ // entry/exit (aka tenure)
+ flavor = eTenure;
+ }
+
+ return flavor;
+}
+
+void GLMPrintfVA( const char *fmt, va_list vargs )
+{
+ // if no channels open, return
+ uint channelMask = GLMDebugChannelMask();
+ if (!channelMask)
+ return;
+
+ // if "all flavors" is off, return
+ uint flavorMask = GLMDebugFlavorMask();
+ if (! ( flavorMask & (1<' - raise indent level after print.
+ // if first char is a '<' - lower indent level before print.
+
+ char buf[100000];
+
+ if (fmt[0] == '<')
+ {
+ GLMIncIndent( -1 );
+ }
+
+ memset( buf, '\t', g_glm_indent );
+ vsprintf( buf+g_glm_indent, fmt, vargs );
+ GLMStringOut( buf );
+
+ if (fmt[0] == '>')
+ {
+ GLMIncIndent( 1 );
+ }
+}
+
+void GLMPrintf( const char *fmt, ... )
+{
+ // if no channels open, return
+ uint channelMask = GLMDebugChannelMask();
+ if (!channelMask)
+ return;
+
+ // if "all flavors" is off, return
+ uint flavorMask = GLMDebugFlavorMask();
+ if (! ( flavorMask & (1<' - raise indent level after print.
+ // if first char is a '<' - lower indent level before print.
+
+ char buf[64000];
+
+ if (str[0] == '<')
+ {
+ GLMIncIndent( -1 );
+ }
+
+ memset( buf, '\t', g_glm_indent );
+
+ if (strlen(str) < sizeof(buf)-g_glm_indent-1)
+ {
+ strcpy( buf + g_glm_indent, str );
+ }
+ else
+ {
+ Debugger();
+ }
+
+
+ GLMStringOut( buf ); // single string out with indenting
+
+ if (str[0] == '>')
+ {
+ GLMIncIndent( 1 );
+ }
+}
+
+
+void GLMPrintText( const char *str, EGLMDebugFlavor flavor, uint options )
+{
+ // if no channels open, return
+ uint channelMask = GLMDebugChannelMask();
+ if (!channelMask)
+ return;
+
+ // if "all flavors" is off, return
+ uint flavorMask = GLMDebugFlavorMask();
+ if (! ( flavorMask & (1<0)
+ {
+ if (g_glm_indent > g_glm_indent_max)
+ {
+ g_glm_indent = g_glm_indent_max;
+ }
+ }
+ else
+ {
+ if (g_glm_indent < 0)
+ {
+ g_glm_indent = 0;
+ }
+ }
+ return g_glm_indent;
+}
+
+int GLMGetIndent( void )
+{
+ return g_glm_indent;
+}
+
+void GLMSetIndent( int indent )
+{
+ g_glm_indent = indent;
+}
+
+#endif
+
+// PIX tracking - you can call these outside of GLMDEBUG=true
+char sg_pPIXName[128];
+
+void GLMBeginPIXEvent( const char *str )
+{
+ V_strncpy( sg_pPIXName, str, 128 );
+
+ /*
+ if (CommandLine()->FindParm("-glmpix2oglp"))
+ {
+ char temp[256];
+ // route PIX event strings to OGLP
+ sprintf( temp,"> %s",sg_pPIXName );
+ CGLSetOption( kCGLGOComment, (GLint)temp );
+ }
+ */
+}
+
+void GLMEndPIXEvent( void )
+{
+ /*
+ if (CommandLine()->FindParm("-glmpix2oglp"))
+ {
+ char temp[256];
+ // route PIX event strings to OGLP
+ sprintf( temp,"< %s",sg_pPIXName );
+ CGLSetOption( kCGLGOComment, (GLint)temp );
+ }
+ */
+ sg_pPIXName[0] = '\0';
+}
+
+
+
+
+//===============================================================================
+
+// helpers for CGLSetOption - no op if no profiler
+void GLMProfilerClearTrace( void )
+{
+ CGLSetOption( kCGLGOResetFunctionTrace, 0 );
+}
+
+void GLMProfilerEnableTrace( bool enable )
+{
+ CGLSetOption( kCGLGOEnableFunctionTrace, enable ? GL_TRUE : GL_FALSE );
+}
+
+// helpers for CGLSetParameter - no op if no profiler
+void GLMProfilerDumpState( void )
+{
+ CGLContextObj curr = CGLGetCurrentContext();
+ CGLSetParameter( curr, kCGLCPDumpState, (const GLint*)1 );
+}
+
+
+//===============================================================================
+
+CGLMFileMirror::CGLMFileMirror( char *fullpath )
+{
+ m_path = strdup( fullpath );
+ m_data = (char *)malloc(1);
+ m_size = 0;
+ UpdateStatInfo();
+ if (m_exists)
+ {
+ ReadFile();
+ }
+}
+
+CGLMFileMirror::~CGLMFileMirror( )
+{
+ if (m_path)
+ {
+ free (m_path);
+ m_path = NULL;
+ }
+
+ if (m_data)
+ {
+ free (m_data);
+ m_data = NULL;
+ }
+}
+
+bool CGLMFileMirror::HasData( void )
+{
+ return (m_size != 0);
+}
+
+
+// return direct pointer to buffer. Will be invalidated if file is re-loaded or if data is written to
+void CGLMFileMirror::GetData( char **dataPtr, uint *dataSizePtr )
+{
+ *dataPtr = m_data;
+ *dataSizePtr = m_size;
+}
+
+
+void CGLMFileMirror::SetData( char *data, uint dataSize )
+{
+ if (m_data)
+ {
+ free( m_data );
+ m_data = NULL;
+ }
+
+ m_size = dataSize;
+
+ m_data = (char *)malloc( m_size +1 );
+ m_data[ m_size ] = 0; // extra NULL terminator, no charge
+
+ memcpy( m_data, data, m_size ); // copy data in
+
+ WriteFile(); // keep disk copy sync'd
+}
+
+static bool stat_diff( struct stat *a, struct stat *b )
+{
+ if (a->st_size != b->st_size)
+ {
+ return true;
+ }
+
+ if (memcmp( &a->st_mtimespec, &b->st_mtimespec, sizeof( struct timespec ) ) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool CGLMFileMirror::PollForChanges( void )
+{
+ // snapshot old stat
+ bool old_exists = m_exists;
+ struct stat old_stat = m_stat;
+
+ (void)old_exists;
+
+ UpdateStatInfo();
+
+ if (m_exists)
+ {
+ if ( stat_diff( &old_stat, &m_stat ) )
+ {
+ // initial difference detected. continue to poll at 0.1s intervals until it stops changing, then read it.
+ int stablecount = 0;
+ do
+ {
+ usleep(100000);
+
+ struct stat last_stat = m_stat;
+ UpdateStatInfo();
+
+ if (stat_diff( &last_stat, &m_stat ))
+ {
+ stablecount = 0;
+ }
+ else
+ {
+ stablecount++;
+ }
+ } while(stablecount<3);
+
+ // changes have settled down, now re-read it
+ ReadFile();
+ return true;
+ }
+ else
+ {
+ return false; // no change
+ }
+ }
+ else
+ {
+ // file does not exist. remake it. not considered to be a change.
+ WriteFile();
+ return false;
+ }
+}
+
+
+
+void CGLMFileMirror::UpdateStatInfo( void )
+{
+ // stat the path
+ struct stat newstat;
+ memset (&newstat, 0, sizeof(newstat) );
+ int result = stat( m_path, &newstat );
+
+ if (!result)
+ {
+ m_exists = true;
+ m_stat = newstat;
+ }
+ else
+ {
+ m_exists = false;
+ memset( &m_stat, 0, sizeof( m_stat ) );
+ }
+}
+
+
+void CGLMFileMirror::ReadFile( void )
+{
+ // unconditional - we discard any old buffer, make a new one,
+ UpdateStatInfo();
+
+ if (m_data)
+ {
+ free( m_data );
+ m_data = NULL;
+ }
+
+ if (m_exists)
+ {
+ FILE *infile = fopen( m_path, "rb" );
+ if (infile)
+ {
+ // get size from stat
+ m_size = m_stat.st_size;
+
+ m_data = (char *)malloc( m_size +1 );
+ m_data[ m_size ] = 0; // extra NULL terminator, no charge
+
+ fread( m_data, 1, m_size, infile );
+
+ fclose( infile );
+ }
+ else
+ {
+ GLMDebugger(); // ouch
+ }
+
+ }
+ else
+ {
+ // hmmmmmm
+ m_data = (char *)malloc(1);
+ m_data[0] = 0;
+ m_size = 0;
+ }
+}
+
+
+void CGLMFileMirror::WriteFile( void )
+{
+ FILE *outfile = fopen( m_path, "wb" );
+
+ if (outfile)
+ {
+ fwrite( m_data, 1, m_size, outfile );
+ fclose( outfile );
+
+ UpdateStatInfo(); // sets m_stat and m_exists
+ }
+ else
+ {
+ GLMDebugger(); // ouch
+ }
+}
+
+void CGLMFileMirror::OpenInEditor( bool foreground )
+{
+ char temp[64000];
+
+ // pass -b if no desire to bring editor to foreground
+ sprintf(temp,"/usr/bin/bbedit %s %s", foreground ? "" : "-b", m_path );
+ system( temp );
+}
+
+
+
+CGLMEditableTextItem::CGLMEditableTextItem( char *text, uint size, bool forceOverwrite, char *prefix, char *suffix )
+{
+ // clone input text (exact size copy)
+ m_origSize = size;
+ m_origText = (char *)malloc( m_origSize );
+ memcpy( m_origText, text, m_origSize );
+
+ // null out munged form til we generate it
+ m_mungedSize = 0;
+ m_mungedText = NULL;
+
+ // null out mirror until we create it
+ m_mirrorBaseName = NULL;
+ m_mirrorFullPath = NULL;
+ m_mirror = NULL;
+
+ GenHashOfOrigText(); // will fill out m_origDigest
+ GenMungedText( false );
+ GenBaseNameAndFullPath( prefix, suffix ); // figure out where the mirror will go
+
+ if (!strcmp(m_mirrorBaseName, "96c7e9d2faf76b1148f7274afd684d4b.fsh"))
+ {
+ printf("\nhello there\n");
+ }
+
+ // make the mirror from the filename.
+ // see if there was any content on disk
+ // if so, honor that content *unless* the force-option is set.
+ m_mirror = new CGLMFileMirror( m_mirrorFullPath );
+
+ // the logic is simple.
+ // the only time we will choose the copy on disk, is if
+ // a - forceOverwrite is false
+ // AND b - the copy on disk is bigger than 10 bytes.
+
+ bool replaceDiskCopy = true;
+
+ char *mirrorData = NULL;
+ uint mirrorSize = 0;
+
+ if (!forceOverwrite)
+ {
+ if (m_mirror->HasData())
+ {
+ // peek at it, and use it if it is more than some minimum number of bytes.
+ m_mirror->GetData( &mirrorData, &mirrorSize );
+ if (mirrorSize > 10)
+ {
+ replaceDiskCopy = false;
+ }
+ }
+ }
+
+ if (replaceDiskCopy)
+ {
+ // push our generated data to the mirror - disk copy is overwritten
+ m_mirror->SetData( m_mungedText, m_mungedSize );
+ }
+ else
+ {
+ GenMungedText( true );
+ }
+
+}
+
+CGLMEditableTextItem::~CGLMEditableTextItem( )
+{
+ if (m_origText)
+ {
+ free (m_origText);
+ }
+
+ if (m_mungedText)
+ {
+ free (m_mungedText);
+ }
+
+ if (m_mirrorBaseName)
+ {
+ free (m_mirrorBaseName);
+ }
+
+ if (m_mirrorFullPath)
+ {
+ free (m_mirrorFullPath);
+ }
+
+ if (m_mirror)
+ {
+ free( m_mirror );
+ }
+}
+
+bool CGLMEditableTextItem::HasData( void )
+{
+ return m_mirror->HasData();
+}
+
+bool CGLMEditableTextItem::PollForChanges( void )
+{
+ bool changed = m_mirror->PollForChanges();
+ if (changed)
+ {
+ // re-gen munged text from mirror (means "copy")
+ GenMungedText( true );
+ }
+ return changed;
+}
+
+void CGLMEditableTextItem::GetCurrentText( char **textOut, uint *sizeOut )
+{
+ if (!m_mungedText) GLMDebugger();
+
+ *textOut = m_mungedText;
+ *sizeOut = m_mungedSize;
+}
+
+void CGLMEditableTextItem::OpenInEditor( bool foreground )
+{
+ m_mirror->OpenInEditor( foreground );
+}
+
+
+void CGLMEditableTextItem::GenHashOfOrigText( void )
+{
+ // bring this code back if you need the live shader edit/debug mode.
+ #if 0
+ MD5Context_t md5ctx;
+ MD5Init( &md5ctx );
+ MD5Update( &md5ctx, (unsigned char*)m_origText, m_origSize );
+ MD5Final( m_origDigest, &md5ctx );
+ #endif
+}
+
+
+void CGLMEditableTextItem::GenBaseNameAndFullPath( char *prefix, char *suffix )
+{
+ // bring this code back if you need the live shader edit/debug mode.
+ #if 0
+ // base name is hash digest in hex, plus the suffix.
+ char temp[5000];
+
+ V_binarytohex( m_origDigest, sizeof(m_origDigest), temp, sizeof( temp ) );
+ if (suffix)
+ {
+ strcat( temp, suffix );
+ }
+ if (m_mirrorBaseName) free(m_mirrorBaseName);
+ m_mirrorBaseName = strdup( temp );
+
+ sprintf( temp, "%s%s", prefix, m_mirrorBaseName );
+ if (m_mirrorFullPath) free(m_mirrorFullPath);
+ m_mirrorFullPath = strdup( temp );
+ #endif
+}
+
+
+void CGLMEditableTextItem::GenMungedText( bool fromMirror )
+{
+ if (fromMirror)
+ {
+ // just import the text as is from the mirror file.
+
+ char *mirrorData = NULL;
+ uint mirrorSize = 0;
+
+ if (m_mirror->HasData())
+ {
+ // peek at it, and use it if it is more than some minimum number of bytes.
+ m_mirror->GetData( &mirrorData, &mirrorSize );
+
+ if (m_mungedText)
+ {
+ free( m_mungedText );
+ m_mungedText = NULL;
+ }
+
+ m_mungedText = (char *)malloc( mirrorSize+1 );
+ m_mungedText[ mirrorSize ] = 0;
+ memcpy( m_mungedText, mirrorData, mirrorSize );
+
+ m_mungedSize = mirrorSize;
+ }
+ else
+ {
+ GLMDebugger();
+ }
+ }
+ else
+ {
+ #if 1
+ // we don't actually clone/munge any more.
+ if (m_mungedText)
+ {
+ free( m_mungedText );
+ m_mungedText = NULL;
+ }
+
+ m_mungedText = (char *)malloc( m_origSize+1 );
+ m_mungedText[ m_origSize ] = 0;
+ memcpy( m_mungedText, m_origText, m_origSize );
+
+ m_mungedSize = m_origSize;
+
+ #else
+ // take pure 'orig' text that came in from the engine, and clone it
+ // do not clone the first line
+ char temp[100000];
+ char *dst = temp;
+ char *lim = &temp[ sizeof(temp) ];
+
+ // zero temp
+ memset( temp, 0, sizeof(temp) );
+
+ // write orig text to temp
+ if (m_origSize >= (sizeof(temp)/2) )
+ {
+ GLMDebugger();
+ }
+
+ memcpy( dst, m_origText, m_origSize );
+ dst += m_origSize;
+
+ // add a newline if the last character wasn't
+ if ( (*(dst-1)) != '\n' )
+ {
+ *dst++ = '\n';
+ }
+
+ // walk orig text again and copy it over, with these caveats
+ // don't copy the first line
+ // insert a # before all the other lines.
+ char *src = temp;
+
+ // walk to end of first line
+ char *firstNewline = strchr( src, '\n' );
+ if (!firstNewline)
+ {
+ GLMDebugger();
+ }
+ else
+ {
+ // advance 'src' to that newline- we're not copying the !! line
+ src = firstNewline;
+ }
+
+
+ // now walk the rest - insert a # after each newline
+ while( (dst < lim) && ((src-temp) < m_origSize) )
+ {
+ switch( *src )
+ {
+ case '\n':
+ *dst++ = *src++;
+ *dst++ = '#';
+ break;
+
+ default:
+ *dst++ = *src++;
+ }
+ }
+ if (dst >= lim)
+ {
+ GLMDebugger();
+ }
+
+ // final newline
+ *dst++ = '\n';
+
+ // copyout
+ if (m_mungedText)
+ {
+ free( m_mungedText );
+ m_mungedText = NULL;
+ }
+
+ m_mungedSize = dst - temp;
+ m_mungedText = (char *)malloc( m_mungedSize );
+ memcpy( m_mungedText, temp, m_mungedSize );
+ #endif
+ }
+}
+
+//===============================================================================
+
+// class for cracking multi-part text blobs
+// sections are demarcated by beginning-of-line markers submitted in a table by the caller
+// typically
+// asm flavors have first-line rules so we use those tags as is
+// !!ARBvp (etc)
+// !!ARBfp (etc)
+// //!!GLSLF // slashes required
+// //!GLSLV
+
+// maybe also introduce "present but disabled" markers like these
+// -!!ARBvp (etc)
+// -!!ARBfp (etc)
+// -//!!GLSLF
+// -//!GLSLV
+
+// resolved. there is no default section for text that doesn't have a marker in front of it. mark it or miss it.
+
+CGLMTextSectioner::CGLMTextSectioner( const char *text, int textLength, const char **markers )
+{
+ // find lines
+ // for each line, see if it starts with a marker
+ // if so, open a new section based at that line
+
+ GLMTextSection *curSection = NULL; // no current section until we see a marker
+
+ const char *cursor = text;
+ const char *textLimit = text+textLength;
+
+ int foundMarker;
+ const char **markerCursor;
+ while( cursor < textLimit )
+ {
+ // top of loop. cursor points to start of a line.
+ // find the end of the line and keep that handy.
+ const char *eol = strchr( cursor, '\n' );
+ int charsInLine = (eol) ? (eol-cursor)+1 : strlen(cursor);
+
+ //see if any of the marker strings is located here.
+ foundMarker = -1;
+ markerCursor = markers;
+
+ while( (foundMarker<0) && (*markerCursor!=NULL) )
+ {
+ // see if the n'th marker is a hit
+ int markerLen = strlen(*markerCursor);
+
+ if (!strncmp( cursor, *markerCursor, markerLen ) )
+ {
+ // hit
+ foundMarker = markerCursor - markers;
+ }
+ markerCursor++;
+ }
+
+ // outcome is either "marker spotted" or "no".
+ // if marker seen, open new section using that marker.
+ // else, grow active section if underway.
+ // then, move cursor to next line.
+
+ if (foundMarker >= 0)
+ {
+ // found marker. start new section.
+ // no need to do anything special with prior section - it was up to date before seeing this marker.
+ GLMTextSection temp;
+
+ temp.m_markerIndex = foundMarker;
+ temp.m_textOffset = cursor - text; // text includes the marker
+ temp.m_textLength = charsInLine; // this line goes in the tally, later lines add to it
+
+ m_sectionTable.push_back( temp );
+
+ curSection = &m_sectionTable[ m_sectionTable.size() - 1 ];
+ }
+ else
+ {
+ // add this line to current section if live
+ if (curSection)
+ {
+ curSection->m_textLength += charsInLine;
+ }
+ }
+ cursor += charsInLine;
+ }
+}
+
+CGLMTextSectioner::~CGLMTextSectioner( )
+{
+ // not much to do.
+}
+
+
+int CGLMTextSectioner::Count( void )
+{
+ return m_sectionTable.size();
+}
+
+void CGLMTextSectioner::GetSection( int index, uint *offsetOut, uint *lengthOut, int *markerIndexOut )
+{
+ Assert( index < m_sectionTable.Count() );
+
+ GLMTextSection *section = &m_sectionTable[ index ];
+
+ *offsetOut = section->m_textOffset;
+ *lengthOut = section->m_textLength;
+ *markerIndexOut = section->m_markerIndex;
+}
+
+//===============================================================================
+
+// how to make a compiled-in font:
+// a. type in a matrix of characters in your fav editor
+// b. take a screen shot of the characters (128x128 pixels in this case)
+// c. export as TIFF raw.
+// d. hex dump it
+// e. column-copy just the hex data
+// f. find and replace: chop out all the spaces and line feeds, change FFFFFF and 000000 to your marker chars of choice.
+// g. wrap each line with quotes and a comma.
+
+unsigned char g_glmDebugFontMap[ 128 * 128 ] =
+{
+" * "
+" * * * * * "
+" * * * * * *** * * ** * * * * * "
+" * * * ***** * * * * * * * * * * * * * * * * "
+" * * * * * * * * * * * * * *** * * "
+" * ***** *** * * * * * * * ***** ***** * "
+" * * * * * * * * * * * * * * * "
+" * * * * * * * * * * * ** ** * "
+" * *** * * ** * * * ** ** * "
+" * * * * * "
+" * "
+" "
+" "
+" *** * *** *** * ***** *** ***** *** *** * * *** "
+"* * ** * * * * ** * * * * * * * ** ** * * * * "
+"* ** * * * * * **** **** * * * * * ** ** * ***** * * "
+"* * * * * ** * * * * * * *** * * * * * "
+"** * * * * ***** * * * * * * **** * ***** * * "
+"* * * * * * * * * * * * * * * ** ** * * "
+" *** * ***** *** * *** *** * *** *** ** ** * * * "
+" * "
+" * "
+" "
+" *** "
+"* * *** **** *** **** ***** ***** *** * * * * * * * * * * * *** "
+"* * * * * * * * * * * * * * * * * * * * * ** ** ** * * * "
+"* * * * * * * * * * * * * * * * * * * * * * * * * * * * "
+"*** * ***** **** * * * **** **** * ** ***** * * ** * * * * ** * * "
+"* ** * * * * * * * * * * * * * * * * * * * * * * * * * "
+"* * * * * * * * * * * * * * * * * * * * * * * * * * * "
+"* * * * **** *** **** ***** * *** * * * *** * * ***** * * * * *** "
+" *** "
+" "
+" * "
+" ** * ** * "
+"**** *** **** *** ***** * * * * * * * * * * ***** * * * * * "
+"* * * * * * * * * * * * * * * * * * * * * * * * * "
+"* * * * * * * * * * * * * * * * * * * * * "
+"**** * * **** *** * * * * * * * * * * * * * * "
+"* * * * * * * * * * * * * * * * * * * * "
+"* * * * * * * * * * * ** ** * * * * * * * "
+"* *** * * *** * *** * * * * * * ***** * * * ****** "
+" * ** * ** "
+" "
+" "
+" * "
+" * * * ** * * * * * "
+" * * * * * * * "
+" **** **** *** **** *** *** **** **** * * * * * **** * ** *** "
+" * * * * * * * * * * * * * * * * * * * * * * * ** * * * "
+" * * * * * * * ***** * * * * * * * *** * * * * * * * * "
+" * ** * * * * * * * * * * * * * * * * * * * * * * * "
+" ** * **** **** **** **** * **** * * * * * * ** * * * * * *** "
+" * * "
+" *** ** "
+" * "
+" ** * ** "
+" * * * * ** * "
+" * * * * * ** *** "
+"**** **** * ** **** **** * * * * * * * * * * * ***** * * * ***** "
+"* * * * ** * * * * * * * * * * * * * * * ** * ** ***** "
+"* * * * * *** * * * * * * * * * * * * * * * ***** "
+"* * * * * * * * ** * * * * * * * * * * * * * *** "
+"**** **** * **** ** ** * * * * * * **** ***** * * * "
+"* * * ** * ** "
+"* * *** * "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+};
+
+
+
+
+
+
+
+
diff --git a/My project/sdk/glmgr/glmgrbasics.h b/My project/sdk/glmgr/glmgrbasics.h
new file mode 100644
index 000000000..6acfe38c3
--- /dev/null
+++ b/My project/sdk/glmgr/glmgrbasics.h
@@ -0,0 +1,512 @@
+//============ Copyright (c) Valve Corporation, All rights reserved. ============
+//
+// glmgrbasics.h
+// types, common headers, forward declarations, utilities
+//
+//===============================================================================
+
+#ifndef GLMBASICS_H
+#define GLMBASICS_H
+
+#pragma once
+
+#include
+#include
+#include