mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-03-21 09:06:30 +08:00
graphics/window-system revamp work-in-progress
This commit is contained in:
parent
034094d0a3
commit
5b8310352f
134
.efrocachemap
generated
134
.efrocachemap
generated
@ -421,42 +421,42 @@
|
||||
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
|
||||
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
|
||||
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
|
||||
"build/assets/ba_data/data/langdata.json": "44b7cb7d2ce62346834ab48d0d1e81bc",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "db961f7fe0541a31880929e1c17ea957",
|
||||
"build/assets/ba_data/data/langdata.json": "ffaf99c11311bb311421f8537be1fab9",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "c246699b9c1949ce7542d32d30d47632",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "995ee0abd5bc05704e9f5a7712774663",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "8fc810e920164f3d7374aaab8000e9ae",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "3fe960a8f0ca529aa57b4f9cb7385abc",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "8d889accdd49334591209bdaf6eaf02f",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "19be7dcc11f5a9ed4fc408a0216ab36b",
|
||||
"build/assets/ba_data/data/languages/croatian.json": "766532c67af5bd0144c2d63cab0516fa",
|
||||
"build/assets/ba_data/data/languages/czech.json": "f3ce219840946cb8f9aa6d3e25927ab3",
|
||||
"build/assets/ba_data/data/languages/czech.json": "70992c2e2ac08a1f95a3e94318ab3332",
|
||||
"build/assets/ba_data/data/languages/danish.json": "3fd69080783d5c9dcc0af737f02b6f1e",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "22b44a33bf81142ba2befad14eb5746e",
|
||||
"build/assets/ba_data/data/languages/english.json": "6d261a19b40a27eca92f6199a26f5779",
|
||||
"build/assets/ba_data/data/languages/english.json": "b38d54aecf3ac47b8d8ca97d8bab3006",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "58f363cfd8a3ccf0c904ab753d95789b",
|
||||
"build/assets/ba_data/data/languages/french.json": "6057b18878ad8379e51b507fa94958d8",
|
||||
"build/assets/ba_data/data/languages/french.json": "d8527da977a563185de25ef02bacf826",
|
||||
"build/assets/ba_data/data/languages/german.json": "549754d2a530d825200c6126be56df5c",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "d23fe0936bb6177443f4b74bf5981b13",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "837423db378b3e7679683805826aa26e",
|
||||
"build/assets/ba_data/data/languages/greek.json": "a65d78f912e9a89f98de004405167a6a",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "88ee0cda537bab9ac827def5e236fe1a",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "796a290a8c44a1e7635208c2ff5fdc6e",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "00b351a98d6fc301df604e1e9d56a055",
|
||||
"build/assets/ba_data/data/languages/italian.json": "11f0a95abce8ef7b667b0d557746ecbe",
|
||||
"build/assets/ba_data/data/languages/italian.json": "338e7a03dff47f4eefc0ca3a995cd4f4",
|
||||
"build/assets/ba_data/data/languages/korean.json": "ca1122a9ee551da3f75ae632012bd0e2",
|
||||
"build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38",
|
||||
"build/assets/ba_data/data/languages/persian.json": "0cf93f27181dd3ef4b0d03b88bf899cf",
|
||||
"build/assets/ba_data/data/languages/persian.json": "71cc5b33abda0f285b970b8cc4a014a8",
|
||||
"build/assets/ba_data/data/languages/polish.json": "826c5b0402c2f0bcc29bc6f48b833545",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "99b27c598c90fd522132af3536aef0ee",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826",
|
||||
"build/assets/ba_data/data/languages/russian.json": "75ee4f36356f4f8a8413d4e0b6f5e268",
|
||||
"build/assets/ba_data/data/languages/russian.json": "910cf653497654a16d5c4f067d6def22",
|
||||
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "27962d53dc3f7dd4e877cd40faafeeef",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "b59d7ad1a98831afbc4ab162af08ec51",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "0122b0b24aa111ab259af02bbae9b7b6",
|
||||
"build/assets/ba_data/data/languages/swedish.json": "77d671f10613291ebf9c71da66f18a18",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "b9d4b4e107456ea6420ee0f9d9d7a03e",
|
||||
"build/assets/ba_data/data/languages/thai.json": "33f63753c9af9a5b238d229a0bf23fbc",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "a5347d5f7fc9dc994053001a936964a4",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "9d7e58c9062dc517c3779c255a9b3142",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "f72eb51abfbbb56e27866895d7e947d2",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "b0e3d73ccf96c5fa490a54f090ee77a5",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "71ff7ec07a1f9715fea93229bff249e1",
|
||||
"build/assets/ba_data/data/languages/vietnamese.json": "921cd1e50f60fe3e101f246e172750ba",
|
||||
"build/assets/ba_data/data/maps/big_g.json": "1dd301d490643088a435ce75df971054",
|
||||
"build/assets/ba_data/data/maps/bridgit.json": "6aea74805f4880cc11237c5734a24422",
|
||||
@ -1416,10 +1416,10 @@
|
||||
"build/assets/ba_data/textures/crossOutMask.pvr": "94110cc4e3e47f81b68f548951a33c2b",
|
||||
"build/assets/ba_data/textures/crossOutMask_preview.png": "d5df4d494cfbf700e3c8726b3693716c",
|
||||
"build/assets/ba_data/textures/crossOut_preview.png": "a0628f1e6b7e9f7d3b73d1c835ec9286",
|
||||
"build/assets/ba_data/textures/cursor.dds": "68e40aed124670a2b53c78101a8b3889",
|
||||
"build/assets/ba_data/textures/cursor.ktx": "627cbabe2eceff9992d31d4a48e98966",
|
||||
"build/assets/ba_data/textures/cursor.pvr": "704963da7a62d555e1dd907076033a02",
|
||||
"build/assets/ba_data/textures/cursor_preview.png": "8d80f75bcdc7f50b479d7756e68b8629",
|
||||
"build/assets/ba_data/textures/cursor.dds": "575b05e3adc74adf5a5d4b482a54adc9",
|
||||
"build/assets/ba_data/textures/cursor.ktx": "56ef6481222c23cbc1ab0fe825f19b03",
|
||||
"build/assets/ba_data/textures/cursor.pvr": "344b8856a315af23f495ebd283ee54fa",
|
||||
"build/assets/ba_data/textures/cursor_preview.png": "0f6820abfe6b79b4133971ace8f3bc42",
|
||||
"build/assets/ba_data/textures/cuteSpaz.dds": "5876162f89e558a2220935a1d63493c3",
|
||||
"build/assets/ba_data/textures/cuteSpaz.ktx": "4a3bc3c1739991298d21a66256289d57",
|
||||
"build/assets/ba_data/textures/cuteSpaz.pvr": "a236803464dc49b61b63a5e83d305c4c",
|
||||
@ -1520,10 +1520,10 @@
|
||||
"build/assets/ba_data/textures/folder.ktx": "293ec1bc118dd368e41623d5341e4428",
|
||||
"build/assets/ba_data/textures/folder.pvr": "22c439c211b592f41987b865d770bc77",
|
||||
"build/assets/ba_data/textures/folder_preview.png": "6e4892d7d43289bc22c8ff94c7c15955",
|
||||
"build/assets/ba_data/textures/fontBig.dds": "962a8dce3f3fdeebbb8abcc0682bcb74",
|
||||
"build/assets/ba_data/textures/fontBig.ktx": "3b999da15c56a6f38bd7cdff5632af9d",
|
||||
"build/assets/ba_data/textures/fontBig.pvr": "3d931bdabdc5097b37be763594b28678",
|
||||
"build/assets/ba_data/textures/fontBig_preview.png": "540b6bca8f5050a8ed246dce542aef93",
|
||||
"build/assets/ba_data/textures/fontBig.dds": "4242bbb85bc1ebd1ed63d7660587bd3c",
|
||||
"build/assets/ba_data/textures/fontBig.ktx": "94b56c2488d6c9ebabfbbb740eca07dd",
|
||||
"build/assets/ba_data/textures/fontBig.pvr": "dff3f6c04a8c7b0bb937001640b42c8d",
|
||||
"build/assets/ba_data/textures/fontBig_preview.png": "f8b15cb04f0deca7774def335a72f053",
|
||||
"build/assets/ba_data/textures/fontExtras.dds": "7ab11df1b3a3daa651dfad34219b89f5",
|
||||
"build/assets/ba_data/textures/fontExtras.ktx": "30c3c8ca2cdf1209ff177017bb10f0a8",
|
||||
"build/assets/ba_data/textures/fontExtras.pvr": "fd3b0bd902c30e4b7aa5fe00e1eec4be",
|
||||
@ -4042,7 +4042,7 @@
|
||||
"build/assets/windows/Win32/Lib/zoneinfo/_tzpath.py": "08a2e9502e68a3e35c45067f7439b108",
|
||||
"build/assets/windows/Win32/Lib/zoneinfo/_zoneinfo.py": "88e71c4db229ce21321b991cd7162d23",
|
||||
"build/assets/windows/Win32/OpenAL32.dll": "8bcdadebd8bc95a591e727a04faebda8",
|
||||
"build/assets/windows/Win32/SDL2.dll": "e358fddbc36ebf4dc8aba79a99466747",
|
||||
"build/assets/windows/Win32/SDL2.dll": "3937d3151ffb6544bf9657d0e45a8d0a",
|
||||
"build/assets/windows/Win32/libvorbis.dll": "dcfa5c5534900b7c109adc820ae57d74",
|
||||
"build/assets/windows/Win32/libvorbisfile.dll": "8abd2d7131857b9cc689b2857d04d018",
|
||||
"build/assets/windows/Win32/msvcp140d.dll": "d172cacd2087cf34db2fb8bb3c29c337",
|
||||
@ -4056,50 +4056,50 @@
|
||||
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
||||
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "e7171e1db64d2c0fdebbaeb45d99422e",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "4f6ed2673aa7716c211c94baeb611da3",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "629d63c3627b863e817a98b891b38325",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "b6315ff0d68b436500e48de435b69c77",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "aa98cf408c857767bcbb41ce2b63ce76",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "fa56d6e2beb16a44eff88dd9ca3e0b3e",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "3f026a96404b41c4369bd40694eae4de",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "9713455275e8d7b6bc98fa85fbc1e3ee",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "051d1a2636fe1b5dadb1f9806b9040a3",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "ff117aec63d1413c9f48bac4fd20c9a5",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "0502bb185cf85e224628b3be5e18750a",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "8999ff0a5601c423e2fa10b59425bfa2",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "f2d0d08db00ee44a5c98023ea8521bcc",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "35e1d1017b406d9ed31b2b901a1d0dbe",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "6346c88ec18632ac3ad63beae6122569",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "a08613797c5064a0b2302b9468dc88e9",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "f3d4f9dc7162d7f736c32f8a8ead5477",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "dbddd278a058fb61b8ca5301a3ae4a09",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "aca30445a8fc28b69a2bce57bd651dc3",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "1ba63aa89b4b45d893499a491e3047cd",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "1e786451b0abe1451f17b908c2d8abb3",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "80db3e75458db18efe1657f8ce686996",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "1e786451b0abe1451f17b908c2d8abb3",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "80db3e75458db18efe1657f8ce686996",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "a29bc1b96b2422dce9154ef8a404a8e6",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "c36dc72d78f9df240ae9f640dee470c2",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "a29bc1b96b2422dce9154ef8a404a8e6",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "c36dc72d78f9df240ae9f640dee470c2",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "d1e2aef8e1ba4fac62908efd3b8079c4",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "4dd471e8559a31c1425cd344646261b5",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "d1e2aef8e1ba4fac62908efd3b8079c4",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "4dd471e8559a31c1425cd344646261b5",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "0bff76811b9640d20c7104b8dabf27e8",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "b6e72c87d43dbf2a93e9a0b74952677b",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "3c8593e81564012a7638a20c0dc0267b",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "b6e72c87d43dbf2a93e9a0b74952677b",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "a6b742a577b1a2a5b99ef4acc4949735",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "3019670a3df31b6ed2bbd5d3a847afbb",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "85335e293ae1433afdf40a83e346d379",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "172855f5f89e9bd36efe7bacad3d5fc9",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "6fa16da3c74bc305a550697b7b453b21",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "dc2d4d3655e8cd65d83e355e731441a8",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "24a6884294c6c6da095e24f0dfa0faf4",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "68f39e024d3ca6bef9a0dc593ba139ab",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "24a88ffc78cd3f59a7fa7df974d79e25",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "ba97e6d831cfc129ebc46443b49c3055",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "f054f613e6a053a281b3d75c0bc19a8b",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "c95435393ac3946b0cdd288cea6fd578",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "a0ef35af73a0d6566f57cd57c603c3cd",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "ef54d4c6043e4fd789936d5fc60757af",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "a2dc425aa51d6fd086346e9418d21b97",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "73ba9c896b534902308178627e67746b",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "bc6e2a93f1cb4cf0b19ceb577eb15ab9",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "4e813fd82f679f2d87d420535cd0d549",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "24497a56d078c29c8ebaca01b655dc7c",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "955dd7032ecd7fb0e329a40964cdebb3",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "cb0519ef32e0e5a2cdcb0405def7bd9c",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "df6c673f248be2612388edc56b1e5288",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "a4913759d8f9b6013fae9c213441298d",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "1f4534097a3b1bfa1f26aec4e7eefff3",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "c97a6cc985522514c5ba5b57cd4a6b70",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "4cd0b0cd2f114ef58dc25cf148e3be64",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "4beca89d3ef221cf195bef82933a5e96",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "6d97073ef999fe7e44fa9aa8ef1b5a42",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "f3d305e647a7f77dd70a48f615cfd750",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "931ce8eab9859d20ad86c47d196ba62c",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "f3d305e647a7f77dd70a48f615cfd750",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "931ce8eab9859d20ad86c47d196ba62c",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "e80b5f536b30a23fe107852a0c2f7536",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "076df48013d64bc07aa59001819f8583",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "e80b5f536b30a23fe107852a0c2f7536",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "076df48013d64bc07aa59001819f8583",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "fcfdeb63ced9156995cf1b08ae5c861f",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "d82ad28301dc8e5b0ca98cf1da5d907c",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "fcfdeb63ced9156995cf1b08ae5c861f",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "d82ad28301dc8e5b0ca98cf1da5d907c",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "6db0247bf985f9d8c7ed85a5e5508a8b",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "097e17c460bf798edf61303789860596",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "14df40bc07bdde8184843d16d5ba7798",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "097e17c460bf798edf61303789860596",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "8542bbc154faedf633dd82bc78dc50b7",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "eb625ccd56cd37e26b6abb99ecc385c3",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "835d9280dddb9fa6554e631184a62f6d",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "5aca1f8dfd9ff294cf2ec2229e393d8e",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "f270764cfbb3791752fbd265b5787889",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "64ca7172f66176fef0ef71d5b1e51663",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "81b8aeeecb650f57d4f89636cbdf5916",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "a3c06c787f387c586de3ff6b092c32dc",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "c81b2b1f3a14b4cd20a7b93416fe893a",
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -62,7 +62,6 @@ libs/
|
||||
|
||||
# Visual Studio
|
||||
.vs
|
||||
*.vcxproj.user
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
|
||||
4
.idea/dictionaries/ericf.xml
generated
4
.idea/dictionaries/ericf.xml
generated
@ -1975,6 +1975,7 @@
|
||||
<w>noninteractively</w>
|
||||
<w>nonmultipart</w>
|
||||
<w>noone</w>
|
||||
<w>nopull</w>
|
||||
<w>norun</w>
|
||||
<w>nospeak</w>
|
||||
<w>nosub</w>
|
||||
@ -2447,6 +2448,7 @@
|
||||
<w>rawkey</w>
|
||||
<w>rawpath</w>
|
||||
<w>rawpaths</w>
|
||||
<w>rawval</w>
|
||||
<w>rayd</w>
|
||||
<w>rcade</w>
|
||||
<w>rcfile</w>
|
||||
@ -2821,6 +2823,7 @@
|
||||
<w>stdobj</w>
|
||||
<w>stdsettings</w>
|
||||
<w>stdspaz</w>
|
||||
<w>steamdeck</w>
|
||||
<w>stedit</w>
|
||||
<w>steelseries</w>
|
||||
<w>stgdict</w>
|
||||
@ -3318,6 +3321,7 @@
|
||||
<w>writeclasses</w>
|
||||
<w>writefuncs</w>
|
||||
<w>wslpath</w>
|
||||
<w>wslview</w>
|
||||
<w>wspath</w>
|
||||
<w>wsroot</w>
|
||||
<w>wtcolor</w>
|
||||
|
||||
37
CHANGELOG.md
37
CHANGELOG.md
@ -1,5 +1,29 @@
|
||||
### 1.7.28 (build 21342, api 8, 2023-09-13)
|
||||
### 1.7.28 (build 21385, api 8, 2023-09-27)
|
||||
|
||||
- Massively cleaned up code related to rendering and window systems (OpenGL,
|
||||
SDL, etc). This code had been growing into a nasty tangle for 15 years
|
||||
attempting to support various old/hacked versions of SDL, etc. I ripped out
|
||||
huge chunks of it and put back still-relevant pieces in a much more cleanly
|
||||
designed way. This should put us in a much better place for supporting various
|
||||
platforms and making graphical improvements going forward. See
|
||||
`ballistica/base/app_adapter/app_adapter_sdl.cc` for an example of the now
|
||||
nicely implemented system.
|
||||
- The engine now requires OpenGL 3.0 or newer on desktop and OpenGL ES 3.0 or
|
||||
newer on mobile. This means we're cutting off a few percent of old devices on
|
||||
Android that only support ES 2, but ES 3 has been out for 10 years now so I
|
||||
feel it is time. As mentioned above, this allows massively cleaning up the
|
||||
graphics code which means we can start to improve it.
|
||||
- Removed gamma controls. These were only active on the old Mac version anyway
|
||||
and are being removed from the upcoming SDL3, so if we want this sort of thing
|
||||
we should do it through shading in the renderer now.
|
||||
- Implemented both vsync and max-fps for the SDL build of the game. This means
|
||||
you can finally take advantage of that nice high frame rate monitor on your
|
||||
PC. Vsync supports 'Disable', 'Enabled' and 'Auto', which attempts to use
|
||||
'adaptive' vsync if available, and no vsync otherwise.
|
||||
- Spent some time tuning a few frame-timing mechanisms, so motion in the game
|
||||
should appear significantly smoother in some cases. Please let me know if it
|
||||
ever appears *less* smooth than before or if you see what looks like weird
|
||||
speed changes which could be timing problems.
|
||||
- Renamed Console to DevConsole, and added an option under advanced settings to
|
||||
always show a 'dev' button onscreen which can be used to toggle it. The
|
||||
backtick key still works also for anyone with a keyboard. I plan to add more
|
||||
@ -42,6 +66,17 @@
|
||||
to fail in some builds/runs (thanks Rikko for the heads-up).
|
||||
- (build 21327) Fixed an issue that could cause the app to pause for 3 seconds
|
||||
at shutdown.
|
||||
- Worked to improve sanity checking on C++ RenderComponents in debug builds to
|
||||
make it easier to use and avoid sending broken commands to the renderer. Some
|
||||
specifics follow.
|
||||
- RenderComponents no longer need an explicit Submit() at the end; if one goes
|
||||
out of scope not in the submitted state it will implicitly run a submit.
|
||||
Hopefully this will encourage concise code where RenderComponents are defined
|
||||
in tight scopes.
|
||||
- RenderComponents now have a ScopedTransform() call which can be used to push
|
||||
and pop the transform stack based on C++ scoping instead of the old
|
||||
PushTransform/PopTransform. This should make it harder to accidentally break
|
||||
the transform stack with unbalanced components.
|
||||
|
||||
|
||||
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
||||
|
||||
3
Makefile
3
Makefile
@ -955,8 +955,7 @@ WINDOWS_CONFIGURATION ?= Debug
|
||||
|
||||
# Stage assets and other files so a built binary will run.
|
||||
windows-staging: assets-windows resources meta
|
||||
$(STAGE_BUILD) -win-$(WINPLT) -$(WINCFGLC) \
|
||||
build/windows/$(WINCFG)_$(WINPLT)
|
||||
$(STAGE_BUILD) -win-$(WINPLT) -$(WINCFGLC) build/windows/$(WINCFG)_$(WINPLT)
|
||||
|
||||
# Build and run a debug windows build (from WSL).
|
||||
windows-debug: windows-debug-build
|
||||
|
||||
4
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
4
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
@ -1176,6 +1176,7 @@
|
||||
<w>noninteractively</w>
|
||||
<w>nonlint</w>
|
||||
<w>noone</w>
|
||||
<w>nopull</w>
|
||||
<w>notarytool</w>
|
||||
<w>nothin</w>
|
||||
<w>notorize</w>
|
||||
@ -1446,6 +1447,7 @@
|
||||
<w>raspbian</w>
|
||||
<w>rasterizer</w>
|
||||
<w>rawkey</w>
|
||||
<w>rawval</w>
|
||||
<w>rayd</w>
|
||||
<w>rcade</w>
|
||||
<w>rcva</w>
|
||||
@ -1675,6 +1677,7 @@
|
||||
<w>staticdata</w>
|
||||
<w>statictest</w>
|
||||
<w>stdint</w>
|
||||
<w>steamdeck</w>
|
||||
<w>stepfast</w>
|
||||
<w>stephane</w>
|
||||
<w>stepnum</w>
|
||||
@ -1950,6 +1953,7 @@
|
||||
<w>wreadlink</w>
|
||||
<w>writeauxiliaryfile</w>
|
||||
<w>writecall</w>
|
||||
<w>wslview</w>
|
||||
<w>wspath</w>
|
||||
<w>wsroot</w>
|
||||
<w>wtfslice</w>
|
||||
|
||||
@ -205,6 +205,8 @@ set(BALLISTICA_SOURCES
|
||||
# AUTOGENERATED_PUBLIC_BEGIN (this section is managed by the "update_project" tool)
|
||||
${BA_SRC_ROOT}/ballistica/base/app_adapter/app_adapter.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/app_adapter/app_adapter.h
|
||||
${BA_SRC_ROOT}/ballistica/base/app_adapter/app_adapter_apple.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/app_adapter/app_adapter_apple.h
|
||||
${BA_SRC_ROOT}/ballistica/base/app_adapter/app_adapter_headless.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/app_adapter/app_adapter_headless.h
|
||||
${BA_SRC_ROOT}/ballistica/base/app_adapter/app_adapter_sdl.cc
|
||||
@ -284,10 +286,31 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/component/special_component.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/component/sprite_component.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/component/sprite_component.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/framebuffer_object_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/gl_sys.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/gl_sys.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/gl_sys_windows.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/gl_sys_windows.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/mesh/mesh_asset_data_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/mesh/mesh_data_dual_texture_full_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/mesh/mesh_data_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/mesh/mesh_data_object_split_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/mesh/mesh_data_simple_full_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/mesh/mesh_data_simple_split_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/mesh/mesh_data_smoke_full_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/mesh/mesh_data_sprite_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/program/program_blur_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/program/program_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/program/program_object_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/program/program_post_process_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/program/program_shield_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/program/program_simple_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/program/program_smoke_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/program/program_sprite_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/render_target_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/renderer_gl.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/renderer_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/gl/texture_data_gl.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/graphics.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/graphics.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/graphics_server.cc
|
||||
|
||||
@ -191,6 +191,8 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_apple.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter_apple.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_headless.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter_headless.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_sdl.cc" />
|
||||
@ -270,10 +272,31 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\component\special_component.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\component\sprite_component.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\component\sprite_component.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\framebuffer_object_gl.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\gl_sys.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\gl_sys.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\gl_sys_windows.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\gl_sys_windows.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_asset_data_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_dual_texture_full_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_object_split_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_simple_full_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_simple_split_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_smoke_full_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_sprite_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_blur_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_object_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_post_process_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_shield_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_simple_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_smoke_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_sprite_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\render_target_gl.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\renderer_gl.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\renderer_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\texture_data_gl.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\graphics.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\graphics.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\graphics_server.cc" />
|
||||
|
||||
@ -7,6 +7,12 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter.h">
|
||||
<Filter>ballistica\base\app_adapter</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_apple.cc">
|
||||
<Filter>ballistica\base\app_adapter</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter_apple.h">
|
||||
<Filter>ballistica\base\app_adapter</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_headless.cc">
|
||||
<Filter>ballistica\base\app_adapter</Filter>
|
||||
</ClCompile>
|
||||
@ -244,18 +250,81 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\component\sprite_component.h">
|
||||
<Filter>ballistica\base\graphics\component</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\framebuffer_object_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\gl_sys.cc">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\gl_sys.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\gl_sys_windows.cc">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\gl_sys_windows.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_asset_data_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_dual_texture_full_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_object_split_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_simple_full_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_simple_split_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_smoke_full_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_sprite_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_blur_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_object_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_post_process_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_shield_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_simple_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_smoke_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_sprite_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\render_target_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\renderer_gl.cc">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\renderer_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\texture_data_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\graphics.cc">
|
||||
<Filter>ballistica\base\graphics</Filter>
|
||||
</ClCompile>
|
||||
@ -1880,6 +1949,8 @@
|
||||
<Filter Include="ballistica\base\graphics" />
|
||||
<Filter Include="ballistica\base\graphics\component" />
|
||||
<Filter Include="ballistica\base\graphics\gl" />
|
||||
<Filter Include="ballistica\base\graphics\gl\mesh" />
|
||||
<Filter Include="ballistica\base\graphics\gl\program" />
|
||||
<Filter Include="ballistica\base\graphics\mesh" />
|
||||
<Filter Include="ballistica\base\graphics\renderer" />
|
||||
<Filter Include="ballistica\base\graphics\support" />
|
||||
|
||||
19
ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.user
Executable file
19
ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.user
Executable file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@ -186,6 +186,8 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_apple.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter_apple.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_headless.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter_headless.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_sdl.cc" />
|
||||
@ -265,10 +267,31 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\component\special_component.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\component\sprite_component.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\component\sprite_component.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\framebuffer_object_gl.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\gl_sys.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\gl_sys.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\gl_sys_windows.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\gl_sys_windows.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_asset_data_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_dual_texture_full_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_object_split_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_simple_full_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_simple_split_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_smoke_full_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_sprite_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_blur_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_object_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_post_process_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_shield_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_simple_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_smoke_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_sprite_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\render_target_gl.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\renderer_gl.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\renderer_gl.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\texture_data_gl.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\graphics.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\graphics.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\graphics_server.cc" />
|
||||
|
||||
@ -7,6 +7,12 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter.h">
|
||||
<Filter>ballistica\base\app_adapter</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_apple.cc">
|
||||
<Filter>ballistica\base\app_adapter</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter_apple.h">
|
||||
<Filter>ballistica\base\app_adapter</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_adapter\app_adapter_headless.cc">
|
||||
<Filter>ballistica\base\app_adapter</Filter>
|
||||
</ClCompile>
|
||||
@ -244,18 +250,81 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\component\sprite_component.h">
|
||||
<Filter>ballistica\base\graphics\component</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\framebuffer_object_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\gl_sys.cc">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\gl_sys.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\gl_sys_windows.cc">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\gl_sys_windows.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_asset_data_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_dual_texture_full_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_object_split_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_simple_full_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_simple_split_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_smoke_full_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\mesh\mesh_data_sprite_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\mesh</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_blur_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_object_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_post_process_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_shield_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_simple_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_smoke_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\program\program_sprite_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl\program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\render_target_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\gl\renderer_gl.cc">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\renderer_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\gl\texture_data_gl.h">
|
||||
<Filter>ballistica\base\graphics\gl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\graphics.cc">
|
||||
<Filter>ballistica\base\graphics</Filter>
|
||||
</ClCompile>
|
||||
@ -1880,6 +1949,8 @@
|
||||
<Filter Include="ballistica\base\graphics" />
|
||||
<Filter Include="ballistica\base\graphics\component" />
|
||||
<Filter Include="ballistica\base\graphics\gl" />
|
||||
<Filter Include="ballistica\base\graphics\gl\mesh" />
|
||||
<Filter Include="ballistica\base\graphics\gl\program" />
|
||||
<Filter Include="ballistica\base\graphics\mesh" />
|
||||
<Filter Include="ballistica\base\graphics\renderer" />
|
||||
<Filter Include="ballistica\base\graphics\support" />
|
||||
|
||||
19
ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.user
Executable file
19
ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.user
Executable file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@ -9,12 +9,12 @@
|
||||
"src/ballistica/base/graphics/texture/dds.h",
|
||||
"src/ballistica/base/graphics/texture/ktx.cc",
|
||||
"src/ballistica/core/platform/android/android_gl3.h",
|
||||
"src/ballistica/core/platform/apple/app_delegate.h",
|
||||
"src/ballistica/core/platform/apple/scripting_bridge_music.h",
|
||||
"src/ballistica/base/platform/apple/app_delegate.h",
|
||||
"src/ballistica/base/platform/apple/scripting_bridge_music.h",
|
||||
"src/ballistica/core/platform/android/utf8/checked.h",
|
||||
"src/ballistica/core/platform/android/utf8/unchecked.h",
|
||||
"src/ballistica/core/platform/android/utf8/core.h",
|
||||
"src/ballistica/core/platform/apple/sdl_main_mac.h",
|
||||
"src/ballistica/base/platform/apple/sdl_main_mac.h",
|
||||
"src/ballistica/base/platform/oculus/main_rift.cc",
|
||||
"src/ballistica/core/platform/android/android_gl3.c"
|
||||
],
|
||||
|
||||
@ -246,6 +246,7 @@ ctx.filter_file_extensions = {
|
||||
'.sh',
|
||||
'.sln',
|
||||
'.vcxproj',
|
||||
'.user',
|
||||
'.cmd',
|
||||
'.hlsl',
|
||||
'.gradle',
|
||||
|
||||
@ -27,6 +27,7 @@ from _babase import (
|
||||
apptime,
|
||||
apptimer,
|
||||
AppTimer,
|
||||
can_toggle_fullscreen,
|
||||
charstr,
|
||||
clipboard_get_text,
|
||||
clipboard_has_text,
|
||||
@ -51,7 +52,6 @@ from _babase import (
|
||||
get_string_width,
|
||||
get_v1_cloud_log_file_path,
|
||||
getsimplesound,
|
||||
has_gamma_control,
|
||||
has_user_run_commands,
|
||||
have_chars,
|
||||
have_permission,
|
||||
@ -90,6 +90,8 @@ from _babase import (
|
||||
shutdown_suppress_end,
|
||||
shutdown_suppress_count,
|
||||
SimpleSound,
|
||||
supports_max_fps,
|
||||
supports_vsync,
|
||||
unlock_all_input,
|
||||
user_agent_string,
|
||||
Vec3,
|
||||
@ -192,6 +194,7 @@ __all__ = [
|
||||
'apptimer',
|
||||
'AppTimer',
|
||||
'Call',
|
||||
'can_toggle_fullscreen',
|
||||
'charstr',
|
||||
'clipboard_get_text',
|
||||
'clipboard_has_text',
|
||||
@ -230,7 +233,6 @@ __all__ = [
|
||||
'getclass',
|
||||
'getsimplesound',
|
||||
'handle_leftover_v1_cloud_log_file',
|
||||
'has_gamma_control',
|
||||
'has_user_run_commands',
|
||||
'have_chars',
|
||||
'have_permission',
|
||||
@ -297,6 +299,8 @@ __all__ = [
|
||||
'storagename',
|
||||
'StringEditAdapter',
|
||||
'StringEditSubsystem',
|
||||
'supports_max_fps',
|
||||
'supports_vsync',
|
||||
'TeamNotFoundError',
|
||||
'timestring',
|
||||
'UIScale',
|
||||
|
||||
@ -736,7 +736,7 @@ class App:
|
||||
if self.state is self.State.PAUSED:
|
||||
self._on_resume()
|
||||
|
||||
# Handle initially entering or returning to other states.
|
||||
# Entering or returning to running state
|
||||
if self._initial_sign_in_completed and self._meta_scan_completed:
|
||||
if self.state != self.State.RUNNING:
|
||||
self.state = self.State.RUNNING
|
||||
@ -744,6 +744,7 @@ class App:
|
||||
if not self._called_on_running:
|
||||
self._called_on_running = True
|
||||
self._on_running()
|
||||
# Entering or returning to loading state:
|
||||
elif self._init_completed:
|
||||
if self.state is not self.State.LOADING:
|
||||
self.state = self.State.LOADING
|
||||
@ -751,6 +752,8 @@ class App:
|
||||
if not self._called_on_loading:
|
||||
self._called_on_loading = True
|
||||
self._on_loading()
|
||||
|
||||
# Entering or returning to initing state:
|
||||
elif self._native_bootstrapping_completed:
|
||||
if self.state is not self.State.INITING:
|
||||
self.state = self.State.INITING
|
||||
@ -758,13 +761,21 @@ class App:
|
||||
if not self._called_on_initing:
|
||||
self._called_on_initing = True
|
||||
self._on_initing()
|
||||
else:
|
||||
# Only possibility left is app-start. We shouldn't be
|
||||
# getting called before at least that happens.
|
||||
assert self._native_start_called
|
||||
assert self.state is self.State.NOT_RUNNING
|
||||
if bool(True):
|
||||
|
||||
# Entering or returning to native bootstrapping:
|
||||
elif self._native_start_called:
|
||||
if self.state is not self.State.NATIVE_BOOTSTRAPPING:
|
||||
self.state = self.State.NATIVE_BOOTSTRAPPING
|
||||
_babase.lifecyclelog('app state native bootstrapping')
|
||||
else:
|
||||
# Only logical possibility left is NOT_RUNNING, in which
|
||||
# case we should not be getting called.
|
||||
logging.warning(
|
||||
'App._update_state called while in %s state;'
|
||||
' should not happen.',
|
||||
self.state.value,
|
||||
stack_info=True,
|
||||
)
|
||||
|
||||
async def _shutdown(self) -> None:
|
||||
import asyncio
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21342
|
||||
TARGET_BALLISTICA_BUILD = 21385
|
||||
TARGET_BALLISTICA_VERSION = '1.7.28'
|
||||
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ from babase import (
|
||||
apptimer,
|
||||
AppTimer,
|
||||
Call,
|
||||
can_toggle_fullscreen,
|
||||
charstr,
|
||||
clipboard_is_supported,
|
||||
clipboard_set_text,
|
||||
@ -52,7 +53,6 @@ from babase import (
|
||||
get_string_width,
|
||||
get_type_name,
|
||||
getclass,
|
||||
has_gamma_control,
|
||||
have_permission,
|
||||
in_logic_thread,
|
||||
increment_analytics_count,
|
||||
@ -76,6 +76,8 @@ from babase import (
|
||||
set_low_level_config_value,
|
||||
set_ui_input_device,
|
||||
SpecialChar,
|
||||
supports_max_fps,
|
||||
supports_vsync,
|
||||
timestring,
|
||||
UIScale,
|
||||
unlock_all_input,
|
||||
@ -136,6 +138,7 @@ __all__ = [
|
||||
'buttonwidget',
|
||||
'Call',
|
||||
'can_show_ad',
|
||||
'can_toggle_fullscreen',
|
||||
'charstr',
|
||||
'checkboxwidget',
|
||||
'clipboard_is_supported',
|
||||
@ -165,7 +168,6 @@ __all__ = [
|
||||
'getmesh',
|
||||
'getsound',
|
||||
'gettexture',
|
||||
'has_gamma_control',
|
||||
'has_video_ads',
|
||||
'have_incentivized_ad',
|
||||
'have_permission',
|
||||
@ -205,6 +207,8 @@ __all__ = [
|
||||
'show_online_score_ui',
|
||||
'Sound',
|
||||
'SpecialChar',
|
||||
'supports_max_fps',
|
||||
'supports_vsync',
|
||||
'Texture',
|
||||
'textwidget',
|
||||
'timestring',
|
||||
|
||||
@ -243,6 +243,7 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
|
||||
# Don't rebuild if the menu is open or if our language and
|
||||
# language-list hasn't changed.
|
||||
|
||||
# NOTE - although we now support widgets updating their own
|
||||
# translations, we still change the label formatting on the language
|
||||
# menu based on the language so still need this. ...however we could
|
||||
|
||||
@ -4,12 +4,15 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
from bauiv1lib.popup import PopupMenu
|
||||
from bauiv1lib.config import ConfigCheckBox, ConfigNumberEdit
|
||||
from bauiv1lib.config import ConfigCheckBox
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
class GraphicsSettingsWindow(bui.Window):
|
||||
"""Window for graphics settings."""
|
||||
@ -42,23 +45,23 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
uiscale = app.ui_v1.uiscale
|
||||
width = 450.0
|
||||
height = 302.0
|
||||
self._max_fps_dirty = False
|
||||
self._last_max_fps_set_time = bui.apptime()
|
||||
self._last_max_fps_str = ''
|
||||
|
||||
self._show_fullscreen = False
|
||||
fullscreen_spacing_top = spacing * 0.2
|
||||
fullscreen_spacing = spacing * 1.2
|
||||
if uiscale == bui.UIScale.LARGE and app.classic.platform != 'android':
|
||||
if bui.can_toggle_fullscreen():
|
||||
self._show_fullscreen = True
|
||||
height += fullscreen_spacing + fullscreen_spacing_top
|
||||
|
||||
show_gamma = False
|
||||
gamma_spacing = spacing * 1.3
|
||||
if bui.has_gamma_control():
|
||||
show_gamma = True
|
||||
height += gamma_spacing
|
||||
show_vsync = bui.supports_vsync()
|
||||
show_tv_mode = not bui.app.env.vr
|
||||
|
||||
show_vsync = False
|
||||
if app.classic.platform == 'mac':
|
||||
show_vsync = True
|
||||
show_max_fps = bui.supports_max_fps()
|
||||
if show_max_fps:
|
||||
height += 50
|
||||
|
||||
show_resolution = True
|
||||
if app.env.vr:
|
||||
@ -70,7 +73,7 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
base_scale = (
|
||||
2.4
|
||||
2.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5
|
||||
if uiscale is bui.UIScale.MEDIUM
|
||||
@ -91,19 +94,20 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
)
|
||||
)
|
||||
|
||||
btn = bui.buttonwidget(
|
||||
back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(35, height - 50),
|
||||
size=(120, 60),
|
||||
# size=(120, 60),
|
||||
size=(60, 60),
|
||||
scale=0.8,
|
||||
text_scale=1.2,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=back_button)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -115,15 +119,7 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
v_align='top',
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
self._fullscreen_checkbox: bui.Widget | None = None
|
||||
self._gamma_controls: ConfigNumberEdit | None = None
|
||||
if self._show_fullscreen:
|
||||
v -= fullscreen_spacing_top
|
||||
self._fullscreen_checkbox = ConfigCheckBox(
|
||||
@ -149,34 +145,10 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
self._have_selected_child = True
|
||||
v -= fullscreen_spacing
|
||||
|
||||
if show_gamma:
|
||||
self._gamma_controls = gmc = ConfigNumberEdit(
|
||||
parent=self._root_widget,
|
||||
position=(90, v),
|
||||
configkey='Screen Gamma',
|
||||
displayname=bui.Lstr(resource=self._r + '.gammaText'),
|
||||
minval=0.1,
|
||||
maxval=2.0,
|
||||
increment=0.1,
|
||||
xoffset=-70,
|
||||
textscale=0.85,
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=gmc.plusbutton,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
if not self._have_selected_child:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=gmc.minusbutton
|
||||
)
|
||||
self._have_selected_child = True
|
||||
v -= gamma_spacing
|
||||
|
||||
self._selected_color = (0.5, 1, 0.5, 1)
|
||||
self._unselected_color = (0.7, 0.7, 0.7, 1)
|
||||
|
||||
# quality
|
||||
# Quality
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(60, v),
|
||||
@ -208,7 +180,7 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
on_value_change_call=self._set_quality,
|
||||
)
|
||||
|
||||
# texture controls
|
||||
# Texture controls
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(230, v),
|
||||
@ -244,8 +216,9 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
|
||||
h_offs = 0
|
||||
|
||||
resolution_popup: PopupMenu | None = None
|
||||
|
||||
if show_resolution:
|
||||
# resolution
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h_offs + 60, v),
|
||||
@ -258,32 +231,17 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
# on standard android we have 'Auto', 'Native', and a few
|
||||
# HD standards
|
||||
# On standard android we have 'Auto', 'Native', and a few
|
||||
# HD standards.
|
||||
if app.classic.platform == 'android':
|
||||
# on cardboard/daydream android we have a few
|
||||
# render-target-scale options
|
||||
if app.classic.subplatform == 'cardboard':
|
||||
rawval = bui.app.config.resolve('GVR Render Target Scale')
|
||||
current_res_cardboard = (
|
||||
str(
|
||||
min(
|
||||
100,
|
||||
max(
|
||||
10,
|
||||
int(
|
||||
round(
|
||||
bui.app.config.resolve(
|
||||
'GVR Render Target Scale'
|
||||
)
|
||||
* 100.0
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
+ '%'
|
||||
str(min(100, max(10, int(round(rawval * 100.0))))) + '%'
|
||||
)
|
||||
PopupMenu(
|
||||
resolution_popup = PopupMenu(
|
||||
parent=self._root_widget,
|
||||
position=(h_offs + 60, v - 50),
|
||||
width=120,
|
||||
@ -301,16 +259,16 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
bui.Lstr(resource='nativeText'),
|
||||
]
|
||||
for res in [1440, 1080, 960, 720, 480]:
|
||||
# nav bar is 72px so lets allow for that in what
|
||||
# choices we show
|
||||
# Nav bar is 72px so lets allow for that in what
|
||||
# choices we show.
|
||||
if native_res[1] >= res - 72:
|
||||
res_str = str(res) + 'p'
|
||||
res_str = f'{res}p'
|
||||
choices.append(res_str)
|
||||
choices_display.append(bui.Lstr(value=res_str))
|
||||
current_res_android = bui.app.config.resolve(
|
||||
'Resolution (Android)'
|
||||
)
|
||||
PopupMenu(
|
||||
resolution_popup = PopupMenu(
|
||||
parent=self._root_widget,
|
||||
position=(h_offs + 60, v - 50),
|
||||
width=120,
|
||||
@ -325,26 +283,11 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
# set pixel-scale instead.
|
||||
current_res = bui.get_display_resolution()
|
||||
if current_res is None:
|
||||
rawval = bui.app.config.resolve('Screen Pixel Scale')
|
||||
current_res2 = (
|
||||
str(
|
||||
min(
|
||||
100,
|
||||
max(
|
||||
10,
|
||||
int(
|
||||
round(
|
||||
bui.app.config.resolve(
|
||||
'Screen Pixel Scale'
|
||||
)
|
||||
* 100.0
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
+ '%'
|
||||
str(min(100, max(10, int(round(rawval * 100.0))))) + '%'
|
||||
)
|
||||
PopupMenu(
|
||||
resolution_popup = PopupMenu(
|
||||
parent=self._root_widget,
|
||||
position=(h_offs + 60, v - 50),
|
||||
width=120,
|
||||
@ -355,11 +298,16 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'obsolete path; discrete resolutions'
|
||||
'obsolete code path; discrete resolutions'
|
||||
' no longer supported'
|
||||
)
|
||||
if resolution_popup is not None:
|
||||
bui.widget(
|
||||
edit=resolution_popup.get_button(),
|
||||
left_widget=back_button,
|
||||
)
|
||||
|
||||
# vsync
|
||||
vsync_popup: PopupMenu | None = None
|
||||
if show_vsync:
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -372,8 +320,7 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
PopupMenu(
|
||||
vsync_popup = PopupMenu(
|
||||
parent=self._root_widget,
|
||||
position=(230, v - 50),
|
||||
width=150,
|
||||
@ -387,8 +334,59 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
current_choice=bui.app.config.resolve('Vertical Sync'),
|
||||
on_value_change_call=self._set_vsync,
|
||||
)
|
||||
if resolution_popup is not None:
|
||||
bui.widget(
|
||||
edit=vsync_popup.get_button(),
|
||||
left_widget=resolution_popup.get_button(),
|
||||
)
|
||||
|
||||
if resolution_popup is not None and vsync_popup is not None:
|
||||
bui.widget(
|
||||
edit=resolution_popup.get_button(),
|
||||
right_widget=vsync_popup.get_button(),
|
||||
)
|
||||
|
||||
v -= 90
|
||||
self._max_fps_text: bui.Widget | None = None
|
||||
if show_max_fps:
|
||||
v -= 5
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(155, v + 10),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(resource=self._r + '.maxFPSText'),
|
||||
color=bui.app.ui_v1.heading_color,
|
||||
scale=0.9,
|
||||
maxwidth=90,
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
max_fps_str = str(bui.app.config.resolve('Max FPS'))
|
||||
self._last_max_fps_str = max_fps_str
|
||||
self._max_fps_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(170, v - 5),
|
||||
size=(105, 30),
|
||||
text=max_fps_str,
|
||||
max_chars=5,
|
||||
editable=True,
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
on_return_press_call=self._on_max_fps_return_press,
|
||||
)
|
||||
v -= 45
|
||||
|
||||
if self._max_fps_text is not None and resolution_popup is not None:
|
||||
bui.widget(
|
||||
edit=resolution_popup.get_button(),
|
||||
down_widget=self._max_fps_text,
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._max_fps_text,
|
||||
up_widget=resolution_popup.get_button(),
|
||||
)
|
||||
|
||||
fpsc = ConfigCheckBox(
|
||||
parent=self._root_widget,
|
||||
position=(69, v - 6),
|
||||
@ -398,9 +396,17 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
displayname=bui.Lstr(resource=self._r + '.showFPSText'),
|
||||
maxwidth=130,
|
||||
)
|
||||
if self._max_fps_text is not None:
|
||||
bui.widget(
|
||||
edit=self._max_fps_text,
|
||||
down_widget=fpsc.widget,
|
||||
)
|
||||
bui.widget(
|
||||
edit=fpsc.widget,
|
||||
up_widget=self._max_fps_text,
|
||||
)
|
||||
|
||||
# (tv mode doesnt apply to vr)
|
||||
if not bui.app.env.vr:
|
||||
if show_tv_mode:
|
||||
tvc = ConfigCheckBox(
|
||||
parent=self._root_widget,
|
||||
position=(240, v - 6),
|
||||
@ -410,13 +416,8 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
displayname=bui.Lstr(resource=self._r + '.tvBorderText'),
|
||||
maxwidth=130,
|
||||
)
|
||||
# grumble..
|
||||
bui.widget(edit=fpsc.widget, right_widget=tvc.widget)
|
||||
try:
|
||||
pass
|
||||
|
||||
except Exception:
|
||||
logging.exception('Exception wiring up graphics settings UI.')
|
||||
bui.widget(edit=tvc.widget, left_widget=fpsc.widget)
|
||||
|
||||
v -= spacing
|
||||
|
||||
@ -429,6 +430,10 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.settings import allsettings
|
||||
|
||||
# Applying max-fps takes a few moments. Apply if it hasn't been
|
||||
# yet.
|
||||
self._apply_max_fps()
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
@ -469,7 +474,60 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
cfg['Vertical Sync'] = val
|
||||
cfg.apply_and_commit()
|
||||
|
||||
def _on_max_fps_return_press(self) -> None:
|
||||
self._apply_max_fps()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=cast(bui.Widget, 0)
|
||||
)
|
||||
|
||||
def _apply_max_fps(self) -> None:
|
||||
if not self._max_fps_dirty or not self._max_fps_text:
|
||||
return
|
||||
|
||||
val: Any = bui.textwidget(query=self._max_fps_text)
|
||||
assert isinstance(val, str)
|
||||
# If there's a broken value, replace it with the default.
|
||||
try:
|
||||
ival = int(val)
|
||||
except ValueError:
|
||||
ival = bui.app.config.default_value('Max FPS')
|
||||
assert isinstance(ival, int)
|
||||
|
||||
# Clamp to reasonable limits (allow -1 to mean no max).
|
||||
if ival != -1:
|
||||
ival = max(10, ival)
|
||||
ival = min(99999, ival)
|
||||
|
||||
# Store it to the config.
|
||||
cfg = bui.app.config
|
||||
cfg['Max FPS'] = ival
|
||||
cfg.apply_and_commit()
|
||||
|
||||
# Update the display if we changed the value.
|
||||
if str(ival) != val:
|
||||
bui.textwidget(edit=self._max_fps_text, text=str(ival))
|
||||
|
||||
self._max_fps_dirty = False
|
||||
|
||||
def _update_controls(self) -> None:
|
||||
if self._max_fps_text is not None:
|
||||
# Keep track of when the max-fps value changes. Once it
|
||||
# remains stable for a few moments, apply it.
|
||||
val: Any = bui.textwidget(query=self._max_fps_text)
|
||||
assert isinstance(val, str)
|
||||
if val != self._last_max_fps_str:
|
||||
# Oop; it changed. Note the time and the fact that we'll
|
||||
# need to apply it at some point.
|
||||
self._max_fps_dirty = True
|
||||
self._last_max_fps_str = val
|
||||
self._last_max_fps_set_time = bui.apptime()
|
||||
else:
|
||||
# If its been stable long enough, apply it.
|
||||
if (
|
||||
self._max_fps_dirty
|
||||
and bui.apptime() - self._last_max_fps_set_time > 1.0
|
||||
):
|
||||
self._apply_max_fps()
|
||||
if self._show_fullscreen:
|
||||
bui.checkboxwidget(
|
||||
edit=self._fullscreen_checkbox,
|
||||
|
||||
@ -2,11 +2,19 @@
|
||||
|
||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||
|
||||
#if BA_OSTYPE_ANDROID
|
||||
#include "ballistica/base/app_adapter/app_adapter_android.h"
|
||||
#endif
|
||||
#include "ballistica/base/app_adapter/app_adapter_apple.h"
|
||||
#include "ballistica/base/app_adapter/app_adapter_headless.h"
|
||||
#include "ballistica/base/app_adapter/app_adapter_sdl.h"
|
||||
#include "ballistica/base/app_adapter/app_adapter_vr.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/graphics/renderer/renderer.h"
|
||||
#include "ballistica/base/input/input.h"
|
||||
#include "ballistica/base/networking/network_reader.h"
|
||||
#include "ballistica/base/networking/networking.h"
|
||||
#include "ballistica/base/platform/base_platform.h"
|
||||
#include "ballistica/base/support/stress_test.h"
|
||||
#include "ballistica/base/ui/ui.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
@ -14,20 +22,47 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
auto AppAdapter::Create() -> AppAdapter* {
|
||||
assert(g_core);
|
||||
|
||||
// TEMP - need to init sdl on our legacy mac build even though its not
|
||||
// technically an SDL app. Kill this once the old mac build is gone.
|
||||
#if BA_LEGACY_MACOS_BUILD
|
||||
AppAdapterSDL::InitSDL();
|
||||
#endif
|
||||
|
||||
AppAdapter* app_adapter{};
|
||||
|
||||
#if BA_HEADLESS_BUILD
|
||||
app_adapter = new AppAdapterHeadless();
|
||||
#elif BA_OSTYPE_ANDROID
|
||||
app_adapter = new AppAdapterAndroid();
|
||||
#elif BA_XCODE_BUILD
|
||||
app_adapter = new AppAdapterApple();
|
||||
#elif BA_RIFT_BUILD
|
||||
// Rift build can spin up in either VR or regular mode.
|
||||
if (g_core->vr_mode) {
|
||||
app_adapter = new AppAdapterVR();
|
||||
} else {
|
||||
app_adapter = new AppAdapterSDL();
|
||||
}
|
||||
#elif BA_CARDBOARD_BUILD
|
||||
app_adapter = new AppAdapterVR();
|
||||
#elif BA_SDL_BUILD
|
||||
app_adapter = new AppAdapterSDL();
|
||||
#else
|
||||
#error No app adapter defined for this build.
|
||||
#endif
|
||||
|
||||
assert(app_adapter);
|
||||
return app_adapter;
|
||||
}
|
||||
|
||||
AppAdapter::AppAdapter() = default;
|
||||
|
||||
AppAdapter::~AppAdapter() = default;
|
||||
|
||||
void AppAdapter::LogicThreadDoApplyAppConfig() {
|
||||
assert(g_base->InLogicThread());
|
||||
}
|
||||
|
||||
auto AppAdapter::ManagesEventLoop() const -> bool {
|
||||
// We have 2 redundant values for essentially the same thing;
|
||||
// should get rid of IsEventPushMode() once we've created
|
||||
// App subclasses for our various platforms.
|
||||
return !g_core->platform->IsEventPushMode();
|
||||
}
|
||||
auto AppAdapter::ManagesMainThreadEventLoop() const -> bool { return true; }
|
||||
|
||||
void AppAdapter::OnMainThreadStartApp() {
|
||||
assert(g_base);
|
||||
@ -37,11 +72,12 @@ void AppAdapter::OnMainThreadStartApp() {
|
||||
// Add some common input devices where applicable. More specific ones (SDL
|
||||
// Joysticks, etc.) get added in subclasses.
|
||||
|
||||
// If we've got a nice themed hardware cursor, show it. Otherwise we'll
|
||||
// render it manually, which is laggier but gets the job done.
|
||||
g_core->platform->SetHardwareCursorVisible(g_buildconfig.hardware_cursor());
|
||||
|
||||
// FIXME: This stuff should probably go elsewhere.
|
||||
if (!g_core->HeadlessMode()) {
|
||||
// If we've got a nice themed hardware cursor, show it. Otherwise we'll
|
||||
// render it manually, which is laggier but gets the job done.
|
||||
g_base->platform->SetHardwareCursorVisible(g_buildconfig.hardware_cursor());
|
||||
|
||||
// On desktop systems we just assume keyboard input exists and add it
|
||||
// immediately.
|
||||
if (g_core->platform->IsRunningOnDesktop()) {
|
||||
@ -56,74 +92,82 @@ void AppAdapter::OnMainThreadStartApp() {
|
||||
}
|
||||
}
|
||||
|
||||
void AppAdapter::DrawFrame(bool during_resize) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
void AppAdapter::OnAppStart() { assert(g_base->InLogicThread()); }
|
||||
void AppAdapter::OnAppPause() { assert(g_base->InLogicThread()); }
|
||||
void AppAdapter::OnAppResume() { assert(g_base->InLogicThread()); }
|
||||
void AppAdapter::OnAppShutdown() { assert(g_base->InLogicThread()); }
|
||||
void AppAdapter::OnAppShutdownComplete() { assert(g_base->InLogicThread()); }
|
||||
void AppAdapter::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
||||
void AppAdapter::DoApplyAppConfig() { assert(g_base->InLogicThread()); }
|
||||
|
||||
// It's possible to be asked to draw before we're ready.
|
||||
if (!g_base->graphics_server || !g_base->graphics_server->renderer()) {
|
||||
return;
|
||||
}
|
||||
// void AppAdapter::DrawFrame(bool during_resize) {
|
||||
// assert(g_base->InGraphicsThread());
|
||||
|
||||
millisecs_t starttime = g_core->GetAppTimeMillisecs();
|
||||
// // It's possible to be asked to draw before we're ready.
|
||||
// if (!g_base->graphics_server || !g_base->graphics_server->renderer()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// A resize-draw event means that we're drawing due to a window resize.
|
||||
// In this case we ignore regular draw events for a short while
|
||||
// afterwards which makes resizing smoother.
|
||||
//
|
||||
// FIXME: should figure out the *correct* way to handle this; I believe
|
||||
// the underlying cause here is some sort of context contention across
|
||||
// threads.
|
||||
if (during_resize) {
|
||||
last_resize_draw_event_time_ = starttime;
|
||||
} else {
|
||||
if (starttime - last_resize_draw_event_time_ < (1000 / 30)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
g_base->graphics_server->TryRender();
|
||||
RunRenderUpkeepCycle();
|
||||
}
|
||||
// millisecs_t starttime = g_core->GetAppTimeMillisecs();
|
||||
|
||||
void AppAdapter::RunRenderUpkeepCycle() {
|
||||
// This should only be firing if the OS is handling the event loop.
|
||||
assert(!ManagesEventLoop());
|
||||
// // A resize-draw event means that we're drawing due to a window resize.
|
||||
// // In this case we ignore regular draw events for a short while
|
||||
// // afterwards which makes resizing smoother.
|
||||
// //
|
||||
// // FIXME: should figure out the *correct* way to handle this; I believe
|
||||
// // the underlying cause here is some sort of context contention across
|
||||
// // threads.
|
||||
// if (during_resize) {
|
||||
// last_resize_draw_event_time_ = starttime;
|
||||
// } else {
|
||||
// if (starttime - last_resize_draw_event_time_ < (1000 / 30)) {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// g_base->graphics_server->TryRender();
|
||||
// // RunRenderUpkeepCycle();
|
||||
// }
|
||||
|
||||
// Pump the main event loop (when we're being driven by frame-draw
|
||||
// callbacks, this is the only place that gets done).
|
||||
g_core->main_event_loop()->RunSingleCycle();
|
||||
// void AppAdapter::RunRenderUpkeepCycle() {
|
||||
// // This should only be firing if the OS is handling the event loop.
|
||||
// assert(!ManagesMainThreadEventLoop());
|
||||
|
||||
// Now do the general app event cycle for whoever needs to process things.
|
||||
// FIXME KILL THIS.
|
||||
RunEvents();
|
||||
}
|
||||
// // Pump the main event loop (when we're being driven by frame-draw
|
||||
// // callbacks, this is the only place that gets done).
|
||||
// g_core->main_event_loop()->RunSingleCycle();
|
||||
|
||||
// // Now do the general app event cycle for whoever needs to process things.
|
||||
// // FIXME KILL THIS.
|
||||
// RunEvents();
|
||||
// }
|
||||
|
||||
// FIXME KILL THIS.
|
||||
void AppAdapter::RunEvents() {
|
||||
// There's probably a better place for this.
|
||||
g_base->stress_test()->Update();
|
||||
// void AppAdapter::RunEvents() {
|
||||
// There's probably a better place for this.
|
||||
// g_base->stress_test()->Update();
|
||||
|
||||
// Give platforms a chance to pump/handle their own events.
|
||||
//
|
||||
// FIXME: now that we have app class overrides, platform should really not
|
||||
// be doing event handling. (need to fix Rift build in this regard).
|
||||
g_core->platform->RunEvents();
|
||||
}
|
||||
// Give platforms a chance to pump/handle their own events.
|
||||
//
|
||||
// FIXME: now that we have app class overrides, platform should really not
|
||||
// be doing event handling. (need to fix Rift build in this regard).
|
||||
// g_core->platform->RunEvents();
|
||||
// }
|
||||
|
||||
void AppAdapter::UpdatePauseResume_() {
|
||||
if (app_paused_) {
|
||||
// Unpause if no one wants pause.
|
||||
if (!app_pause_requested_) {
|
||||
OnAppResume_();
|
||||
app_paused_ = false;
|
||||
}
|
||||
} else {
|
||||
// OnAppPause if anyone wants.
|
||||
if (app_pause_requested_) {
|
||||
OnAppPause_();
|
||||
app_paused_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// void AppAdapter::UpdatePauseResume_() {
|
||||
// if (app_paused_) {
|
||||
// // Unpause if no one wants pause.
|
||||
// if (!app_pause_requested_) {
|
||||
// OnAppResume_();
|
||||
// app_paused_ = false;
|
||||
// }
|
||||
// } else {
|
||||
// // OnAppPause if anyone wants.
|
||||
// if (app_pause_requested_) {
|
||||
// OnAppPause_();
|
||||
// app_paused_ = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void AppAdapter::OnAppPause_() {
|
||||
assert(g_core->InMainThread());
|
||||
@ -144,7 +188,7 @@ void AppAdapter::OnAppPause_() {
|
||||
|
||||
void AppAdapter::OnAppResume_() {
|
||||
assert(g_core->InMainThread());
|
||||
last_app_resume_time_ = g_core->GetAppTimeMillisecs();
|
||||
// last_app_resume_time_ = g_core->GetAppTimeMillisecs();
|
||||
|
||||
// Spin all event-loops back up.
|
||||
EventLoop::SetEventLoopsPaused(false);
|
||||
@ -173,6 +217,13 @@ void AppAdapter::OnAppResume_() {
|
||||
void AppAdapter::PauseApp() {
|
||||
assert(g_core);
|
||||
assert(g_core->InMainThread());
|
||||
|
||||
if (app_paused_) {
|
||||
Log(LogLevel::kWarning,
|
||||
"AppAdapter::PauseApp() called with app already paused.");
|
||||
return;
|
||||
}
|
||||
|
||||
millisecs_t start_time{core::CorePlatform::GetCurrentMillisecs()};
|
||||
|
||||
// Apple mentioned 5 seconds to run stuff once backgrounded or they bring
|
||||
@ -181,9 +232,10 @@ void AppAdapter::PauseApp() {
|
||||
|
||||
g_core->platform->DebugLog(
|
||||
"PauseApp@" + std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
||||
assert(!app_pause_requested_);
|
||||
app_pause_requested_ = true;
|
||||
UpdatePauseResume_();
|
||||
// assert(!app_pause_requested_);
|
||||
// app_pause_requested_ = true;
|
||||
OnAppPause_();
|
||||
// UpdatePauseResume_();
|
||||
|
||||
// We assume that the OS will completely suspend our process the moment we
|
||||
// return from this call (though this is not technically true on all
|
||||
@ -219,13 +271,21 @@ void AppAdapter::PauseApp() {
|
||||
}
|
||||
|
||||
void AppAdapter::ResumeApp() {
|
||||
assert(g_core && g_core->InMainThread());
|
||||
assert(g_core);
|
||||
assert(g_core->InMainThread());
|
||||
|
||||
if (!app_paused_) {
|
||||
Log(LogLevel::kWarning,
|
||||
"AppAdapter::ResumeApp() called with app not in paused state.");
|
||||
return;
|
||||
}
|
||||
millisecs_t start_time{core::CorePlatform::GetCurrentMillisecs()};
|
||||
g_core->platform->DebugLog(
|
||||
"ResumeApp@" + std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
||||
assert(app_pause_requested_);
|
||||
app_pause_requested_ = false;
|
||||
UpdatePauseResume_();
|
||||
// assert(app_pause_requested_);
|
||||
// app_pause_requested_ = false;
|
||||
// UpdatePauseResume_();
|
||||
OnAppResume_();
|
||||
if (g_buildconfig.debug_build()) {
|
||||
Log(LogLevel::kDebug,
|
||||
"ResumeApp() completed in "
|
||||
@ -235,21 +295,18 @@ void AppAdapter::ResumeApp() {
|
||||
}
|
||||
}
|
||||
|
||||
void AppAdapter::DidFinishRenderingFrame(FrameDef* frame) {}
|
||||
|
||||
void AppAdapter::PrimeMainThreadEventPump() {
|
||||
assert(!ManagesEventLoop());
|
||||
|
||||
// Need to release the GIL while we're doing this so other thread
|
||||
// can do their Python-y stuff.
|
||||
Python::ScopedInterpreterLockRelease release;
|
||||
|
||||
// Pump events manually until a screen gets created.
|
||||
// At that point we use frame-draws to drive our event loop.
|
||||
while (!g_base->graphics_server->initial_screen_created()) {
|
||||
g_core->main_event_loop()->RunSingleCycle();
|
||||
core::CorePlatform::SleepMillisecs(1);
|
||||
}
|
||||
void AppAdapter::RunMainThreadEventLoopToCompletion() {
|
||||
FatalError("RunMainThreadEventLoopToCompletion is not implemented here.");
|
||||
}
|
||||
|
||||
void AppAdapter::DoExitMainThreadEventLoop() {
|
||||
FatalError("DoExitMainThreadEventLoop is not implemented here.");
|
||||
}
|
||||
|
||||
auto AppAdapter::CanToggleFullscreen() -> bool const { return false; }
|
||||
|
||||
auto AppAdapter::SupportsVSync() -> bool const { return false; }
|
||||
|
||||
auto AppAdapter::SupportsMaxFPS() -> bool const { return false; }
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -3,40 +3,54 @@
|
||||
#ifndef BALLISTICA_BASE_APP_ADAPTER_APP_ADAPTER_H_
|
||||
#define BALLISTICA_BASE_APP_ADAPTER_APP_ADAPTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/shared/generic/lambda_runnable.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
/// Adapts app behavior specific to a particular paradigm and/or api
|
||||
/// environment. For example, 'Headless', 'VROculus', 'SDL', etc. Multiple
|
||||
/// of these may be supported on a single platform, unlike the Platform
|
||||
/// classes where generally there is a single one for the whole platform.
|
||||
/// For example, on Windows, we might have GUI, VR, and Headless
|
||||
/// AppAdapters, but they all might share the same CorePlatform and
|
||||
/// BasePlatform classes.
|
||||
/// environment. For example, 'Headless', 'VROculus', 'SDL', etc. These may
|
||||
/// be mixed & matched with platform classes to define a build. For example,
|
||||
/// on Windows, we might have SDL, VR, and Headless AppAdapters, but they
|
||||
/// all might share the same CorePlatform and BasePlatform classes.
|
||||
class AppAdapter {
|
||||
public:
|
||||
AppAdapter();
|
||||
virtual ~AppAdapter();
|
||||
/// Instantiate the AppAdapter subclass for the current build.
|
||||
static auto Create() -> AppAdapter*;
|
||||
|
||||
/// Called in the main thread when the app is being started.
|
||||
virtual void OnMainThreadStartApp();
|
||||
|
||||
/// Return whether this class runs its own event loop.
|
||||
auto ManagesEventLoop() const -> bool;
|
||||
// Logic thread callbacks.
|
||||
virtual void OnAppStart();
|
||||
virtual void OnAppPause();
|
||||
virtual void OnAppResume();
|
||||
virtual void OnAppShutdown();
|
||||
virtual void OnAppShutdownComplete();
|
||||
virtual void OnScreenSizeChange();
|
||||
virtual void DoApplyAppConfig();
|
||||
|
||||
/// Called for non-event-loop-managing apps to give them an opportunity to
|
||||
/// ensure they are self-sustaining. For instance, an app relying on
|
||||
/// frame-draws for its main thread event processing may need to manually
|
||||
/// pump events until a screen-creation event goes through which should
|
||||
/// keep things running thereafter.
|
||||
virtual void PrimeMainThreadEventPump();
|
||||
/// Return whether this class manages the main thread event loop itself.
|
||||
/// Default is true. If this is true, RunMainThreadEventLoopToCompletion()
|
||||
/// will be called to run the app. This should return false on builds
|
||||
/// where the OS manages the main thread event loop and we just sit in it
|
||||
/// and receive events via callbacks/etc.
|
||||
virtual auto ManagesMainThreadEventLoop() const -> bool;
|
||||
|
||||
/// Handle any pending OS events. On normal graphical builds this is
|
||||
/// triggered by RunRenderUpkeepCycle(); timer intervals for headless
|
||||
/// builds, etc. Should process any pending OS events, etc.
|
||||
virtual void RunEvents();
|
||||
/// When called, the main thread event loop should be run until
|
||||
/// ExitMainThreadEventLoop() is called. This will only be called if
|
||||
/// ManagesMainThreadEventLoop() returns true.
|
||||
virtual void RunMainThreadEventLoopToCompletion();
|
||||
|
||||
/// Called when the main thread event loop should exit. Will only be
|
||||
/// called if ManagesMainThreadEventLoop() returns true.
|
||||
virtual void DoExitMainThreadEventLoop();
|
||||
|
||||
/// Push a call to be run in the app's main thread.
|
||||
template <typename F>
|
||||
void PushMainThreadCall(const F& lambda) {
|
||||
DoPushMainThreadRunnable(NewLambdaRunnableUnmanaged(lambda));
|
||||
}
|
||||
|
||||
/// Put the app into a paused state. Should be called from the main
|
||||
/// thread. Pauses work, closes network sockets, etc. May correspond to
|
||||
@ -53,34 +67,29 @@ class AppAdapter {
|
||||
|
||||
auto app_paused() const { return app_paused_; }
|
||||
|
||||
/// The last time the app was resumed (uses GetAppTimeMillisecs() value).
|
||||
auto last_app_resume_time() const { return last_app_resume_time_; }
|
||||
/// Return whether this AppAdapter supports a 'fullscreen' toggle for its
|
||||
/// display. This currently will simply affect whether that option is
|
||||
/// available in display settings or via a hotkey.
|
||||
virtual auto CanToggleFullscreen() -> bool const;
|
||||
|
||||
/// Attempt to draw a frame.
|
||||
void DrawFrame(bool during_resize = false);
|
||||
/// Return whether this AppAdapter supports vsync controls for its display.
|
||||
virtual auto SupportsVSync() -> bool const;
|
||||
|
||||
/// Gets called when the app config is being applied. Note that this call
|
||||
/// happens in the logic thread, so we should do any reading that needs to
|
||||
/// happen in the logic thread and then forward the values to ourself back
|
||||
/// in our main thread.
|
||||
virtual void LogicThreadDoApplyAppConfig();
|
||||
/// Return whether this AppAdapter supports max-fps controls for its display.
|
||||
virtual auto SupportsMaxFPS() -> bool const;
|
||||
|
||||
/// Used on platforms where our main thread event processing is driven by
|
||||
/// frame-draw commands given to us. This should be called after drawing a
|
||||
/// frame in order to bring game state up to date and process OS events.
|
||||
void RunRenderUpkeepCycle();
|
||||
protected:
|
||||
AppAdapter();
|
||||
virtual ~AppAdapter();
|
||||
|
||||
/// Called by the graphics-server when drawing completes for a frame.
|
||||
virtual void DidFinishRenderingFrame(FrameDef* frame);
|
||||
/// Push a raw pointer Runnable to the platform's 'main' thread. The main
|
||||
/// thread should call its RunAndLogErrors() method and then delete it.
|
||||
virtual void DoPushMainThreadRunnable(Runnable* runnable) = 0;
|
||||
|
||||
private:
|
||||
void UpdatePauseResume_();
|
||||
void OnAppPause_();
|
||||
void OnAppResume_();
|
||||
bool app_pause_requested_{};
|
||||
bool app_paused_{};
|
||||
millisecs_t last_resize_draw_event_time_{};
|
||||
millisecs_t last_app_resume_time_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
25
src/ballistica/base/app_adapter/app_adapter_apple.cc
Normal file
25
src/ballistica/base/app_adapter/app_adapter_apple.cc
Normal file
@ -0,0 +1,25 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
#if BA_XCODE_BUILD
|
||||
|
||||
#include "ballistica/base/app_adapter/app_adapter_apple.h"
|
||||
|
||||
#include <BallisticaKit-Swift.h>
|
||||
|
||||
#include "ballistica/shared/ballistica.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
auto AppAdapterApple::ManagesMainThreadEventLoop() const -> bool {
|
||||
// Nope; we run under a standard Cocoa/UIKit environment and they call us; we
|
||||
// don't call them.
|
||||
return false;
|
||||
}
|
||||
|
||||
void AppAdapterApple::DoPushMainThreadRunnable(Runnable* runnable) {
|
||||
// Kick this along to swift.
|
||||
BallisticaKit::PushRawRunnableToMain(runnable);
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_XCODE_BUILD
|
||||
26
src/ballistica/base/app_adapter/app_adapter_apple.h
Normal file
26
src/ballistica/base/app_adapter/app_adapter_apple.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_APP_ADAPTER_APP_ADAPTER_APPLE_H_
|
||||
#define BALLISTICA_BASE_APP_ADAPTER_APP_ADAPTER_APPLE_H_
|
||||
|
||||
#if BA_XCODE_BUILD
|
||||
|
||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class AppAdapterApple : public AppAdapter {
|
||||
public:
|
||||
auto ManagesMainThreadEventLoop() const -> bool override;
|
||||
|
||||
protected:
|
||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_XCODE_BUILD
|
||||
|
||||
#endif // BALLISTICA_BASE_APP_ADAPTER_APP_ADAPTER_APPLE_H_
|
||||
@ -3,20 +3,41 @@
|
||||
|
||||
#include "ballistica/base/app_adapter/app_adapter_headless.h"
|
||||
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/shared/ballistica.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// We could technically use the vanilla App class here since we're not
|
||||
// changing anything.
|
||||
AppAdapterHeadless::AppAdapterHeadless() {
|
||||
// Handle a few misc things like stress-test updates.
|
||||
// (SDL builds set up a similar timer so we need to also).
|
||||
// This can probably go away at some point.
|
||||
g_core->main_event_loop()->NewTimer(10, true, NewLambdaRunnable([this] {
|
||||
assert(g_base->app_adapter);
|
||||
g_base->app_adapter->RunEvents();
|
||||
}));
|
||||
AppAdapterHeadless::AppAdapterHeadless() {}
|
||||
|
||||
void AppAdapterHeadless::OnMainThreadStartApp() {
|
||||
assert(g_core->InMainThread());
|
||||
|
||||
// We're not embedded into any sort of event system, so we just
|
||||
// spin up our very own event loop for the main thread.
|
||||
main_event_loop_ =
|
||||
new EventLoop(EventLoopID::kMain, ThreadSource::kWrapCurrent);
|
||||
}
|
||||
|
||||
void AppAdapterHeadless::DoApplyAppConfig() {
|
||||
// Normal graphical app-adapters kick off screen creation here
|
||||
// which then leads to remaining app bootstrapping. We create
|
||||
// a 'null' screen purely for the same effect.
|
||||
PushMainThreadCall([] { g_base->graphics_server->SetNullGraphics(); });
|
||||
}
|
||||
|
||||
void AppAdapterHeadless::RunMainThreadEventLoopToCompletion() {
|
||||
assert(g_core->InMainThread());
|
||||
main_event_loop_->RunToCompletion();
|
||||
}
|
||||
|
||||
void AppAdapterHeadless::DoPushMainThreadRunnable(Runnable* runnable) {
|
||||
main_event_loop_->PushRunnable(runnable);
|
||||
}
|
||||
|
||||
void AppAdapterHeadless::DoExitMainThreadEventLoop() {
|
||||
assert(g_core->InMainThread());
|
||||
main_event_loop_->Exit();
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -12,6 +12,18 @@ namespace ballistica::base {
|
||||
class AppAdapterHeadless : public AppAdapter {
|
||||
public:
|
||||
AppAdapterHeadless();
|
||||
|
||||
void OnMainThreadStartApp() override;
|
||||
|
||||
void DoApplyAppConfig() override;
|
||||
|
||||
protected:
|
||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||
void RunMainThreadEventLoopToCompletion() override;
|
||||
void DoExitMainThreadEventLoop() override;
|
||||
|
||||
private:
|
||||
EventLoop* main_event_loop_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
||||
#ifndef BALLISTICA_BASE_APP_ADAPTER_APP_ADAPTER_SDL_H_
|
||||
#define BALLISTICA_BASE_APP_ADAPTER_APP_ADAPTER_SDL_H_
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#if BA_SDL_BUILD
|
||||
|
||||
#include <vector>
|
||||
@ -10,51 +11,83 @@
|
||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||
#include "ballistica/shared/math/vector2f.h"
|
||||
|
||||
// Predeclare for pointers.
|
||||
struct SDL_Window;
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class AppAdapterSDL : public AppAdapter {
|
||||
public:
|
||||
static void InitSDL();
|
||||
AppAdapterSDL();
|
||||
void HandleSDLEvent(const SDL_Event& event);
|
||||
void RunEvents() override;
|
||||
void DidFinishRenderingFrame(FrameDef* frame) override;
|
||||
void SetAutoVSync(bool enable);
|
||||
void OnMainThreadStartApp() override;
|
||||
|
||||
/// Return g_base->app_adapter as an AppAdapterSDL. (assumes it actually is
|
||||
/// one).
|
||||
/// Return g_base->app_adapter as an AppAdapterSDL. (Assumes it actually
|
||||
/// is one).
|
||||
static AppAdapterSDL* Get() {
|
||||
assert(g_base && g_base->app_adapter != nullptr);
|
||||
assert(dynamic_cast<AppAdapterSDL*>(g_base->app_adapter)
|
||||
== static_cast<AppAdapterSDL*>(g_base->app_adapter));
|
||||
return static_cast<AppAdapterSDL*>(g_base->app_adapter);
|
||||
}
|
||||
void SetInitialScreenDimensions(const Vector2f& dimensions);
|
||||
|
||||
AppAdapterSDL();
|
||||
|
||||
void OnMainThreadStartApp() override;
|
||||
void DoApplyAppConfig() override;
|
||||
|
||||
auto CanToggleFullscreen() -> bool const override;
|
||||
auto SupportsVSync() -> bool const override;
|
||||
auto SupportsMaxFPS() -> bool const override;
|
||||
|
||||
protected:
|
||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||
void RunMainThreadEventLoopToCompletion() override;
|
||||
void DoExitMainThreadEventLoop() override;
|
||||
|
||||
private:
|
||||
static void SDLJoystickConnected_(int index);
|
||||
static void SDLJoystickDisconnected_(int index);
|
||||
void SetScreen_(bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
||||
TextureQualityRequest texture_quality_requested,
|
||||
GraphicsQualityRequest graphics_quality_requested);
|
||||
void HandleSDLEvent_(const SDL_Event& event);
|
||||
void UpdateScreenSizes_();
|
||||
void ReloadRenderer_(bool fullscreen,
|
||||
GraphicsQualityRequest graphics_quality_requested,
|
||||
TextureQualityRequest texture_quality_requested);
|
||||
void OnSDLJoystickAdded_(int index);
|
||||
void OnSDLJoystickRemoved_(int index);
|
||||
// Given an SDL joystick ID, returns our Ballistica input for it.
|
||||
auto GetSDLJoystickInput_(int sdl_joystick_id) const -> JoystickInput*;
|
||||
// The same but using sdl events.
|
||||
auto GetSDLJoystickInput_(const SDL_Event* e) const -> JoystickInput*;
|
||||
void DoSwap_();
|
||||
void SwapBuffers_();
|
||||
void UpdateAutoVSync_(int diff);
|
||||
// void DoSwap_();
|
||||
// void SwapBuffers_();
|
||||
// void UpdateAutoVSync_(int diff);
|
||||
void AddSDLInputDevice_(JoystickInput* input, int index);
|
||||
void RemoveSDLInputDevice_(int index);
|
||||
millisecs_t last_swap_time_{};
|
||||
millisecs_t swap_start_time_{};
|
||||
int too_slow_frame_count_{};
|
||||
bool auto_vsync_{};
|
||||
bool vsync_enabled_{true};
|
||||
float average_vsync_fps_{60.0f};
|
||||
int vsync_good_frame_count_{};
|
||||
int vsync_bad_frame_count_{};
|
||||
// millisecs_t last_swap_time_{};
|
||||
// millisecs_t swap_start_time_{};
|
||||
// int too_slow_frame_count_{};
|
||||
// bool auto_vsync_{};
|
||||
// bool vsync_enabled_{true};
|
||||
// float average_vsync_fps_{60.0f};
|
||||
// int vsync_good_frame_count_{};
|
||||
// int vsync_bad_frame_count_{};
|
||||
uint32_t sdl_runnable_event_id_{};
|
||||
std::vector<JoystickInput*> sdl_joysticks_;
|
||||
/// This is in points, not pixels.
|
||||
Vector2f screen_dimensions_{1.0f, 1.0f};
|
||||
Vector2f window_size_{1.0f, 1.0f};
|
||||
SDL_Window* sdl_window_{};
|
||||
void* sdl_gl_context_{};
|
||||
// SDL_Surface* sdl_screen_surface_{};
|
||||
bool done_{};
|
||||
bool fullscreen_{};
|
||||
VSyncRequest vsync_{VSyncRequest::kNever};
|
||||
bool vsync_enabled_{};
|
||||
microsecs_t oversleep{};
|
||||
int max_fps_{60};
|
||||
bool debug_log_sdl_frame_timing_{};
|
||||
// std::unique_ptr<GLContext> gl_context_;
|
||||
|
||||
// TEMP
|
||||
// friend class GLContext;
|
||||
friend class GraphicsServer;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -13,9 +13,11 @@ namespace ballistica::base {
|
||||
|
||||
AppAdapterVR::AppAdapterVR() {}
|
||||
|
||||
auto AppAdapterVR::ManagesMainThreadEventLoop() const -> bool { return false; }
|
||||
|
||||
void AppAdapterVR::PushVRSimpleRemoteStateCall(
|
||||
const VRSimpleRemoteState& state) {
|
||||
g_core->main_event_loop()->PushCall([this, state] {
|
||||
g_base->app_adapter->PushMainThreadCall([this, state] {
|
||||
// Convert this to a full hands state, adding in some simple elbow
|
||||
// positioning of our own and left/right.
|
||||
VRHandsState s;
|
||||
@ -47,16 +49,19 @@ void AppAdapterVR::VRPreDraw() {
|
||||
return;
|
||||
}
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (FrameDef* frame_def = g_base->graphics_server->GetRenderFrameDef()) {
|
||||
// Note: this could be part of PreprocessRenderFrameDef but the non-vr
|
||||
// path needs it to be separate since preprocess doesn't happen
|
||||
// sometimes. Should probably clean that up.
|
||||
g_base->graphics_server->RunFrameDefMeshUpdates(frame_def);
|
||||
// FIXME - this is internal graphics-server details that the render-server
|
||||
// should handle.
|
||||
Log(LogLevel::kWarning, "FIXME: Have GraphicsServer handle VR drawing.");
|
||||
// if (FrameDef* frame_def = g_base->graphics_server->GetRenderFrameDef()) {
|
||||
// // Note: this could be part of PreprocessRenderFrameDef but the non-vr
|
||||
// // path needs it to be separate since preprocess doesn't happen
|
||||
// // sometimes. Should probably clean that up.
|
||||
// g_base->graphics_server->RunFrameDefMeshUpdates(frame_def);
|
||||
|
||||
// store this for the duration of this frame
|
||||
vr_render_frame_def_ = frame_def;
|
||||
g_base->graphics_server->PreprocessRenderFrameDef(frame_def);
|
||||
}
|
||||
// // store this for the duration of this frame
|
||||
// vr_render_frame_def_ = frame_def;
|
||||
// g_base->graphics_server->PreprocessRenderFrameDef(frame_def);
|
||||
// }
|
||||
}
|
||||
|
||||
void AppAdapterVR::VRPostDraw() {
|
||||
@ -69,7 +74,8 @@ void AppAdapterVR::VRPostDraw() {
|
||||
g_base->graphics_server->FinishRenderFrameDef(vr_render_frame_def_);
|
||||
vr_render_frame_def_ = nullptr;
|
||||
}
|
||||
RunRenderUpkeepCycle();
|
||||
Log(LogLevel::kWarning, "WOULD RUN RENDER UPKEEP CYCLE");
|
||||
// RunRenderUpkeepCycle();
|
||||
}
|
||||
|
||||
void AppAdapterVR::VRSetHead(float tx, float ty, float tz, float yaw,
|
||||
@ -118,6 +124,22 @@ void AppAdapterVR::VRDrawEye(int eye, float yaw, float pitch, float roll,
|
||||
}
|
||||
}
|
||||
|
||||
void AppAdapterVR::RunMainThreadEventLoopToCompletion() {
|
||||
// FIXME - can basically copy sdl path here methinks.
|
||||
FatalError(
|
||||
"FIXME: IMPLEMENT AppAdapterVR::RunMainThreadEventLoopToCompletion");
|
||||
// g_core->main_event_loop()->RunToCompletion();
|
||||
}
|
||||
|
||||
void AppAdapterVR::DoPushMainThreadRunnable(Runnable* runnable) {
|
||||
FatalError("FIXME: DoPushMainThreadRunnable unimplemented here.");
|
||||
}
|
||||
|
||||
void AppAdapterVR::DoExitMainThreadEventLoop() {
|
||||
FatalError("FIXME: IMPLEMENT AppAdapterVR::DoExitMainThreadEventLoop");
|
||||
// g_core->main_event_loop()->Exit();
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_VR_BUILD
|
||||
|
||||
@ -19,8 +19,10 @@ class AppAdapterVR : public AppAdapter {
|
||||
float r2 = 0.0f;
|
||||
};
|
||||
|
||||
auto ManagesMainThreadEventLoop() const -> bool override;
|
||||
|
||||
/// Return g_app as a AppAdapterVR. (assumes it actually is one).
|
||||
static auto get() -> AppAdapterVR* {
|
||||
static auto Get() -> AppAdapterVR* {
|
||||
assert(g_base != nullptr && g_base->app_adapter != nullptr);
|
||||
assert(dynamic_cast<AppAdapterVR*>(g_base->app_adapter)
|
||||
== static_cast<AppAdapterVR*>(g_base->app_adapter));
|
||||
@ -39,6 +41,11 @@ class AppAdapterVR : public AppAdapter {
|
||||
float tan_r, float tan_b, float tan_t, float eye_x,
|
||||
float eye_y, float eye_z, int viewport_x, int viewport_y);
|
||||
|
||||
protected:
|
||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||
void RunMainThreadEventLoopToCompletion() override;
|
||||
void DoExitMainThreadEventLoop() override;
|
||||
|
||||
private:
|
||||
FrameDef* vr_render_frame_def_{};
|
||||
};
|
||||
|
||||
@ -19,9 +19,9 @@ const microsecs_t kAppModeMaxHeadlessDisplayStep{500000};
|
||||
const microsecs_t kAppModeMinHeadlessDisplayStep{1000};
|
||||
|
||||
/// Represents 'what the app is doing'. The global app-mode can be switched
|
||||
/// as the app is running. Be aware that, unlike the AppAdapter classes
|
||||
/// which primarily deal with the main thread, most functionality here is
|
||||
/// based in the logic thread.
|
||||
/// as the app is running. The Python layer has its own Python AppMode
|
||||
/// classes, and generally when one of them becomes active it calls down
|
||||
/// to the C++ layer to make a corresponding C++ AppMode class active.
|
||||
class AppMode {
|
||||
public:
|
||||
AppMode();
|
||||
@ -33,13 +33,12 @@ class AppMode {
|
||||
/// Called just before the app-mode ceases being the active one.
|
||||
virtual void OnDeactivate();
|
||||
|
||||
/// Logic thread callbacks that run while the app-mode is active.
|
||||
virtual void OnAppStart();
|
||||
virtual void OnAppPause();
|
||||
virtual void OnAppResume();
|
||||
virtual void OnAppShutdown();
|
||||
virtual void OnAppShutdownComplete();
|
||||
|
||||
/// Apply the app config.
|
||||
virtual void DoApplyAppConfig();
|
||||
|
||||
/// Update the logic thread for a new display-time. Can be called at any
|
||||
|
||||
@ -41,29 +41,29 @@ void AppModeEmpty::DrawWorld(base::FrameDef* frame_def) {
|
||||
}
|
||||
auto& grp(*hello_text_group_);
|
||||
auto* pass = frame_def->overlay_pass();
|
||||
|
||||
SimpleComponent c(pass);
|
||||
c.SetTransparent(true);
|
||||
c.SetColor(0.7f, 0.0f, 1.0f, 1.0f);
|
||||
c.PushTransform();
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
auto xoffs =
|
||||
sinf(static_cast<float>(frame_def->display_time_millisecs()) / 600.0f);
|
||||
auto yoffs =
|
||||
cosf(static_cast<float>(frame_def->display_time_millisecs()) / 600.0f);
|
||||
|
||||
auto xoffs =
|
||||
sinf(static_cast<float>(frame_def->display_time_millisecs()) / 600.0f);
|
||||
auto yoffs =
|
||||
cosf(static_cast<float>(frame_def->display_time_millisecs()) / 600.0f);
|
||||
// Z value -1 will draw us under most everything.
|
||||
c.Translate(pass->virtual_width() * 0.5f - 70.0f + xoffs * 200.0f,
|
||||
pass->virtual_height() * 0.5f - 20.0f + yoffs * 200.0f, -1.0f);
|
||||
c.Scale(2.0, 2.0);
|
||||
|
||||
// Z value -1 will draw us under most everything.
|
||||
c.Translate(pass->virtual_width() * 0.5f - 70.0f + xoffs * 200.0f,
|
||||
pass->virtual_height() * 0.5f - 20.0f + yoffs * 200.0f, -1.0f);
|
||||
c.Scale(2.0, 2.0);
|
||||
|
||||
int text_elem_count = grp.GetElementCount();
|
||||
for (int e = 0; e < text_elem_count; e++) {
|
||||
c.SetTexture(grp.GetElementTexture(e));
|
||||
c.SetFlatness(1.0f);
|
||||
c.DrawMesh(grp.GetElementMesh(e));
|
||||
int text_elem_count = grp.GetElementCount();
|
||||
for (int e = 0; e < text_elem_count; e++) {
|
||||
c.SetTexture(grp.GetElementTexture(e));
|
||||
c.SetFlatness(1.0f);
|
||||
c.DrawMesh(grp.GetElementMesh(e));
|
||||
}
|
||||
}
|
||||
|
||||
c.PopTransform();
|
||||
c.Submit();
|
||||
}
|
||||
|
||||
|
||||
@ -41,6 +41,7 @@ static void rgba8888_unpremultiply_in_place(uint8_t* src, size_t cb) {
|
||||
}
|
||||
|
||||
TextureAsset::TextureAsset() = default;
|
||||
|
||||
TextureAsset::TextureAsset(const std::string& file_in, TextureType type_in,
|
||||
TextureMinQuality min_quality_in)
|
||||
: file_name_(file_in), type_(type_in), min_quality_(min_quality_in) {
|
||||
@ -59,19 +60,19 @@ TextureAsset::TextureAsset(TextPacker* packer) : packer_(packer) {
|
||||
}
|
||||
|
||||
TextureAsset::TextureAsset(const std::string& qr_url) : is_qr_code_(true) {
|
||||
int hard_limit{96};
|
||||
int soft_limit{64};
|
||||
size_t hard_limit{96};
|
||||
size_t soft_limit{64};
|
||||
if (qr_url.size() > hard_limit) {
|
||||
char buffer[512];
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"QR code url byte length %zu exceeds hard-limit of %d;"
|
||||
"QR code url byte length %zu exceeds hard-limit of %zu;"
|
||||
" please use shorter urls. (url=%s)",
|
||||
qr_url.size(), hard_limit, qr_url.c_str());
|
||||
throw Exception(buffer, PyExcType::kValue);
|
||||
} else if (qr_url.size() > soft_limit) {
|
||||
char buffer[512];
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"QR code url byte length %zu exceeds soft-limit of %d;"
|
||||
"QR code url byte length %zu exceeds soft-limit of %zu;"
|
||||
" please use shorter urls. (url=%s)",
|
||||
qr_url.size(), soft_limit, qr_url.c_str());
|
||||
Log(LogLevel::kWarning, buffer);
|
||||
@ -211,15 +212,11 @@ void TextureAsset::DoPreload() {
|
||||
if (file_name_size > 12
|
||||
&& !strcmp(file_name_full_.c_str() + file_name_size - 12,
|
||||
".android_dds")) {
|
||||
#if BA_ENABLE_OPENGL
|
||||
LoadDDS(file_name_full_, preload_datas_[0].buffers,
|
||||
preload_datas_[0].widths, preload_datas_[0].heights,
|
||||
preload_datas_[0].formats, preload_datas_[0].sizes,
|
||||
texture_quality, static_cast<uint8_t>(min_quality_),
|
||||
&preload_datas_[0].base_level);
|
||||
#else
|
||||
throw Exception();
|
||||
#endif
|
||||
|
||||
// We should only be loading this if we support etc1 in hardware.
|
||||
assert(g_base->graphics_server->SupportsTextureCompressionType(
|
||||
@ -238,15 +235,11 @@ void TextureAsset::DoPreload() {
|
||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||
".dds")) {
|
||||
// Dxt1 for non-alpha and dxt5 for alpha (.dds files).
|
||||
#if BA_ENABLE_OPENGL
|
||||
LoadDDS(file_name_full_, preload_datas_[0].buffers,
|
||||
preload_datas_[0].widths, preload_datas_[0].heights,
|
||||
preload_datas_[0].formats, preload_datas_[0].sizes,
|
||||
texture_quality, static_cast<int>(min_quality_),
|
||||
&preload_datas_[0].base_level);
|
||||
#else
|
||||
throw Exception();
|
||||
#endif
|
||||
|
||||
// Decompress dxt1/dxt5 if we don't natively support it.
|
||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
@ -257,15 +250,11 @@ void TextureAsset::DoPreload() {
|
||||
".ktx")) {
|
||||
// Etc2 or etc1 for non-alpha and etc2 for alpha (.ktx files).
|
||||
try {
|
||||
#if BA_ENABLE_OPENGL
|
||||
LoadKTX(file_name_full_, preload_datas_[0].buffers,
|
||||
preload_datas_[0].widths, preload_datas_[0].heights,
|
||||
preload_datas_[0].formats, preload_datas_[0].sizes,
|
||||
texture_quality, static_cast<uint8_t>(min_quality_),
|
||||
&preload_datas_[0].base_level);
|
||||
#else
|
||||
throw Exception();
|
||||
#endif
|
||||
} catch (const std::exception& e) {
|
||||
throw Exception("Error loading file '" + file_name_full_
|
||||
+ "': " + e.what());
|
||||
@ -343,15 +332,11 @@ void TextureAsset::DoPreload() {
|
||||
&& !strcmp(file_name_full_.c_str() + file_name_size - 12,
|
||||
".android_dds")) {
|
||||
try {
|
||||
#if BA_ENABLE_OPENGL
|
||||
LoadDDS(name, preload_datas_[d].buffers, preload_datas_[d].widths,
|
||||
preload_datas_[d].heights, preload_datas_[d].formats,
|
||||
preload_datas_[d].sizes, texture_quality,
|
||||
static_cast<uint8_t>(min_quality_),
|
||||
&preload_datas_[d].base_level);
|
||||
#else
|
||||
throw Exception();
|
||||
#endif
|
||||
} catch (const std::exception& e) {
|
||||
throw Exception("Error loading file '" + file_name_full_
|
||||
+ "': " + e.what());
|
||||
@ -373,16 +358,12 @@ void TextureAsset::DoPreload() {
|
||||
}
|
||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||
".dds")) {
|
||||
#if BA_ENABLE_OPENGL
|
||||
// Dxt1 for non-alpha and dxt5 for alpha (.dds files).
|
||||
LoadDDS(name, preload_datas_[d].buffers, preload_datas_[d].widths,
|
||||
preload_datas_[d].heights, preload_datas_[d].formats,
|
||||
preload_datas_[d].sizes, texture_quality,
|
||||
static_cast<uint8_t>(min_quality_),
|
||||
&preload_datas_[d].base_level);
|
||||
#else
|
||||
throw Exception();
|
||||
#endif
|
||||
|
||||
// Decompress dxt1/dxt5 if we don't natively support it.
|
||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
@ -392,15 +373,11 @@ void TextureAsset::DoPreload() {
|
||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||
".ktx")) {
|
||||
// Etc2 or etc1 for non-alpha and etc2 for alpha (.ktx files)
|
||||
#if BA_ENABLE_OPENGL
|
||||
LoadKTX(name, preload_datas_[d].buffers, preload_datas_[d].widths,
|
||||
preload_datas_[d].heights, preload_datas_[d].formats,
|
||||
preload_datas_[d].sizes, texture_quality,
|
||||
static_cast<uint8_t>(min_quality_),
|
||||
&preload_datas_[d].base_level);
|
||||
#else
|
||||
throw Exception();
|
||||
#endif
|
||||
|
||||
// Decompress etc2 ones if we don't natively support them.
|
||||
if (((preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||
|
||||
@ -12,7 +12,8 @@ namespace ballistica::base {
|
||||
const int kMaxTextureLevels = 14;
|
||||
|
||||
// Temporary data that is passed along to the renderer when creating
|
||||
// rendererdata. This may include sdl surfaces and/or compressed buffers.
|
||||
// renderer-data. This may include things like sdl surfaces and/or
|
||||
// compressed buffers.
|
||||
class TextureAssetPreloadData {
|
||||
public:
|
||||
static void rgba8888_to_rgba4444_in_place(void* src, size_t cb);
|
||||
|
||||
@ -7,8 +7,7 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// Renderer-specific data (gl tex, etc)
|
||||
// this is extended by the renderer
|
||||
// Renderer-specific data (gl tex, etc). To be extended by the renderer.
|
||||
class TextureAssetRendererData : public Object {
|
||||
public:
|
||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
||||
@ -18,9 +17,7 @@ class TextureAssetRendererData : public Object {
|
||||
// Create the renderer data but don't load it in yet.
|
||||
TextureAssetRendererData() = default;
|
||||
|
||||
// load the data.
|
||||
// if incremental is true, return whether the load was completed
|
||||
// (non-incremental loads should always complete)
|
||||
// Load the data.
|
||||
virtual void Load() = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
#if BA_ENABLE_AUDIO
|
||||
|
||||
#if HAVE_FRAMEWORK_OPENAL
|
||||
#if BA_HAVE_FRAMEWORK_OPENAL
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#else
|
||||
|
||||
@ -33,7 +33,9 @@ LPALCDEVICERESUMESOFT alcDeviceResumeSOFT;
|
||||
const int kAudioProcessIntervalNormal{500};
|
||||
const int kAudioProcessIntervalFade{50};
|
||||
const int kAudioProcessIntervalPendingLoad{1};
|
||||
#if (BA_DEBUG_BUILD || BA_TEST_BUILD)
|
||||
const bool kShowInUseSounds{};
|
||||
#endif
|
||||
|
||||
int AudioServer::al_source_count_ = 0;
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ core::CoreFeatureSet* g_core{};
|
||||
BaseFeatureSet* g_base{};
|
||||
|
||||
BaseFeatureSet::BaseFeatureSet()
|
||||
: app_adapter{BasePlatform::CreateAppAdapter()},
|
||||
: app_adapter{AppAdapter::Create()},
|
||||
app_config{new AppConfig()},
|
||||
app_mode_{AppModeEmpty::GetSingleton()},
|
||||
assets{new Assets()},
|
||||
@ -50,7 +50,7 @@ BaseFeatureSet::BaseFeatureSet()
|
||||
bg_dynamics_server{g_core->HeadlessMode() ? nullptr
|
||||
: new BGDynamicsServer},
|
||||
context_ref{new ContextRef(nullptr)},
|
||||
graphics{BasePlatform::CreateGraphics()},
|
||||
graphics{Graphics::Create()},
|
||||
graphics_server{new GraphicsServer()},
|
||||
huffman{new Huffman()},
|
||||
input{new Input()},
|
||||
@ -58,7 +58,7 @@ BaseFeatureSet::BaseFeatureSet()
|
||||
network_reader{new NetworkReader()},
|
||||
network_writer{new NetworkWriter()},
|
||||
networking{new Networking()},
|
||||
platform{BasePlatform::CreatePlatform()},
|
||||
platform{BasePlatform::Create()},
|
||||
python{new BasePython()},
|
||||
stdio_console{g_buildconfig.enable_stdio_console() ? new StdioConsole()
|
||||
: nullptr},
|
||||
@ -223,8 +223,8 @@ void BaseFeatureSet::OnAppShutdownComplete() {
|
||||
g_core->LifecycleLog("app exiting (main thread)");
|
||||
|
||||
// Flag our own event loop to exit (or ask the OS to if they're managing).
|
||||
if (app_adapter->ManagesEventLoop()) {
|
||||
g_core->main_event_loop()->Quit();
|
||||
if (app_adapter->ManagesMainThreadEventLoop()) {
|
||||
app_adapter->DoExitMainThreadEventLoop();
|
||||
} else {
|
||||
platform->TerminateApp();
|
||||
}
|
||||
@ -276,14 +276,14 @@ void BaseFeatureSet::set_app_mode(AppMode* mode) {
|
||||
}
|
||||
}
|
||||
|
||||
auto BaseFeatureSet::AppManagesEventLoop() -> bool {
|
||||
return app_adapter->ManagesEventLoop();
|
||||
auto BaseFeatureSet::AppManagesMainThreadEventLoop() -> bool {
|
||||
return app_adapter->ManagesMainThreadEventLoop();
|
||||
}
|
||||
|
||||
void BaseFeatureSet::RunAppToCompletion() {
|
||||
BA_PRECONDITION(g_core->InMainThread());
|
||||
BA_PRECONDITION(g_base);
|
||||
BA_PRECONDITION(g_base->app_adapter->ManagesEventLoop());
|
||||
BA_PRECONDITION(g_base->app_adapter->ManagesMainThreadEventLoop());
|
||||
BA_PRECONDITION(!called_run_app_to_completion_);
|
||||
called_run_app_to_completion_ = true;
|
||||
|
||||
@ -294,12 +294,12 @@ void BaseFeatureSet::RunAppToCompletion() {
|
||||
// Let go of the GIL while we're running.
|
||||
Python::ScopedInterpreterLockRelease gil_release;
|
||||
|
||||
g_core->main_event_loop()->RunToCompletion();
|
||||
g_base->app_adapter->RunMainThreadEventLoopToCompletion();
|
||||
}
|
||||
|
||||
void BaseFeatureSet::PrimeAppMainThreadEventPump() {
|
||||
app_adapter->PrimeMainThreadEventPump();
|
||||
}
|
||||
// void BaseFeatureSet::PrimeAppMainThreadEventPump() {
|
||||
// app_adapter->PrimeMainThreadEventPump();
|
||||
// }
|
||||
|
||||
auto BaseFeatureSet::HavePlus() -> bool {
|
||||
if (!plus_soft_ && !tried_importing_plus_) {
|
||||
@ -469,10 +469,12 @@ auto BaseFeatureSet::InLogicThread() const -> bool {
|
||||
}
|
||||
|
||||
auto BaseFeatureSet::InGraphicsThread() const -> bool {
|
||||
if (auto* loop = graphics_server->event_loop()) {
|
||||
return loop->ThreadIsCurrent();
|
||||
}
|
||||
return false;
|
||||
// FIXME.
|
||||
return g_core->InMainThread();
|
||||
// if (auto* loop = graphics_server->event_loop()) {
|
||||
// return loop->ThreadIsCurrent();
|
||||
// }
|
||||
// return false;
|
||||
}
|
||||
|
||||
auto BaseFeatureSet::InAudioThread() const -> bool {
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
// It predeclares our feature-set's various types and globals and other
|
||||
// bits.
|
||||
|
||||
// Predeclared types from other feature sets that we use.
|
||||
namespace ballistica::core {
|
||||
class CoreConfig;
|
||||
class CoreFeatureSet;
|
||||
@ -58,7 +57,6 @@ class Context;
|
||||
class ContextRef;
|
||||
class DataAsset;
|
||||
class FrameDef;
|
||||
class GLContext;
|
||||
class Graphics;
|
||||
class GraphicsServer;
|
||||
class Huffman;
|
||||
@ -177,6 +175,8 @@ enum class GraphicsQuality {
|
||||
kHigher,
|
||||
};
|
||||
|
||||
enum class VSyncRequest { kNever, kAlways, kAuto };
|
||||
|
||||
/// Requests for exact or auto graphics quality values.
|
||||
enum class GraphicsQualityRequest {
|
||||
kUnset,
|
||||
@ -624,13 +624,13 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
||||
/// Called when app shutdown process completes. Sets app to exit.
|
||||
void OnAppShutdownComplete();
|
||||
|
||||
auto AppManagesEventLoop() -> bool override;
|
||||
auto AppManagesMainThreadEventLoop() -> bool override;
|
||||
|
||||
/// Run app event loop to completion (only applies to flavors which manage
|
||||
/// their own event loop).
|
||||
void RunAppToCompletion() override;
|
||||
|
||||
void PrimeAppMainThreadEventPump() override;
|
||||
// void PrimeAppMainThreadEventPump() override;
|
||||
|
||||
auto CurrentContext() -> const ContextRef& {
|
||||
assert(InLogicThread()); // Up to caller to ensure this.
|
||||
|
||||
@ -203,7 +203,9 @@ void BGDynamics::Draw(FrameDef* frame_def) {
|
||||
// Draw shadows.
|
||||
if (ds->shadow_vertices.Exists()) {
|
||||
assert(ds->shadow_indices.Exists());
|
||||
if (!shadows_mesh_.Exists()) shadows_mesh_ = Object::New<SpriteMesh>();
|
||||
if (!shadows_mesh_.Exists()) {
|
||||
shadows_mesh_ = Object::New<SpriteMesh>();
|
||||
}
|
||||
shadows_mesh_->SetIndexData(ds->shadow_indices);
|
||||
shadows_mesh_->SetData(
|
||||
Object::Ref<MeshBuffer<VertexSprite>>(ds->shadow_vertices));
|
||||
|
||||
@ -31,46 +31,50 @@ void CollisionCache::Draw(FrameDef* frame_def) {
|
||||
c.SetColor(0, 1, 0, 0.1f);
|
||||
float cell_width = (1.0f / static_cast<float>(grid_width_));
|
||||
float cell_height = (1.0f / static_cast<float>(grid_height_));
|
||||
c.PushTransform();
|
||||
c.Translate((x_min_ + x_max_) * 0.5f, 0, (z_min_ + z_max_) * 0.5f);
|
||||
c.Scale(x_max_ - x_min_, 1, z_max_ - z_min_);
|
||||
c.PushTransform();
|
||||
c.Scale(1, 0.01f, 1);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
c.PopTransform();
|
||||
c.Translate(-0.5f + 0.5f * cell_width, 0, -0.5f + 0.5f * cell_height);
|
||||
for (int x = 0; x < grid_width_; x++) {
|
||||
for (int z = 0; z < grid_height_; z++) {
|
||||
int cell_index = z * grid_width_ + x;
|
||||
assert(cell_index >= 0 && cell_index < static_cast<int>(glow_.size()));
|
||||
if (glow_[cell_index]) {
|
||||
c.SetColor(1, 1, 1, 0.2f);
|
||||
} else {
|
||||
c.SetColor(0, 0, 1, 0.2f);
|
||||
}
|
||||
c.PushTransform();
|
||||
c.Translate(static_cast<float>(x) / static_cast<float>(grid_width_),
|
||||
cells_[cell_index].height_confirmed_collide_,
|
||||
static_cast<float>(z) / static_cast<float>(grid_height_));
|
||||
c.Scale(0.95f * cell_width, 0.01f, 0.95f * cell_height);
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.Translate((x_min_ + x_max_) * 0.5f, 0, (z_min_ + z_max_) * 0.5f);
|
||||
c.Scale(x_max_ - x_min_, 1, z_max_ - z_min_);
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.Scale(1, 0.01f, 1);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
c.PopTransform();
|
||||
if (glow_[cell_index]) {
|
||||
c.SetColor(1, 1, 1, 0.2f);
|
||||
} else {
|
||||
c.SetColor(1, 0, 0, 0.2f);
|
||||
}
|
||||
c.Translate(-0.5f + 0.5f * cell_width, 0, -0.5f + 0.5f * cell_height);
|
||||
for (int x = 0; x < grid_width_; x++) {
|
||||
for (int z = 0; z < grid_height_; z++) {
|
||||
int cell_index = z * grid_width_ + x;
|
||||
assert(cell_index >= 0 && cell_index < static_cast<int>(glow_.size()));
|
||||
if (glow_[cell_index]) {
|
||||
c.SetColor(1, 1, 1, 0.2f);
|
||||
} else {
|
||||
c.SetColor(0, 0, 1, 0.2f);
|
||||
}
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.Translate(static_cast<float>(x) / static_cast<float>(grid_width_),
|
||||
cells_[cell_index].height_confirmed_collide_,
|
||||
static_cast<float>(z) / static_cast<float>(grid_height_));
|
||||
c.Scale(0.95f * cell_width, 0.01f, 0.95f * cell_height);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
}
|
||||
if (glow_[cell_index]) {
|
||||
c.SetColor(1, 1, 1, 0.2f);
|
||||
} else {
|
||||
c.SetColor(1, 0, 0, 0.2f);
|
||||
}
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.Translate(static_cast<float>(x) / static_cast<float>(grid_width_),
|
||||
cells_[cell_index].height_confirmed_empty_,
|
||||
static_cast<float>(z) / static_cast<float>(grid_height_));
|
||||
c.Scale(0.95f * cell_width, 0.01f, 0.95f * cell_height);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
}
|
||||
glow_[cell_index] = 0;
|
||||
}
|
||||
c.PushTransform();
|
||||
c.Translate(static_cast<float>(x) / static_cast<float>(grid_width_),
|
||||
cells_[cell_index].height_confirmed_empty_,
|
||||
static_cast<float>(z) / static_cast<float>(grid_height_));
|
||||
c.Scale(0.95f * cell_width, 0.01f, 0.95f * cell_height);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
c.PopTransform();
|
||||
glow_[cell_index] = 0;
|
||||
}
|
||||
}
|
||||
c.PopTransform();
|
||||
c.Submit();
|
||||
|
||||
if (explicit_bool(false)) {
|
||||
@ -79,47 +83,54 @@ void CollisionCache::Draw(FrameDef* frame_def) {
|
||||
c2.SetColor(1, 0, 0, 1.0f);
|
||||
float cell_width2 = (1.0f / static_cast<float>(grid_width_));
|
||||
float cell_height2 = (1.0f / static_cast<float>(grid_height_));
|
||||
c2.PushTransform();
|
||||
c2.Translate((x_min_ + x_max_) * 0.5f, 0, (z_min_ + z_max_) * 0.5f);
|
||||
c2.Scale(x_max_ - x_min_, 1, z_max_ - z_min_);
|
||||
c2.PushTransform();
|
||||
c2.Scale(1, 0.01f, 1);
|
||||
c2.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
c2.PopTransform();
|
||||
c2.Translate(-0.5f + 0.5f * cell_width2, 0, -0.5f + 0.5f * cell_height2);
|
||||
for (int x = 0; x < grid_width_; x++) {
|
||||
for (int z = 0; z < grid_height_; z++) {
|
||||
int cell_index = z * grid_width_ + x;
|
||||
assert(cell_index >= 0 && cell_index < static_cast<int>(glow_.size()));
|
||||
if (glow_[cell_index]) {
|
||||
c2.SetColor(1, 1, 1, 0.2f);
|
||||
} else {
|
||||
c2.SetColor(1, 0, 0, 0.2f);
|
||||
}
|
||||
c2.PushTransform();
|
||||
c2.Translate(static_cast<float>(x) / static_cast<float>(grid_width_),
|
||||
cells_[cell_index].height_confirmed_empty_,
|
||||
static_cast<float>(z) / static_cast<float>(grid_height_));
|
||||
c2.Scale(0.95f * cell_width2, 0.01f, 0.95f * cell_height2);
|
||||
c2.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
c2.PopTransform();
|
||||
if (glow_[cell_index]) {
|
||||
c2.SetColor(1, 1, 1, 0.2f);
|
||||
} else {
|
||||
c2.SetColor(0, 0, 1, 0.2f);
|
||||
}
|
||||
c2.PushTransform();
|
||||
c2.Translate(static_cast<float>(x) / static_cast<float>(grid_width_),
|
||||
cells_[cell_index].height_confirmed_collide_,
|
||||
static_cast<float>(z) / static_cast<float>(grid_height_));
|
||||
c2.Scale(0.95f * cell_width2, 0.01f, 0.95f * cell_height2);
|
||||
c2.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
c2.PopTransform();
|
||||
{
|
||||
auto xf = c2.ScopedTransform();
|
||||
|
||||
glow_[cell_index] = 0;
|
||||
c2.Translate((x_min_ + x_max_) * 0.5f, 0, (z_min_ + z_max_) * 0.5f);
|
||||
c2.Scale(x_max_ - x_min_, 1, z_max_ - z_min_);
|
||||
{
|
||||
auto xf = c2.ScopedTransform();
|
||||
c2.Scale(1, 0.01f, 1);
|
||||
c2.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
}
|
||||
c2.Translate(-0.5f + 0.5f * cell_width2, 0, -0.5f + 0.5f * cell_height2);
|
||||
for (int x = 0; x < grid_width_; x++) {
|
||||
for (int z = 0; z < grid_height_; z++) {
|
||||
int cell_index = z * grid_width_ + x;
|
||||
assert(cell_index >= 0
|
||||
&& cell_index < static_cast<int>(glow_.size()));
|
||||
if (glow_[cell_index]) {
|
||||
c2.SetColor(1, 1, 1, 0.2f);
|
||||
} else {
|
||||
c2.SetColor(1, 0, 0, 0.2f);
|
||||
}
|
||||
{
|
||||
auto xf = c2.ScopedTransform();
|
||||
c2.Translate(
|
||||
static_cast<float>(x) / static_cast<float>(grid_width_),
|
||||
cells_[cell_index].height_confirmed_empty_,
|
||||
static_cast<float>(z) / static_cast<float>(grid_height_));
|
||||
c2.Scale(0.95f * cell_width2, 0.01f, 0.95f * cell_height2);
|
||||
c2.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
}
|
||||
if (glow_[cell_index]) {
|
||||
c2.SetColor(1, 1, 1, 0.2f);
|
||||
} else {
|
||||
c2.SetColor(0, 0, 1, 0.2f);
|
||||
}
|
||||
{
|
||||
auto xf = c2.ScopedTransform();
|
||||
c2.Translate(
|
||||
static_cast<float>(x) / static_cast<float>(grid_width_),
|
||||
cells_[cell_index].height_confirmed_collide_,
|
||||
static_cast<float>(z) / static_cast<float>(grid_height_));
|
||||
c2.Scale(0.95f * cell_width2, 0.01f, 0.95f * cell_height2);
|
||||
c2.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBox));
|
||||
}
|
||||
glow_[cell_index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
c2.PopTransform();
|
||||
c2.Submit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
void RenderComponent::ScissorPush(const Rect& rIn) {
|
||||
void RenderComponent::ScissorPush(const Rect& rect) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScissorPush);
|
||||
cmd_buffer_->PutFloats(rIn.l, rIn.b, rIn.r, rIn.t);
|
||||
cmd_buffer_->PutFloats(rect.l, rect.b, rect.r, rect.t);
|
||||
}
|
||||
|
||||
#if BA_DEBUG_BUILD
|
||||
|
||||
@ -9,33 +9,86 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
/// RenderComponents are used to assemble command streams to send to the
|
||||
/// renderer. These do a lot of extra work in debug builds to make sure
|
||||
/// valid commands are being constructed, so it is best to iterate on them
|
||||
/// in debug mode when possible.
|
||||
///
|
||||
/// The general workflow with a RenderComponents is to set all 'config'
|
||||
/// options at the beginning and then to issue one or more draw commands
|
||||
/// after. Check the source of each call for EnsureConfiguring() or
|
||||
/// EnsureDrawing() to see which is which. Flipping from configuring to
|
||||
/// drawing can cause shader binding or other work to be done in the
|
||||
/// graphics api, so switches back and forth should be minimized.
|
||||
///
|
||||
/// RenderComponent output goes to a specific draw list in the renderer.
|
||||
/// Depending on the type of RenderPass, there may be a single draw-list,
|
||||
/// transparent and opaque draw-lists, draw-lists for different shaders,
|
||||
/// etc. RenderComponents currently must be sure to only draw to a single
|
||||
/// draw list; otherwise things like PushTransform/PopTransforms may affect
|
||||
/// different draw lists. Stay tuned for this system to evolve into
|
||||
/// something more foolproof.
|
||||
class RenderComponent {
|
||||
public:
|
||||
class ScopedTransformObj {
|
||||
private:
|
||||
class ScopedTransformObj_ {
|
||||
public:
|
||||
explicit ScopedTransformObj(RenderComponent* c) : c_{c} {
|
||||
explicit ScopedTransformObj_(RenderComponent* c) : c_{c} {
|
||||
c_->PushTransform();
|
||||
}
|
||||
~ScopedTransformObj() { c_->PopTransform(); }
|
||||
~ScopedTransformObj_() { c_->PopTransform(); }
|
||||
|
||||
private:
|
||||
RenderComponent* c_;
|
||||
};
|
||||
|
||||
explicit RenderComponent(RenderPass* pass)
|
||||
: state_(State::kConfiguring), pass_(pass), cmd_buffer_(nullptr) {}
|
||||
class ScopedScissorObj_ {
|
||||
public:
|
||||
explicit ScopedScissorObj_(RenderComponent* c, const Rect& r) : c_{c} {
|
||||
c_->ScissorPush(r);
|
||||
}
|
||||
~ScopedScissorObj_() { c_->ScissorPop(); }
|
||||
|
||||
private:
|
||||
RenderComponent* c_;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit RenderComponent(RenderPass* pass) : pass_(pass) {
|
||||
assert(g_base->InLogicThread());
|
||||
}
|
||||
|
||||
~RenderComponent() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
if (state_ != State::kSubmitted) {
|
||||
Log(LogLevel::kError,
|
||||
"RenderComponent dying without submit() having been called.");
|
||||
Submit();
|
||||
}
|
||||
}
|
||||
|
||||
/// End current drawing by this component. This is implicitly done when a
|
||||
/// component goes out of scope, but one may choose to do this explicitly
|
||||
/// to allow other components to draw while this one still exists (only
|
||||
/// one RenderComponent can be actively drawing in a frame-def at a time).
|
||||
void Submit() {
|
||||
if (state_ != State::kSubmitted) {
|
||||
#if BA_DEBUG_BUILD
|
||||
if (state_ == State::kDrawing) {
|
||||
// If we were drawing, let the frame-def know we're done.
|
||||
assert(pass_->frame_def()->active_render_component() == this);
|
||||
pass_->frame_def()->set_active_render_component(nullptr);
|
||||
}
|
||||
#endif
|
||||
state_ = State::kSubmitted;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawMeshAsset(MeshAsset* mesh, uint32_t flags = 0) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kDrawMeshAsset);
|
||||
cmd_buffer_->PutInt(flags);
|
||||
cmd_buffer_->PutMeshAsset(mesh);
|
||||
}
|
||||
|
||||
void DrawMeshAssetInstanced(MeshAsset* mesh,
|
||||
const std::vector<Matrix44f>& matrices,
|
||||
int flags = 0) {
|
||||
@ -47,6 +100,7 @@ class RenderComponent {
|
||||
cmd_buffer_->PutMeshAsset(mesh);
|
||||
cmd_buffer_->PutMatrices(matrices);
|
||||
}
|
||||
|
||||
void DrawMesh(Mesh* m, int flags = 0) {
|
||||
EnsureDrawing();
|
||||
if (m->IsValid()) {
|
||||
@ -56,134 +110,147 @@ class RenderComponent {
|
||||
cmd_buffer_->PutMeshData(m->mesh_data_client_handle()->mesh_data);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawScreenQuad() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kDrawScreenQuad);
|
||||
}
|
||||
// draw triangles using old-school gl format.. only for debugging
|
||||
// and not supported in all configurations
|
||||
|
||||
// Draw triangles using old-school gl format.. only for debugging and not
|
||||
// supported in all configurations.
|
||||
void BeginDebugDrawTriangles() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(
|
||||
RenderCommandBuffer::Command::kBeginDebugDrawTriangles);
|
||||
}
|
||||
|
||||
void BeginDebugDrawLines() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kBeginDebugDrawLines);
|
||||
}
|
||||
|
||||
void Vertex(float x, float y, float z) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kDebugDrawVertex3);
|
||||
cmd_buffer_->PutFloats(x, y, z);
|
||||
}
|
||||
|
||||
void End() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kEndDebugDraw);
|
||||
}
|
||||
void ScissorPush(const Rect& rIn);
|
||||
void ScissorPop() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScissorPop);
|
||||
}
|
||||
|
||||
void PushTransform() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kPushTransform);
|
||||
}
|
||||
|
||||
void PopTransform() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kPopTransform);
|
||||
}
|
||||
auto ScopedTransform() -> ScopedTransformObj {
|
||||
return ScopedTransformObj(this);
|
||||
|
||||
/// Add a transform push/pop to the component. Remember to assign the
|
||||
/// result to a variable or the pop will be immediate.
|
||||
auto ScopedTransform() -> ScopedTransformObj_ {
|
||||
return ScopedTransformObj_(this);
|
||||
}
|
||||
|
||||
/// Add a scissor push/pop to the component. Remember to assign the result
|
||||
/// to a variable or the pop will be immediate.
|
||||
auto ScopedScissor(const Rect& rect) -> ScopedScissorObj_ {
|
||||
return ScopedScissorObj_(this, rect);
|
||||
}
|
||||
|
||||
void Translate(float x, float y) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTranslate2);
|
||||
cmd_buffer_->PutFloats(x, y);
|
||||
}
|
||||
|
||||
void Translate(float x, float y, float z) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTranslate3);
|
||||
cmd_buffer_->PutFloats(x, y, z);
|
||||
}
|
||||
|
||||
void CursorTranslate() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kCursorTranslate);
|
||||
}
|
||||
|
||||
void Rotate(float angle, float x, float y, float z) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kRotate);
|
||||
cmd_buffer_->PutFloats(angle, x, y, z);
|
||||
}
|
||||
|
||||
void Scale(float x, float y) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScale2);
|
||||
cmd_buffer_->PutFloats(x, y);
|
||||
}
|
||||
|
||||
void Scale(float x, float y, float z) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScale3);
|
||||
cmd_buffer_->PutFloats(x, y, z);
|
||||
}
|
||||
|
||||
void ScaleUniform(float s) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScaleUniform);
|
||||
cmd_buffer_->PutFloat(s);
|
||||
}
|
||||
|
||||
void MultMatrix(const float* t) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kMultMatrix);
|
||||
cmd_buffer_->PutFloatArray16(t);
|
||||
}
|
||||
|
||||
#if BA_VR_BUILD
|
||||
void VRTransformToRightHand() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(
|
||||
RenderCommandBuffer::Command::kTransformToRightHand);
|
||||
}
|
||||
|
||||
void VRTransformToLeftHand() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTransformToLeftHand);
|
||||
}
|
||||
|
||||
void VRTransformToHead() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTransformToHead);
|
||||
}
|
||||
#endif // BA_VR_BUILD
|
||||
|
||||
void TranslateToProjectedPoint(float x, float y, float z) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(
|
||||
RenderCommandBuffer::Command::kTranslateToProjectedPoint);
|
||||
cmd_buffer_->PutFloats(x, y, z);
|
||||
}
|
||||
|
||||
void FlipCullFace() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kFlipCullFace);
|
||||
}
|
||||
void Submit() {
|
||||
if (state_ != State::kSubmitted) {
|
||||
// If we were drawing, make note that we're done.
|
||||
if (state_ == State::kDrawing) {
|
||||
#if BA_DEBUG_BUILD
|
||||
assert(pass_->frame_def()->defining_component());
|
||||
pass_->frame_def()->set_defining_component(false);
|
||||
#endif
|
||||
}
|
||||
state_ = State::kSubmitted;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
enum class State { kConfiguring, kDrawing, kSubmitted };
|
||||
void EnsureConfiguring() {
|
||||
if (state_ != State::kConfiguring) {
|
||||
// if we were drawing, make note that we're done
|
||||
#if BA_DEBUG_BUILD
|
||||
// FIXME: currently releasing status as active-render-component here
|
||||
// but should perhaps hold on to it for consistency.
|
||||
if (state_ == State::kDrawing) {
|
||||
assert(pass_->frame_def()->defining_component());
|
||||
pass_->frame_def()->set_defining_component(false);
|
||||
assert(pass_->frame_def()->active_render_component() == this);
|
||||
pass_->frame_def()->set_active_render_component(nullptr);
|
||||
}
|
||||
#endif // BA_DEBUG_BUILD
|
||||
#endif
|
||||
state_ = State::kConfiguring;
|
||||
}
|
||||
}
|
||||
@ -209,33 +276,31 @@ class RenderComponent {
|
||||
// Given a shader type, sets up the config target buffer.
|
||||
void ConfigForShading(ShadingType shading_type) {
|
||||
// Determine which buffer to write to, etc.
|
||||
// Debugging: if we've got transparent-only or opaque-only mode flipped on,
|
||||
// make sure only those type of components are being submitted.
|
||||
|
||||
#if BA_DEBUG_BUILD
|
||||
// Debugging: if we've got transparent-only or opaque-only mode flipped
|
||||
// on, make sure only those type of components are being submitted.
|
||||
ConfigForShadingDebugChecks(shading_type);
|
||||
// Also make sure only transparent stuff is going into the
|
||||
// light/shadow/overlay3D passes (we skip rendering the opaque lists there
|
||||
// since there shouldn't be anything in them, and we're not using depth
|
||||
// for those so it wouldn't be much of an optimization..)
|
||||
// light/shadow/overlay3D passes (we skip rendering the opaque lists
|
||||
// there since there shouldn't be anything in them, and we're not using
|
||||
// depth for those so it wouldn't be much of an optimization).
|
||||
if ((pass_->type() == RenderPass::Type::kLightPass
|
||||
|| pass_->type() == RenderPass::Type::kLightShadowPass
|
||||
|| pass_->type() == RenderPass::Type::kOverlay3DPass)
|
||||
&& !Graphics::IsShaderTransparent(shading_type)) {
|
||||
throw Exception(
|
||||
"Opaque component submitted to light/shadow/overlay3d pass;"
|
||||
" not cool man.");
|
||||
FatalError("Opaque component submitted to light/shadow/overlay3d pass.");
|
||||
}
|
||||
|
||||
// Likewise the blit pass should consist solely of opaque stuff.
|
||||
if (pass_->type() == RenderPass::Type::kBlitPass
|
||||
&& Graphics::IsShaderTransparent(shading_type)) {
|
||||
throw Exception(
|
||||
"Transparent component submitted to blit pass;"
|
||||
" not cool man.");
|
||||
FatalError("Transparent component submitted to blit pass.");
|
||||
}
|
||||
#endif // BA_DEBUG_BUILD
|
||||
// Certain passes (overlay, etc) draw objects in the order
|
||||
// provided. Other passes group by shader for efficiency.
|
||||
|
||||
// Certain passes (overlay, etc) draw objects in the order provided.
|
||||
// Other passes group by shader for efficiency.
|
||||
if (pass_->UsesWorldLists()) {
|
||||
cmd_buffer_ = pass_->GetCommands(shading_type);
|
||||
} else {
|
||||
@ -255,21 +320,28 @@ class RenderComponent {
|
||||
if (state_ != State::kDrawing) {
|
||||
WriteConfig();
|
||||
state_ = State::kDrawing;
|
||||
// make sure we're the only one drawing until we're submitted
|
||||
#if BA_DEBUG_BUILD
|
||||
assert(!pass_->frame_def()->defining_component());
|
||||
pass_->frame_def()->set_defining_component(true);
|
||||
#endif // BA_DEBUG_BUILD
|
||||
// Let the frame-def know we're the active component drawing to it now.
|
||||
assert(pass_->frame_def()->active_render_component() == nullptr);
|
||||
pass_->frame_def()->set_active_render_component(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// subclasses should override this to dump
|
||||
// their needed data to the stream
|
||||
// Subclasses should override this to dump their needed data to the
|
||||
// stream.
|
||||
virtual void WriteConfig() = 0;
|
||||
|
||||
protected:
|
||||
RenderCommandBuffer* cmd_buffer_;
|
||||
State state_;
|
||||
RenderCommandBuffer* cmd_buffer_{};
|
||||
State state_{State::kConfiguring};
|
||||
RenderPass* pass_;
|
||||
|
||||
public:
|
||||
void ScissorPush(const Rect& rect);
|
||||
|
||||
void ScissorPop() {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScissorPop);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
namespace ballistica::base {
|
||||
|
||||
void SimpleComponent::WriteConfig() {
|
||||
// if we're transparent we don't want to do optimization-based
|
||||
// shader swapping (ie: when color is 1). This is because it can
|
||||
// affect draw order, which is important unlike with opaque stuff.
|
||||
// If we're transparent, we don't want to do optimization-based shader
|
||||
// swapping (ie: when color is 1). This is because it can affect draw
|
||||
// order, which is important unlike with opaque stuff.
|
||||
if (transparent_) {
|
||||
if (texture_.Exists()) {
|
||||
if (colorize_texture_.Exists()) {
|
||||
@ -52,7 +52,7 @@ void SimpleComponent::WriteConfig() {
|
||||
cmd_buffer_->PutTexture(colorize_texture_);
|
||||
}
|
||||
} else {
|
||||
// non-colorized with texture
|
||||
// Non-colorized with texture.
|
||||
if (double_sided_) {
|
||||
assert(!mask_texture_.Exists()); // unimplemented combo
|
||||
assert(flatness_ == 0.0f); // unimplemented combo
|
||||
@ -111,7 +111,7 @@ void SimpleComponent::WriteConfig() {
|
||||
}
|
||||
} else {
|
||||
if (flatness_ != 0.0f) {
|
||||
assert(!mask_texture_.Exists()); // unimplemented
|
||||
assert(!mask_texture_.Exists()); // unimplemented combo
|
||||
ConfigForShading(
|
||||
ShadingType::kSimpleTextureModulatedTransFlatness);
|
||||
cmd_buffer_->PutInt(premultiplied_);
|
||||
@ -120,8 +120,8 @@ void SimpleComponent::WriteConfig() {
|
||||
cmd_buffer_->PutTexture(texture_);
|
||||
} else {
|
||||
if (mask_texture_.Exists()) {
|
||||
// currently mask functionality requires colorize too, so
|
||||
// just send a black texture for that..
|
||||
// Currently mask functionality requires colorize too, so
|
||||
// just send a black texture for that.
|
||||
ConfigForShading(
|
||||
ShadingType::
|
||||
kSimpleTextureModulatedTransparentColorized2Masked);
|
||||
@ -165,12 +165,12 @@ void SimpleComponent::WriteConfig() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// when we're opaque we can do some shader-swapping optimizations
|
||||
// When we're opaque, we can do some shader-swapping optimizations
|
||||
// since draw order doesn't matter.
|
||||
assert(flatness_ == 0.0f); // unimplemented combo
|
||||
assert(glow_amount_ == 0.0f); // unimplemented combo
|
||||
assert(shadow_opacity_ == 0.0f); // unimplemented combo
|
||||
assert(!double_sided_); // not implemented
|
||||
assert(!double_sided_); // unimplemented combo
|
||||
assert(!mask_uv2_texture_.Exists()); // unimplemented combo
|
||||
if (texture_.Exists()) {
|
||||
if (colorize_texture_.Exists()) {
|
||||
@ -194,8 +194,8 @@ void SimpleComponent::WriteConfig() {
|
||||
} else {
|
||||
assert(!do_colorize_2_); // unsupported combo
|
||||
if (mask_texture_.Exists()) {
|
||||
// currently mask functionality requires colorize too, so
|
||||
// we have to send a black texture along for that..
|
||||
// Currently mask functionality requires colorize too, so
|
||||
// we have to send a black texture along for that.
|
||||
ConfigForShading(
|
||||
ShadingType::kSimpleTextureModulatedColorized2Masked);
|
||||
cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_,
|
||||
@ -207,7 +207,7 @@ void SimpleComponent::WriteConfig() {
|
||||
g_base->assets->SysTexture(SysTextureID::kBlack));
|
||||
cmd_buffer_->PutTexture(mask_texture_);
|
||||
} else {
|
||||
// if no color was provided we can do a super-cheap version
|
||||
// If no color was provided, we can do a super-cheap version.
|
||||
if (!have_color_) {
|
||||
ConfigForShading(ShadingType::kSimpleTexture);
|
||||
cmd_buffer_->PutTexture(texture_);
|
||||
|
||||
@ -36,18 +36,22 @@ class SimpleComponent : public RenderComponent {
|
||||
have_color_(false),
|
||||
double_sided_(false),
|
||||
do_colorize_2_(false) {}
|
||||
|
||||
void SetPremultiplied(bool val) {
|
||||
EnsureConfiguring();
|
||||
premultiplied_ = val;
|
||||
}
|
||||
|
||||
void SetTransparent(bool val) {
|
||||
EnsureConfiguring();
|
||||
transparent_ = val;
|
||||
}
|
||||
|
||||
void SetTexture(TextureAsset* t) {
|
||||
EnsureConfiguring();
|
||||
texture_ = t;
|
||||
}
|
||||
|
||||
void SetTexture(const Object::Ref<TextureAsset>& t) {
|
||||
EnsureConfiguring();
|
||||
texture_ = t;
|
||||
@ -59,31 +63,36 @@ class SimpleComponent : public RenderComponent {
|
||||
EnsureConfiguring();
|
||||
colorize_texture_ = t;
|
||||
}
|
||||
// red multiplies source color, green adds colorize1-color,
|
||||
// and blue adds white
|
||||
// (currently requires colorize1 and colorize 2 to be set)
|
||||
|
||||
// Red multiplies source color, green adds colorize1-color, and blue adds
|
||||
// white (currently requires colorize1 and colorize 2 to be set).
|
||||
void SetMaskTexture(TextureAsset* t) {
|
||||
EnsureConfiguring();
|
||||
mask_texture_ = t;
|
||||
}
|
||||
|
||||
void SetMaskUV2Texture(TextureAsset* t) {
|
||||
EnsureConfiguring();
|
||||
mask_uv2_texture_ = t;
|
||||
}
|
||||
|
||||
void ClearMaskUV2Texture() {
|
||||
EnsureConfiguring();
|
||||
mask_uv2_texture_.Clear();
|
||||
}
|
||||
|
||||
void SetDoubleSided(bool enable) {
|
||||
EnsureConfiguring();
|
||||
double_sided_ = enable;
|
||||
}
|
||||
|
||||
void SetColor(float r, float g, float b, float a = 1.0f) {
|
||||
// we support fast inline color changes with drawing streams
|
||||
// (avoids having to re-send a whole configure for every color change)
|
||||
// ..make sure to only allow this if we have a color already; otherwise we
|
||||
// We support fast inline color changes with drawing streams (avoids
|
||||
// having to re-send a whole configure for every color change).
|
||||
|
||||
// Make sure to only allow this if we have a color already; otherwise we
|
||||
// need to config since we might be implicitly switch shaders by setting
|
||||
// color
|
||||
// color.
|
||||
if (state_ == State::kDrawing && have_color_) {
|
||||
cmd_buffer_->PutCommand(
|
||||
RenderCommandBuffer::Command::kSimpleComponentInlineColor);
|
||||
@ -97,6 +106,7 @@ class SimpleComponent : public RenderComponent {
|
||||
color_b_ = b;
|
||||
color_a_ = a;
|
||||
}
|
||||
|
||||
void SetColorizeColor(float r, float g, float b, float a = 1.0f) {
|
||||
EnsureConfiguring();
|
||||
colorize_color_r_ = r;
|
||||
@ -104,6 +114,7 @@ class SimpleComponent : public RenderComponent {
|
||||
colorize_color_b_ = b;
|
||||
colorize_color_a_ = a;
|
||||
}
|
||||
|
||||
void SetColorizeColor2(float r, float g, float b, float a = 1.0f) {
|
||||
EnsureConfiguring();
|
||||
colorize_color2_r_ = r;
|
||||
@ -112,6 +123,7 @@ class SimpleComponent : public RenderComponent {
|
||||
colorize_color2_a_ = a;
|
||||
do_colorize_2_ = true;
|
||||
}
|
||||
|
||||
void SetShadow(float offsetX, float offsetY, float blur, float opacity) {
|
||||
EnsureConfiguring();
|
||||
shadow_offset_x_ = offsetX;
|
||||
@ -119,11 +131,13 @@ class SimpleComponent : public RenderComponent {
|
||||
shadow_blur_ = blur;
|
||||
shadow_opacity_ = opacity;
|
||||
}
|
||||
void setGlow(float amount, float blur) {
|
||||
|
||||
void SetGlow(float amount, float blur) {
|
||||
EnsureConfiguring();
|
||||
glow_amount_ = amount;
|
||||
glow_blur_ = blur;
|
||||
}
|
||||
|
||||
void SetFlatness(float flatness) {
|
||||
EnsureConfiguring();
|
||||
flatness_ = flatness;
|
||||
|
||||
334
src/ballistica/base/graphics/gl/framebuffer_object_gl.h
Normal file
334
src/ballistica/base/graphics/gl/framebuffer_object_gl.h
Normal file
@ -0,0 +1,334 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_FRAMEBUFFER_OBJECT_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_FRAMEBUFFER_OBJECT_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::FramebufferObjectGL : public Framebuffer {
|
||||
public:
|
||||
FramebufferObjectGL(RendererGL* renderer_in, int width_in, int height_in,
|
||||
bool linear_interp_in, bool depth_in, bool is_texture_in,
|
||||
bool depth_is_texture_in, bool high_quality_in,
|
||||
bool msaa_in, bool alpha_in)
|
||||
: width_(width_in),
|
||||
height_(height_in),
|
||||
linear_interp_(linear_interp_in),
|
||||
depth_(depth_in),
|
||||
is_texture_(is_texture_in),
|
||||
depth_is_texture_(depth_is_texture_in),
|
||||
renderer_(renderer_in),
|
||||
high_quality_(high_quality_in),
|
||||
msaa_(msaa_in),
|
||||
alpha_(alpha_in) {
|
||||
// Desktop stuff is always high-quality.
|
||||
#if BA_OSTYPE_MACOS || BA_OSTYPE_LINUX || BA_OSTYPE_WINDOWS
|
||||
high_quality_ = true;
|
||||
#endif
|
||||
|
||||
// Things are finally getting to the point where we can default to
|
||||
// desktop quality on some mobile stuff.
|
||||
#if BA_OSTYPE_ANDROID
|
||||
if (renderer_->is_tegra_k1_) {
|
||||
high_quality_ = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
~FramebufferObjectGL() override { Unload(); }
|
||||
|
||||
void Load(bool force_low_quality = false) {
|
||||
if (loaded_) return;
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
GLenum status;
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
glGenFramebuffers(1, &framebuffer_);
|
||||
renderer_->BindFramebuffer(framebuffer_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
bool do_high_quality = high_quality_;
|
||||
if (force_low_quality) do_high_quality = false;
|
||||
int samples = 0;
|
||||
if (msaa_) {
|
||||
// Can't multisample with texture buffers currently.
|
||||
assert(!is_texture_ && !depth_is_texture_);
|
||||
|
||||
int target_samples =
|
||||
renderer_->GetMSAASamplesForFramebuffer_(width_, height_);
|
||||
|
||||
if (do_high_quality) {
|
||||
samples = std::min(target_samples, renderer_->msaa_max_samples_rgb8());
|
||||
} else {
|
||||
samples =
|
||||
std::min(target_samples, renderer_->msaa_max_samples_rgb565());
|
||||
}
|
||||
}
|
||||
if (is_texture_) {
|
||||
// Attach a texture for the color target.
|
||||
glGenTextures(1, &texture_);
|
||||
renderer_->BindTexture_(GL_TEXTURE_2D, texture_);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
linear_interp_ ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
linear_interp_ ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// On android/ios lets go with 16 bit unless they explicitly request
|
||||
// high quality.
|
||||
#if BA_OSTYPE_ANDROID || BA_OSTYPE_IOS_TVOS
|
||||
GLenum format;
|
||||
if (alpha_) {
|
||||
format = do_high_quality ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
} else {
|
||||
format = do_high_quality ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5;
|
||||
}
|
||||
#else
|
||||
GLenum format = GL_UNSIGNED_BYTE;
|
||||
#endif
|
||||
// if (srgbTest) {
|
||||
// glTexImage2D(GL_TEXTURE_2D, 0, alpha_?GL_SRGB8_ALPHA8:GL_SRGB8,
|
||||
// _width, _height, 0, alpha_?GL_RGBA:GL_RGB, format, nullptr);
|
||||
// } else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, alpha_ ? GL_RGBA : GL_RGB, width_, height_,
|
||||
0, alpha_ ? GL_RGBA : GL_RGB, format, nullptr);
|
||||
// }
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, texture_, 0);
|
||||
} else {
|
||||
// Regular renderbuffer.
|
||||
assert(!alpha_); // fixme
|
||||
#if BA_OSTYPE_IOS_TVOS
|
||||
GLenum format =
|
||||
GL_RGB565; // FIXME; need to pull ES3 headers in for GL_RGB8
|
||||
#elif BA_OSTYPE_ANDROID
|
||||
GLenum format = do_high_quality ? GL_RGB8 : GL_RGB565;
|
||||
#else
|
||||
GLenum format = GL_RGB8;
|
||||
#endif
|
||||
glGenRenderbuffers(1, &render_buffer_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, render_buffer_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
if (samples > 0) {
|
||||
#if BA_OSTYPE_IOS_TVOS
|
||||
throw Exception();
|
||||
#else
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, format,
|
||||
width_, height_);
|
||||
#endif
|
||||
} else {
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, format, width_, height_);
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, render_buffer_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
if (depth_) {
|
||||
if (depth_is_texture_) {
|
||||
glGenTextures(1, &depth_texture_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
renderer_->BindTexture_(GL_TEXTURE_2D, depth_texture_);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
// FIXME: need to pull in ES3 stuff for iOS to get GL_DEPTH_COMPONENT24.
|
||||
// #if BA_OSTYPE_IOS_TVOS
|
||||
// glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_,
|
||||
// height_, 0,
|
||||
// GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr);
|
||||
// #else
|
||||
if (do_high_quality) {
|
||||
// #if BA_OSTYPE_ANDROID
|
||||
// assert(g_running_es3);
|
||||
// #endif // BA_OSTYPE_ANDROID
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width_, height_,
|
||||
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
} else {
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D, 0,
|
||||
renderer_->gl_is_es() ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
|
||||
width_, height_, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT,
|
||||
nullptr);
|
||||
}
|
||||
// #endif // BA_OSTYPE_IOS_TVOS
|
||||
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
||||
GL_TEXTURE_2D, depth_texture_, 0);
|
||||
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
} else {
|
||||
// Just use a plain old renderbuffer if we don't need it as a texture
|
||||
// (this is more widely supported).
|
||||
glGenRenderbuffers(1, &depth_render_buffer_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth_render_buffer_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (samples > 0) {
|
||||
// #if BA_OSTYPE_IOS_TVOS
|
||||
// throw Exception();
|
||||
// #else
|
||||
// (GL_DEPTH_COMPONENT24 not available in ES2 it looks like)
|
||||
bool do24;
|
||||
// #if BA_OSTYPE_ANDROID
|
||||
// do24 = (do_high_quality && g_running_es3);
|
||||
// #else
|
||||
do24 = do_high_quality;
|
||||
// #endif
|
||||
|
||||
glRenderbufferStorageMultisample(
|
||||
GL_RENDERBUFFER, samples,
|
||||
do24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, width_,
|
||||
height_);
|
||||
// (do_high_quality &&
|
||||
// g_running_es3)?GL_DEPTH_COMPONENT24:GL_DEPTH_COMPONENT16, _width,
|
||||
// _height);
|
||||
// #endif
|
||||
} else {
|
||||
// FIXME - need to pull in es3 headers to get GL_DEPTH_COMPONENT24 on
|
||||
// iOS
|
||||
// #if BA_OSTYPE_IOS_TVOS
|
||||
// GLenum format = GL_DEPTH_COMPONENT16;
|
||||
// #else
|
||||
// GL_DEPTH_COMPONENT24 not available in ES2 it looks like.
|
||||
GLenum format = (do_high_quality && renderer_->gl_is_es())
|
||||
? GL_DEPTH_COMPONENT24
|
||||
: GL_DEPTH_COMPONENT16;
|
||||
// #endif
|
||||
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, format, width_, height_);
|
||||
}
|
||||
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
||||
GL_RENDERBUFFER, depth_render_buffer_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
const char* version = (const char*)glGetString(GL_VERSION);
|
||||
const char* vendor = (const char*)glGetString(GL_VENDOR);
|
||||
const char* renderer = (const char*)glGetString(GL_RENDERER);
|
||||
throw Exception(
|
||||
"Framebuffer setup failed for " + std::to_string(width_) + " by "
|
||||
+ std::to_string(height_) + " fb with depth " + std::to_string(depth_)
|
||||
+ " asTex " + std::to_string(depth_is_texture_) + " gl-version "
|
||||
+ version + " vendor " + vendor + " renderer " + renderer);
|
||||
}
|
||||
// GLint enc;
|
||||
// glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
|
||||
// GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &enc); if
|
||||
// (enc == GL_SRGB) {
|
||||
// Log(LogLevel::kInfo, "GOT SRGB!!!!!!!!!!!");
|
||||
// } else if (enc == GL_LINEAR) {
|
||||
// Log(LogLevel::kInfo, "GOT LINEAR...");
|
||||
// } else {
|
||||
// Log(LogLevel::kInfo, "GOT OTHER..");
|
||||
// }
|
||||
loaded_ = true;
|
||||
}
|
||||
|
||||
void Unload() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (!loaded_) return;
|
||||
|
||||
// If our textures are currently bound as anything, clear that out.
|
||||
// (otherwise a new texture with that same ID won't be bindable)
|
||||
for (int& i : renderer_->bound_textures_2d_) {
|
||||
if (i == texture_) { // NOLINT(bugprone-branch-clone)
|
||||
i = -1;
|
||||
} else if (depth_ && (i == depth_texture_)) {
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_base->graphics_server->renderer_context_lost()) {
|
||||
// Tear down the FBO and texture attachment
|
||||
if (is_texture_) {
|
||||
glDeleteTextures(1, &texture_);
|
||||
} else {
|
||||
glDeleteRenderbuffers(1, &render_buffer_);
|
||||
}
|
||||
if (depth_) {
|
||||
if (depth_is_texture_) {
|
||||
glDeleteTextures(1, &depth_texture_);
|
||||
} else {
|
||||
glDeleteRenderbuffers(1, &depth_render_buffer_);
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
// If this one is current, make sure we re-bind next time.
|
||||
// (otherwise we might prevent a new framebuffer with a recycled id from
|
||||
// binding)
|
||||
if (renderer_->active_framebuffer_ == framebuffer_) {
|
||||
renderer_->active_framebuffer_ = -1;
|
||||
}
|
||||
glDeleteFramebuffers(1, &framebuffer_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
loaded_ = false;
|
||||
}
|
||||
|
||||
void Bind() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
renderer_->BindFramebuffer(framebuffer_);
|
||||
// if (time(nullptr)%2 == 0) {
|
||||
// glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
// }
|
||||
}
|
||||
|
||||
auto texture() const -> GLuint {
|
||||
assert(is_texture_);
|
||||
return texture_;
|
||||
}
|
||||
|
||||
auto depth_texture() const -> GLuint {
|
||||
assert(depth_ && depth_is_texture_);
|
||||
return depth_texture_;
|
||||
}
|
||||
|
||||
auto width() const -> int { return width_; }
|
||||
auto height() const -> int { return height_; }
|
||||
auto id() const -> GLuint { return framebuffer_; }
|
||||
|
||||
private:
|
||||
RendererGL* renderer_{};
|
||||
bool depth_{};
|
||||
bool is_texture_{};
|
||||
bool depth_is_texture_{};
|
||||
bool high_quality_{};
|
||||
bool msaa_{};
|
||||
bool alpha_{};
|
||||
bool linear_interp_{};
|
||||
bool loaded_{};
|
||||
int width_{}, height_{};
|
||||
GLuint framebuffer_{};
|
||||
GLuint texture_{};
|
||||
GLuint depth_texture_{};
|
||||
GLuint render_buffer_{};
|
||||
GLuint depth_render_buffer_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_FRAMEBUFFER_OBJECT_GL_H_
|
||||
@ -3,364 +3,58 @@
|
||||
#if BA_ENABLE_OPENGL
|
||||
#include "ballistica/base/graphics/gl/gl_sys.h"
|
||||
|
||||
#include "ballistica/base/app_adapter/app_adapter_sdl.h"
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/core/core.h"
|
||||
#include "ballistica/shared/ballistica.h"
|
||||
|
||||
#if BA_OSTYPE_ANDROID
|
||||
#include <EGL/egl.h>
|
||||
#if !BA_USE_ES3_INCLUDES
|
||||
#include "ballistica/core/platform/android/android_gl3.h"
|
||||
#endif
|
||||
#endif
|
||||
// #include "ballistica/base/app_adapter/app_adapter_sdl.h"
|
||||
// #include "ballistica/base/base.h"
|
||||
// #include "ballistica/core/core.h"
|
||||
|
||||
#if BA_OSTYPE_WINDOWS
|
||||
#pragma comment(lib, "opengl32.lib")
|
||||
#pragma comment(lib, "glu32.lib")
|
||||
#endif
|
||||
// #if BA_OSTYPE_ANDROID
|
||||
// #include <EGL/egl.h>
|
||||
// #if !BA_USE_ES3_INCLUDES
|
||||
// #include "ballistica/core/platform/android/android_gl3.h"
|
||||
// #endif
|
||||
// #endif
|
||||
|
||||
#if BA_OSTYPE_MACOS
|
||||
#include <OpenGL/CGLContext.h>
|
||||
#include <OpenGL/CGLTypes.h>
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#endif
|
||||
// #if BA_OSTYPE_MACOS
|
||||
// #include <OpenGL/CGLContext.h>
|
||||
// #include <OpenGL/CGLTypes.h>
|
||||
// #include <OpenGL/OpenGL.h>
|
||||
// #endif
|
||||
|
||||
#if BA_DEBUG_BUILD
|
||||
#define DEBUG_CHECK_GL_ERROR \
|
||||
{ \
|
||||
GLenum err = glGetError(); \
|
||||
if (err != GL_NO_ERROR) \
|
||||
Log(LogLevel::kError, "OPENGL ERROR AT LINE " + std::to_string(__LINE__) \
|
||||
+ ": " + GLErrorToString(err)); \
|
||||
}
|
||||
#else
|
||||
#define DEBUG_CHECK_GL_ERROR
|
||||
#endif
|
||||
// #if BA_OSTYPE_IOS
|
||||
// void (*glInvalidateFramebuffer)(GLenum target, GLsizei num_attachments,
|
||||
// const GLenum* attachments) = nullptr;
|
||||
// #endif
|
||||
|
||||
#if BA_OSTYPE_ANDROID
|
||||
PFNGLDISCARDFRAMEBUFFEREXTPROC _glDiscardFramebufferEXT = nullptr;
|
||||
#endif
|
||||
|
||||
#if BA_OSTYPE_WINDOWS
|
||||
PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ = nullptr;
|
||||
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC
|
||||
glGetFramebufferAttachmentParameteriv = nullptr;
|
||||
PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = nullptr;
|
||||
PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr;
|
||||
PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = nullptr;
|
||||
PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = nullptr;
|
||||
PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = nullptr;
|
||||
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr;
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
|
||||
PFNGLCREATESHADERPROC glCreateShader = nullptr;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
|
||||
PFNGLGETINFOLOGARBPROC glGetInfoLogARB = nullptr;
|
||||
PFNGLATTACHSHADERPROC glAttachShader = nullptr;
|
||||
PFNGLUSEPROGRAMOBJECTARBPROC glUseProgram = nullptr;
|
||||
PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr;
|
||||
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr;
|
||||
PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = nullptr;
|
||||
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
|
||||
PFNGLUNIFORM1IPROC glUniform1i = nullptr;
|
||||
PFNGLUNIFORM1FPROC glUniform1f = nullptr;
|
||||
PFNGLUNIFORM1FVPROC glUniform1fv = nullptr;
|
||||
PFNGLUNIFORM2FPROC glUniform2f = nullptr;
|
||||
PFNGLUNIFORM3FPROC glUniform3f = nullptr;
|
||||
PFNGLUNIFORM4FPROC glUniform4f = nullptr;
|
||||
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr;
|
||||
PFNGLGENBUFFERSPROC glGenBuffers = nullptr;
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr;
|
||||
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr;
|
||||
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr;
|
||||
PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
|
||||
PFNGLBUFFERDATAPROC glBufferData = nullptr;
|
||||
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr;
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample =
|
||||
nullptr;
|
||||
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr;
|
||||
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr;
|
||||
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr;
|
||||
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
|
||||
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = nullptr;
|
||||
PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fv = nullptr;
|
||||
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = nullptr;
|
||||
PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D = nullptr;
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv = nullptr;
|
||||
PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;
|
||||
PFNGLDELETESHADERPROC glDeleteShader = nullptr;
|
||||
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr;
|
||||
PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr;
|
||||
PFNGLDETACHSHADERPROC glDetachShader = nullptr;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;
|
||||
#endif // BA_OSTYPE_WINDOWS
|
||||
// #if BA_OSTYPE_ANDROID
|
||||
// PFNGLDISCARDFRAMEBUFFEREXTPROC _glDiscardFramebufferEXT = nullptr;
|
||||
// #endif
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "hicpp-signed-bitwise"
|
||||
#pragma ide diagnostic ignored "EmptyDeclOrStmt"
|
||||
bool g_sys_gl_inited{};
|
||||
|
||||
GLContext::GLContext(int target_res_x, int target_res_y, bool fullscreen)
|
||||
: fullscreen_(fullscreen) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
bool need_window = true;
|
||||
#if BA_RIFT_BUILD
|
||||
// on the rift build we don't need a window when running in vr mode; we just
|
||||
// use the context we're created into...
|
||||
if (g_core->IsVRMode()) {
|
||||
need_window = false;
|
||||
}
|
||||
#endif // BA_RIFT_BUILD
|
||||
if (explicit_bool(need_window)) {
|
||||
#if BA_SDL2_BUILD
|
||||
#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
int flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS;
|
||||
#else
|
||||
// Things are a bit more varied on desktop..
|
||||
uint32_t flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
||||
| SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
|
||||
if (fullscreen_) {
|
||||
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
}
|
||||
#endif
|
||||
sdl_window_ = SDL_CreateWindow(nullptr, SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED, target_res_x,
|
||||
target_res_y, flags);
|
||||
if (!sdl_window_) {
|
||||
throw Exception("Unable to create SDL Window of size "
|
||||
+ std::to_string(target_res_x) + " by "
|
||||
+ std::to_string(target_res_y));
|
||||
}
|
||||
sdl_gl_context_ = SDL_GL_CreateContext(sdl_window_);
|
||||
if (!sdl_gl_context_) {
|
||||
throw Exception("Unable to create SDL GL Context");
|
||||
}
|
||||
SDL_SetWindowTitle(sdl_window_, "BallisticaKit");
|
||||
// #if 0
|
||||
// // Fetch needed android gl stuff.
|
||||
// #if BA_OSTYPE_ANDROID
|
||||
// #define GET(PTRTYPE, FUNC, REQUIRED) \
|
||||
// FUNC = (PTRTYPE)eglGetProcAddress(#FUNC); \
|
||||
// if (!FUNC) FUNC = (PTRTYPE)eglGetProcAddress(#FUNC "EXT"); \
|
||||
// if (REQUIRED) { \
|
||||
// BA_PRECONDITION(FUNC != nullptr); \
|
||||
// }
|
||||
// GET(PFNGLDISCARDFRAMEBUFFEREXTPROC, _glDiscardFramebufferEXT, false);
|
||||
// #endif // BA_OSTYPE_ANDROID
|
||||
|
||||
// Our actual drawable size could differ from the window size on retina
|
||||
// devices.
|
||||
int win_size_x, win_size_y;
|
||||
SDL_GetWindowSize(sdl_window_, &win_size_x, &win_size_y);
|
||||
AppAdapterSDL::Get()->SetInitialScreenDimensions(Vector2f(
|
||||
static_cast<float>(win_size_x), static_cast<float>(win_size_y)));
|
||||
#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
res_x_ = win_size_x;
|
||||
res_y_ = win_size_y;
|
||||
#else
|
||||
SDL_GL_GetDrawableSize(sdl_window_, &res_x_, &res_y_);
|
||||
#endif // BA_OSTYPE_ANDROID
|
||||
// #endif // 0
|
||||
|
||||
// This can come through as zero in some cases (on our cardboard build at
|
||||
// least).
|
||||
if (win_size_x != 0) {
|
||||
pixel_density_ =
|
||||
static_cast<float>(res_x_) / static_cast<float>(win_size_x);
|
||||
}
|
||||
#elif BA_SDL_BUILD // BA_SDL2_BUILD
|
||||
// Provide an empty implementation of this if noone provided a real one.
|
||||
#ifndef BA_HAS_SYS_GL_INIT
|
||||
|
||||
int v_flags;
|
||||
v_flags = SDL_OPENGL;
|
||||
if (fullscreen_) {
|
||||
v_flags |= SDL_FULLSCREEN;
|
||||
// convert to the closest valid fullscreen resolution
|
||||
// (our last 1.2 build is mac and it's got hacked-in fullscreen-window
|
||||
// support; so we don't need this) getValidResolution(target_res_x,
|
||||
// target_res_y);
|
||||
} else {
|
||||
v_flags |= SDL_RESIZABLE;
|
||||
}
|
||||
surface_ = SDL_SetVideoMode(target_res_x, target_res_y, 32, v_flags);
|
||||
void SysGLInit() { assert(!g_sys_gl_inited); }
|
||||
|
||||
// if we failed, fall back to windowed mode.
|
||||
if (surface_ == nullptr) {
|
||||
throw Exception("SDL_SetVideoMode() failed for "
|
||||
+ std::to_string(target_res_x) + " by "
|
||||
+ std::to_string(target_res_y) + " fullscreen="
|
||||
+ std::to_string(static_cast<int>(fullscreen_)));
|
||||
}
|
||||
res_x_ = surface_->w;
|
||||
res_y_ = surface_->h;
|
||||
AppAdapterSDL::Get()->SetInitialScreenDimensions(Vector2f(res_x_, res_y_));
|
||||
SDL_WM_SetCaption("BallisticaKit", "BallisticaKit");
|
||||
#elif BA_OSTYPE_ANDROID
|
||||
// On Android the Java layer creates a GL setup before even calling us.
|
||||
// So we have nothing to do here. Hooray!
|
||||
#else
|
||||
throw Exception("FIXME: Unimplemented");
|
||||
#endif // BA_SDL2_BUILD
|
||||
}
|
||||
|
||||
// Fetch needed android gl stuff.
|
||||
#if BA_OSTYPE_ANDROID
|
||||
#define GET(PTRTYPE, FUNC, REQUIRED) \
|
||||
FUNC = (PTRTYPE)eglGetProcAddress(#FUNC); \
|
||||
if (!FUNC) FUNC = (PTRTYPE)eglGetProcAddress(#FUNC "EXT"); \
|
||||
if (REQUIRED) { \
|
||||
BA_PRECONDITION(FUNC != nullptr); \
|
||||
}
|
||||
GET(PFNGLDISCARDFRAMEBUFFEREXTPROC, _glDiscardFramebufferEXT, false);
|
||||
#endif // BA_OSTYPE_ANDROID
|
||||
|
||||
// Fetch needed windows gl stuff.
|
||||
#if BA_OSTYPE_WINDOWS
|
||||
#define GET(PTRTYPE, FUNC, REQUIRED) \
|
||||
FUNC = (PTRTYPE)wglGetProcAddress(#FUNC); \
|
||||
if (!FUNC) FUNC = (PTRTYPE)wglGetProcAddress(#FUNC "EXT"); \
|
||||
if (REQUIRED) { \
|
||||
BA_PRECONDITION(FUNC != nullptr); \
|
||||
}
|
||||
GET(PFNGLGETINTERNALFORMATIVPROC, glGetInternalformativ,
|
||||
false); // for checking msaa level support
|
||||
GET(PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC,
|
||||
glGetFramebufferAttachmentParameteriv, false); // for checking srgb stuff
|
||||
GET(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate,
|
||||
false); // needed for VR overlay
|
||||
GET(PFNGLACTIVETEXTUREPROC, glActiveTexture, true);
|
||||
GET(PFNGLCLIENTACTIVETEXTUREARBPROC, glClientActiveTextureARB, true);
|
||||
GET(PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT, true);
|
||||
GET(PFNGLPOINTPARAMETERFVARBPROC, glPointParameterfvARB, true);
|
||||
GET(PFNGLPOINTPARAMETERFARBPROC, glPointParameterfARB, true);
|
||||
GET(PFNGLCREATEPROGRAMPROC, glCreateProgram, true);
|
||||
GET(PFNGLCREATESHADERPROC, glCreateShader, true);
|
||||
GET(PFNGLSHADERSOURCEPROC, glShaderSource, true);
|
||||
GET(PFNGLCOMPILESHADERPROC, glCompileShader, true);
|
||||
GET(PFNGLLINKPROGRAMPROC, glLinkProgram, true);
|
||||
GET(PFNGLGETINFOLOGARBPROC, glGetInfoLogARB, true);
|
||||
GET(PFNGLATTACHSHADERPROC, glAttachShader, true);
|
||||
GET(PFNGLUSEPROGRAMOBJECTARBPROC, glUseProgram, true);
|
||||
GET(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap, true);
|
||||
GET(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer, true);
|
||||
GET(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation, true);
|
||||
GET(PFNGLUNIFORM1IPROC, glUniform1i, true);
|
||||
GET(PFNGLUNIFORM1FPROC, glUniform1f, true);
|
||||
GET(PFNGLUNIFORM1FVPROC, glUniform1fv, true);
|
||||
GET(PFNGLUNIFORM2FPROC, glUniform2f, true);
|
||||
GET(PFNGLUNIFORM3FPROC, glUniform3f, true);
|
||||
GET(PFNGLUNIFORM4FPROC, glUniform4f, true);
|
||||
GET(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers, true);
|
||||
GET(PFNGLGENBUFFERSPROC, glGenBuffers, true);
|
||||
GET(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D, true);
|
||||
GET(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers, true);
|
||||
GET(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer, true);
|
||||
GET(PFNGLBINDBUFFERPROC, glBindBuffer, true);
|
||||
GET(PFNGLBUFFERDATAPROC, glBufferData, true);
|
||||
GET(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage, true);
|
||||
GET(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer, true);
|
||||
GET(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus, true);
|
||||
GET(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers, true);
|
||||
GET(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers, true);
|
||||
GET(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer, true);
|
||||
GET(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray, true);
|
||||
GET(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray, true);
|
||||
GET(PFNGLUNIFORMMATRIX4FVARBPROC, glUniformMatrix4fv, true);
|
||||
GET(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation, true);
|
||||
GET(PFNGLCOMPRESSEDTEXIMAGE2DPROC, glCompressedTexImage2D, true);
|
||||
GET(PFNGLGETSHADERIVPROC, glGetShaderiv, true);
|
||||
GET(PFNGLGETPROGRAMIVPROC, glGetProgramiv, true);
|
||||
GET(PFNGLDELETESHADERPROC, glDeleteShader, true);
|
||||
GET(PFNGLDELETEBUFFERSPROC, glDeleteBuffers, true);
|
||||
GET(PFNGLDELETEPROGRAMPROC, glDeleteProgram, true);
|
||||
GET(PFNGLDETACHSHADERPROC, glDetachShader, true);
|
||||
GET(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog, true);
|
||||
GET(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog, true);
|
||||
|
||||
// Stuff we can live without:
|
||||
GET(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray, false);
|
||||
GET(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays, false);
|
||||
GET(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays, false);
|
||||
GET(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer, false);
|
||||
GET(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample,
|
||||
false);
|
||||
|
||||
#undef GET
|
||||
#endif // BA_OSTYPE_WINDOWS
|
||||
|
||||
// So that our window comes up nice and black.
|
||||
// FIXME should just make the window's blanking color black.
|
||||
|
||||
#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
// Not needed here.
|
||||
#else
|
||||
|
||||
#if BA_SDL2_BUILD
|
||||
// Gonna wait and see if if still need this.
|
||||
#elif BA_SDL_BUILD
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
SDL_GL_SwapBuffers();
|
||||
#endif // BA_SDL2_BUILD
|
||||
|
||||
#endif // IOS/ANDROID
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
void GLContext::SetVSync(bool enable) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
#if BA_OSTYPE_MACOS
|
||||
CGLContextObj context = CGLGetCurrentContext();
|
||||
BA_PRECONDITION(context);
|
||||
GLint sync = enable;
|
||||
CGLSetParameter(context, kCGLCPSwapInterval, &sync);
|
||||
#else
|
||||
|
||||
#endif // BA_OSTYPE_MACOS
|
||||
}
|
||||
|
||||
GLContext::~GLContext() {
|
||||
if (!g_base->InGraphicsThread()) {
|
||||
Log(LogLevel::kError, "GLContext dying in non-graphics thread");
|
||||
}
|
||||
#if BA_SDL2_BUILD
|
||||
|
||||
#if BA_RIFT_BUILD
|
||||
// (in rift we only have a window in 2d mode)
|
||||
if (!g_core->IsVRMode()) {
|
||||
BA_PRECONDITION_LOG(sdl_window_);
|
||||
}
|
||||
#else // BA_RIFT_MODE
|
||||
BA_PRECONDITION_LOG(sdl_window_);
|
||||
#endif // BA_RIFT_BUILD
|
||||
|
||||
if (sdl_window_) {
|
||||
SDL_DestroyWindow(sdl_window_);
|
||||
sdl_window_ = nullptr;
|
||||
}
|
||||
#elif BA_SDL_BUILD
|
||||
BA_PRECONDITION_LOG(surface_);
|
||||
if (surface_) {
|
||||
SDL_FreeSurface(surface_);
|
||||
surface_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
auto GLErrorToString(GLenum err) -> std::string {
|
||||
switch (err) {
|
||||
case GL_NO_ERROR:
|
||||
return "GL_NO_ERROR";
|
||||
case GL_INVALID_ENUM:
|
||||
return "GL_INVALID_ENUM";
|
||||
case GL_INVALID_VALUE:
|
||||
return "GL_INVALID_VALUE";
|
||||
case GL_INVALID_OPERATION:
|
||||
return "GL_INVALID_OPERATION";
|
||||
case GL_OUT_OF_MEMORY:
|
||||
return "GL_OUT_OF_MEMORY";
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
return "GL_INVALID_FRAMEBUFFER_OPERATION";
|
||||
default:
|
||||
return std::to_string(err);
|
||||
}
|
||||
}
|
||||
#endif // BA_HAS_SYS_GL_INIT
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
|
||||
@ -3,204 +3,232 @@
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_GL_SYS_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_GL_SYS_H_
|
||||
|
||||
// A single header to include system GL headers along with custom
|
||||
// per-platform defines/function-pointers/etc.
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
// On most platforms we directly link against GL and want all the functions
|
||||
// defined in the header for us. On Windows we have to define/load newer
|
||||
// stuff manually though, so we don't want that.
|
||||
#if !BA_OSTYPE_WINDOWS
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
// ----------------------------- BASE GL INCLUDES ------------------------------
|
||||
|
||||
#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
|
||||
#if BA_USE_ES3_INCLUDES
|
||||
#include <GLES3/gl3.h>
|
||||
#include <GLES3/gl3ext.h>
|
||||
#elif BA_OSTYPE_IOS_TVOS
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#else
|
||||
// On SDL builds, let SDL handle this for us.
|
||||
#if BA_SDL_BUILD
|
||||
#include <SDL/SDL.h> // needed for ios?...
|
||||
#include <SDL/SDL_opengles2.h>
|
||||
#else
|
||||
// FIXME: According to https://developer.android.com/ndk/guides/stable_apis
|
||||
// we can always link against ES3.1 now that we're API 21+, so we shouldn't
|
||||
// need our funky stubs and function lookups anymore.
|
||||
// (though we'll still need to check for availability of 3.x features)
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#endif // BA_SDL_BUILD
|
||||
#endif // BA_USE_ES3_INCLUDES
|
||||
|
||||
// looks like these few defines are currently missing on android
|
||||
// (s3tc works on some nvidia hardware)
|
||||
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
|
||||
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
|
||||
#endif
|
||||
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
||||
#endif
|
||||
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
|
||||
#endif
|
||||
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
||||
#endif
|
||||
|
||||
#else // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
|
||||
// SDK Desktop builds.
|
||||
#if BA_SDL2_BUILD
|
||||
#include <SDL_opengl.h>
|
||||
#elif BA_SDL_BUILD // BA_SDL2_BUILD
|
||||
#define NO_SDL_GLEXT
|
||||
#include <SDL_opengl.h>
|
||||
#endif // BA_SDL2_BUILD
|
||||
#endif
|
||||
|
||||
#if BA_OSTYPE_MACOS
|
||||
// For XCode builds, grab Apple's framework-y headers.
|
||||
#if BA_XCODE_BUILD
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#endif // BA_XCODE_BUILD
|
||||
#endif // BA_OSTYPE_MACOS
|
||||
|
||||
#endif // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
|
||||
#include "ballistica/core/platform/support/min_sdl.h"
|
||||
#include "ballistica/shared/foundation/object.h"
|
||||
|
||||
#if BA_OSTYPE_ANDROID
|
||||
extern PFNGLDISCARDFRAMEBUFFEREXTPROC _glDiscardFramebufferEXT;
|
||||
#if BA_OPENGL_IS_ES
|
||||
#include <OpenGLES/ES3/gl.h>
|
||||
#include <OpenGLES/ES3/glext.h>
|
||||
#else
|
||||
#include <OpenGL/gl3.h>
|
||||
#include <OpenGL/gl3ext.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// On Android, we're currently supporting Android API 21 and newer, which
|
||||
// means we can count on GL ES 3.1 libs/headers always being available. Note
|
||||
// that hardware may still be limited to older versions so we need to check
|
||||
// for that and set a limit in our manifest.
|
||||
#if BA_OSTYPE_ANDROID
|
||||
#include <GLES3/gl31.h>
|
||||
#include <GLES3/gl3ext.h>
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Now mix in a bit of magic of our own...
|
||||
|
||||
// We may use S3TC types even on ES (Android Nvidia hardware supports them)
|
||||
// but they're not currently in ES's glext.h. Define here if needed.
|
||||
#ifndef GL_EXT_texture_compression_s3tc
|
||||
#define GL_EXT_texture_compression_s3tc 1
|
||||
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
||||
#endif /* GL_EXT_texture_compression_s3tc */
|
||||
|
||||
// Anisotropic texturing is still an extension in GL 3 and ES 3.2, so
|
||||
// define its values if need be (they seem to exist in desktop glext.h
|
||||
// but not es)
|
||||
#ifndef GL_EXT_texture_filter_anisotropic
|
||||
#define GL_EXT_texture_filter_anisotropic 1
|
||||
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
|
||||
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
|
||||
#endif /* GL_EXT_texture_filter_anisotropic */
|
||||
|
||||
// Desktop GL has glDepthRange() which takes a double. GL ES has
|
||||
// glDepthRangef() which takes a float. Let's always accept doubles and
|
||||
// down-convert where needed.
|
||||
#if BA_OPENGL_IS_ES
|
||||
inline void glDepthRange(double min, double max) {
|
||||
return glDepthRangef(min, max);
|
||||
}
|
||||
#endif
|
||||
|
||||
// #if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
|
||||
// #if BA_USE_ES3_INCLUDES
|
||||
// #include <GLES3/gl3.h>
|
||||
// #include <GLES3/gl3ext.h>
|
||||
// #elif BA_OSTYPE_IOS_TVOS
|
||||
// #include <OpenGLES/ES2/gl.h>
|
||||
// #include <OpenGLES/ES2/glext.h>
|
||||
// #else
|
||||
// #if BA_SDL_BUILD
|
||||
// #include <SDL/SDL.h> // needed for ios?...
|
||||
// #include <SDL/SDL_opengles2.h>
|
||||
// #else
|
||||
// // FIXME: According to https://developer.android.com/ndk/guides/stable_apis
|
||||
// // we can always link against ES3.1 now that we're API 21+, so we shouldn't
|
||||
// // need our funky stubs and function lookups anymore.
|
||||
// // (though we'll still need to check for availability of 3.x features)
|
||||
// #include <GLES2/gl2.h>
|
||||
// #include <GLES2/gl2ext.h>
|
||||
// #endif // BA_SDL_BUILD
|
||||
// #endif // BA_USE_ES3_INCLUDES
|
||||
|
||||
// Looks like these few defines are currently missing on android (s3tc works
|
||||
// on some nvidia hardware).
|
||||
// #ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
|
||||
// #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
|
||||
// #endif
|
||||
// #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
|
||||
// #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
||||
// #endif
|
||||
// #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
|
||||
// #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
|
||||
// #endif
|
||||
// #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
|
||||
// #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
||||
// #endif
|
||||
|
||||
// #if BA_OSTYPE_IOS_TVOS
|
||||
// extern void (*glInvalidateFramebuffer)(GLenum target, GLsizei
|
||||
// num_attachments,
|
||||
// const GLenum* attachments);
|
||||
// #define glDepthRange glDepthRangef
|
||||
// #define glGenVertexArrays glGenVertexArraysOES
|
||||
// #define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||
// #define glBindVertexArray glBindVertexArrayOES
|
||||
// #define glClearDepth glClearDepthf
|
||||
// #endif // BA_OSTYPE_IOS_TVOS
|
||||
|
||||
// #else // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
|
||||
// SDL Desktop builds.
|
||||
// #if BA_SDL2_BUILD
|
||||
// #include <SDL_opengl.h>
|
||||
// #elif BA_SDL_BUILD // BA_SDL2_BUILD
|
||||
// #define NO_SDL_GLEXT
|
||||
// #include <SDL_opengl.h>
|
||||
// #endif // BA_SDL2_BUILD
|
||||
|
||||
// #if BA_OSTYPE_MACOS
|
||||
// #include <OpenGL/CGLContext.h>
|
||||
// (NO LONGER APPLIES IN CORE PROFILE)
|
||||
// #define glGenVertexArrays glGenVertexArraysAPPLE
|
||||
// #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
|
||||
// #define glBindVertexArray glBindVertexArrayAPPLE
|
||||
// #endif // BA_OSTYPE_MACOS
|
||||
|
||||
// #endif // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
|
||||
|
||||
// #if BA_OSTYPE_ANDROID
|
||||
// #include <EGL/egl.h>
|
||||
// #include <android/log.h>
|
||||
// #if !BA_USE_ES3_INCLUDES
|
||||
// #include "ballistica/core/platform/android/android_gl3.h"
|
||||
// #endif
|
||||
// #define glDepthRange glDepthRangef
|
||||
// #define glDiscardFramebufferEXT _glDiscardFramebufferEXT
|
||||
// #ifndef GL_RGB565_OES
|
||||
// #define GL_RGB565_OES 0x8D62
|
||||
// #endif // GL_RGB565_OES
|
||||
// #define GL_READ_FRAMEBUFFER 0x8CA8
|
||||
// #define GL_DRAW_FRAMEBUFFER 0x8CA9
|
||||
// #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
|
||||
// #define glClearDepth glClearDepthf
|
||||
// #endif // BA_OSTYPE_ANDROID
|
||||
|
||||
// #if BA_OSTYPE_ANDROID
|
||||
// extern PFNGLDISCARDFRAMEBUFFEREXTPROC _glDiscardFramebufferEXT;
|
||||
// #endif
|
||||
|
||||
#if BA_OSTYPE_WINDOWS
|
||||
#ifndef WGL_EXT_swap_control
|
||||
#define WGL_EXT_swap_control 1
|
||||
typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC)(int interval);
|
||||
typedef int(WINAPI* PFNWGLGETSWAPINTERVALEXTPROC)(VOID); // NOLINT
|
||||
#endif // WGL_EXT_swap_control
|
||||
extern PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ;
|
||||
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC
|
||||
glGetFramebufferAttachmentParameteriv;
|
||||
extern PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate;
|
||||
extern PFNGLACTIVETEXTUREPROC glActiveTexture;
|
||||
extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
|
||||
extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
|
||||
extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
|
||||
extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
|
||||
extern PFNGLCREATEPROGRAMPROC glCreateProgram;
|
||||
extern PFNGLCREATESHADERPROC glCreateShader;
|
||||
extern PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
extern PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
extern PFNGLLINKPROGRAMPROC glLinkProgram;
|
||||
extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
|
||||
extern PFNGLATTACHSHADERPROC glAttachShader;
|
||||
extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgram;
|
||||
extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
|
||||
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
||||
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
|
||||
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
||||
extern PFNGLUNIFORM1IPROC glUniform1i;
|
||||
extern PFNGLUNIFORM1FPROC glUniform1f;
|
||||
extern PFNGLUNIFORM1FVPROC glUniform1fv;
|
||||
extern PFNGLUNIFORM2FPROC glUniform2f;
|
||||
extern PFNGLUNIFORM3FPROC glUniform3f;
|
||||
extern PFNGLUNIFORM4FPROC glUniform4f;
|
||||
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
||||
extern PFNGLGENBUFFERSPROC glGenBuffers;
|
||||
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||
extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
||||
extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
||||
extern PFNGLBINDBUFFERPROC glBindBuffer;
|
||||
extern PFNGLBUFFERDATAPROC glBufferData;
|
||||
extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
||||
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
|
||||
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
||||
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
|
||||
extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
|
||||
extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
|
||||
extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
|
||||
extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
|
||||
extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fv;
|
||||
extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
|
||||
extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
|
||||
extern PFNGLGETSHADERIVPROC glGetShaderiv;
|
||||
extern PFNGLGETPROGRAMIVPROC glGetProgramiv;
|
||||
extern PFNGLDELETESHADERPROC glDeleteShader;
|
||||
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
||||
extern PFNGLDELETEBUFFERSPROC glDeleteBuffers;
|
||||
extern PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
||||
extern PFNGLDETACHSHADERPROC glDetachShader;
|
||||
extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
||||
extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
||||
#endif // BA_OSTYPE_WINDOWS
|
||||
|
||||
#ifndef GL_NV_texture_rectangle
|
||||
#define GL_TEXTURE_RECTANGLE_NV 0x84F5
|
||||
#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6
|
||||
#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7
|
||||
#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8
|
||||
#endif
|
||||
#ifndef GL_NV_texture_rectangle
|
||||
#define GL_NV_texture_rectangle 1
|
||||
#include "ballistica/base/graphics/gl/gl_sys_windows.h"
|
||||
#endif
|
||||
|
||||
// Support for gl object debug labeling.
|
||||
// #ifndef GL_NV_texture_rectangle
|
||||
// #define GL_TEXTURE_RECTANGLE_NV 0x84F5
|
||||
// #define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6
|
||||
// #define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7
|
||||
// #define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8
|
||||
// #endif
|
||||
// #ifndef GL_NV_texture_rectangle
|
||||
// #define GL_NV_texture_rectangle 1
|
||||
// #endif
|
||||
|
||||
// Support for GL object debug labeling.
|
||||
#if BA_OSTYPE_IOS_TVOS
|
||||
#define GL_LABEL_OBJECT(type, obj, label) glLabelObjectEXT(type, obj, 0, label)
|
||||
#define GL_PUSH_GROUP_MARKER(label) glPushGroupMarkerEXT(0, label)
|
||||
#define GL_POP_GROUP_MARKER() glPopGroupMarkerEXT()
|
||||
#define BA_GL_LABEL_OBJECT(type, obj, label) \
|
||||
glLabelObjectEXT(type, obj, 0, label)
|
||||
#define BA_GL_PUSH_GROUP_MARKER(label) glPushGroupMarkerEXT(0, label)
|
||||
#define BA_GL_POP_GROUP_MARKER() glPopGroupMarkerEXT()
|
||||
#else
|
||||
#define GL_LABEL_OBJECT(type, obj, label) ((void)0)
|
||||
#define GL_PUSH_GROUP_MARKER(label) ((void)0)
|
||||
#define GL_POP_GROUP_MARKER() ((void)0)
|
||||
#define BA_GL_LABEL_OBJECT(type, obj, label) ((void)0)
|
||||
#define BA_GL_PUSH_GROUP_MARKER(label) ((void)0)
|
||||
#define BA_GL_POP_GROUP_MARKER() ((void)0)
|
||||
#endif
|
||||
|
||||
// OpenGL ES uses precision; regular GL doesn't.
|
||||
#if BA_OPENGL_IS_ES
|
||||
#define BA_GLSL_LOWP "lowp "
|
||||
#define BA_GLSL_MEDIUMP "mediump "
|
||||
#define BA_GLSL_HIGHP "highp "
|
||||
#else
|
||||
#define BA_GLSL_LOWP
|
||||
#define BA_GLSL_MEDIUMP
|
||||
#define BA_GLSL_HIGHP
|
||||
#endif // BA_OPENGL_IS_ES
|
||||
|
||||
// Our old GLSL source uses 'attribute' and our newer uses 'in'
|
||||
#if BA_OPENGL_IS_ES
|
||||
#define BA_GLSL_VERTEX_IN "attribute"
|
||||
#define BA_GLSL_VERTEX_OUT "varying"
|
||||
#define BA_GLSL_FRAG_IN "varying"
|
||||
#define BA_GLSL_FRAGCOLOR "gl_FragColor"
|
||||
#define BA_GLSL_TEXTURE2D "texture2D"
|
||||
#define BA_GLSL_TEXTURE2DPROJ "texture2DProj"
|
||||
#define BA_GLSL_TEXTURECUBE "textureCube"
|
||||
#else
|
||||
#define BA_GLSL_VERTEX_IN "in"
|
||||
#define BA_GLSL_VERTEX_OUT "out"
|
||||
#define BA_GLSL_FRAG_IN "in"
|
||||
#define BA_GLSL_FRAGCOLOR "fragColor"
|
||||
#define BA_GLSL_TEXTURE2D "texture"
|
||||
#define BA_GLSL_TEXTURE2DPROJ "textureProj"
|
||||
#define BA_GLSL_TEXTURECUBE "texture"
|
||||
#endif
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
auto GLErrorToString(GLenum err) -> std::string;
|
||||
extern bool g_sys_gl_inited;
|
||||
|
||||
// Container for OpenGL rendering context data.
|
||||
class GLContext {
|
||||
public:
|
||||
GLContext(int target_res_x, int target_res_y, bool fullScreen);
|
||||
~GLContext();
|
||||
auto res_x() const -> int { return res_x_; }
|
||||
auto res_y() const -> int { return res_y_; }
|
||||
auto pixel_density() const -> float { return pixel_density_; }
|
||||
void SetVSync(bool enable);
|
||||
|
||||
// Currently no surface/window in this case.
|
||||
#if BA_SDL2_BUILD
|
||||
auto sdl_window() const -> SDL_Window* {
|
||||
assert(sdl_window_);
|
||||
return sdl_window_;
|
||||
}
|
||||
#elif BA_SDL_BUILD // BA_SDL2_BUILD
|
||||
SDL_Surface* sdl_screen_surface() const {
|
||||
assert(surface_);
|
||||
return surface_;
|
||||
}
|
||||
#endif // BA_SDL2_BUILD
|
||||
|
||||
private:
|
||||
#if BA_SDL2_BUILD
|
||||
SDL_Window* sdl_window_{};
|
||||
SDL_GLContext sdl_gl_context_{};
|
||||
#endif // BA_SDL2_BUILD
|
||||
bool fullscreen_{};
|
||||
int res_x_{};
|
||||
int res_y_{};
|
||||
float pixel_density_{1.0f};
|
||||
#if BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
SDL_Surface* surface_{};
|
||||
#endif
|
||||
}; // GLContext
|
||||
// Called when a GL renderer is spinning up. Allows fetching/assigning any
|
||||
// global function pointers or data needed for GL to function. Will be
|
||||
// called only once and then g_sys_gl_inited set. A platform that defines
|
||||
// this should define BA_HAS_SYS_GL_INIT; otherwise a default empty
|
||||
// implementation will be defined.
|
||||
void SysGLInit();
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
|
||||
175
src/ballistica/base/graphics/gl/gl_sys_windows.cc
Normal file
175
src/ballistica/base/graphics/gl/gl_sys_windows.cc
Normal file
@ -0,0 +1,175 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#if BA_ENABLE_OPENGL && BA_OSTYPE_WINDOWS
|
||||
#include "ballistica/base/graphics/gl/gl_sys_windows.h"
|
||||
|
||||
#include "SDL.h"
|
||||
#include "ballistica/base/graphics/gl/gl_sys.h"
|
||||
#include "ballistica/shared/ballistica.h"
|
||||
|
||||
#pragma comment(lib, "opengl32.lib")
|
||||
// #pragma comment(lib, "glu32.lib")
|
||||
|
||||
PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ{};
|
||||
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC
|
||||
glGetFramebufferAttachmentParameteriv{};
|
||||
PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate{};
|
||||
PFNGLACTIVETEXTUREPROC glActiveTextureBA{};
|
||||
// PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB{};
|
||||
PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB{};
|
||||
// PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB{};
|
||||
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT{};
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram{};
|
||||
PFNGLCREATESHADERPROC glCreateShader{};
|
||||
PFNGLSHADERSOURCEPROC glShaderSource{};
|
||||
PFNGLCOMPILESHADERPROC glCompileShader{};
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram{};
|
||||
PFNGLGETINFOLOGARBPROC glGetInfoLogARB{};
|
||||
PFNGLATTACHSHADERPROC glAttachShader{};
|
||||
PFNGLUSEPROGRAMOBJECTARBPROC glUseProgram{};
|
||||
PFNGLGENERATEMIPMAPPROC glGenerateMipmap{};
|
||||
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer{};
|
||||
PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer{};
|
||||
PFNGLBINDVERTEXARRAYPROC glBindVertexArray{};
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation{};
|
||||
PFNGLUNIFORM1IPROC glUniform1i{};
|
||||
PFNGLUNIFORM1FPROC glUniform1f{};
|
||||
PFNGLUNIFORM1FVPROC glUniform1fv{};
|
||||
PFNGLUNIFORM2FPROC glUniform2f{};
|
||||
PFNGLUNIFORM3FPROC glUniform3f{};
|
||||
PFNGLUNIFORM4FPROC glUniform4f{};
|
||||
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers{};
|
||||
PFNGLGENBUFFERSPROC glGenBuffers{};
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays{};
|
||||
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D{};
|
||||
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers{};
|
||||
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer{};
|
||||
PFNGLBINDBUFFERPROC glBindBuffer{};
|
||||
PFNGLBUFFERDATAPROC glBufferData{};
|
||||
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage{};
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample{};
|
||||
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer{};
|
||||
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus{};
|
||||
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers{};
|
||||
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers{};
|
||||
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer{};
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray{};
|
||||
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray{};
|
||||
PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fv{};
|
||||
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation{};
|
||||
PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2DBA{};
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv{};
|
||||
PFNGLGETPROGRAMIVPROC glGetProgramiv{};
|
||||
PFNGLDELETESHADERPROC glDeleteShader{};
|
||||
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays{};
|
||||
PFNGLDELETEBUFFERSPROC glDeleteBuffers{};
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram{};
|
||||
PFNGLDETACHSHADERPROC glDetachShader{};
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog{};
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog{};
|
||||
PFNGLGETSTRINGIPROC glGetStringi{};
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
static auto GetGLFunc_(const char* name, bool required) -> void* {
|
||||
void* func = SDL_GL_GetProcAddress(name);
|
||||
if (!func) {
|
||||
func = SDL_GL_GetProcAddress((std::string(name) + "EXT").c_str());
|
||||
}
|
||||
if (required && func == nullptr) {
|
||||
FatalError("OpenGL function '" + std::string(name)
|
||||
+ "' not found.\nAre your graphics drivers up to date?");
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
// Our variable name matches the name we're fetching from the library.
|
||||
#define GET(PTRTYPE, FUNC, REQUIRED) FUNC = (PTRTYPE)GetGLFunc_(#FUNC, REQUIRED)
|
||||
|
||||
// Our variable name equals the library name + BA. (For symbol clashes).
|
||||
#define GET2(PTRTYPE, FUNC, REQUIRED) \
|
||||
FUNC##BA = (PTRTYPE)GetGLFunc_(#FUNC, REQUIRED)
|
||||
|
||||
void SysGLInit() {
|
||||
assert(!g_sys_gl_inited);
|
||||
|
||||
SDL_GL_LoadLibrary(nullptr);
|
||||
|
||||
void* testval{};
|
||||
|
||||
PFNGLGETINTERNALFORMATIVPROC fptr;
|
||||
fptr = (PFNGLGETINTERNALFORMATIVPROC)testval;
|
||||
|
||||
// For checking msaa level support. This is only available in GL 4.2+
|
||||
// so we can survive without it.
|
||||
GET(PFNGLGETINTERNALFORMATIVPROC, glGetInternalformativ, false);
|
||||
|
||||
// For checking srgb stuff.
|
||||
GET(PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC,
|
||||
glGetFramebufferAttachmentParameteriv, false);
|
||||
|
||||
// Needed for VR overlay.
|
||||
GET(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate, false);
|
||||
|
||||
GET2(PFNGLACTIVETEXTUREPROC, glActiveTexture, true);
|
||||
// GET(PFNGLCLIENTACTIVETEXTUREARBPROC, glClientActiveTextureARB, true);
|
||||
GET(PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT, true);
|
||||
GET(PFNGLPOINTPARAMETERFVARBPROC, glPointParameterfvARB, true);
|
||||
// GET(PFNGLPOINTPARAMETERFARBPROC, glPointParameterfARB, true);
|
||||
GET(PFNGLCREATEPROGRAMPROC, glCreateProgram, true);
|
||||
GET(PFNGLCREATESHADERPROC, glCreateShader, true);
|
||||
GET(PFNGLSHADERSOURCEPROC, glShaderSource, true);
|
||||
GET(PFNGLCOMPILESHADERPROC, glCompileShader, true);
|
||||
GET(PFNGLLINKPROGRAMPROC, glLinkProgram, true);
|
||||
GET(PFNGLGETINFOLOGARBPROC, glGetInfoLogARB, true);
|
||||
GET(PFNGLATTACHSHADERPROC, glAttachShader, true);
|
||||
GET(PFNGLUSEPROGRAMOBJECTARBPROC, glUseProgram, true);
|
||||
GET(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap, true);
|
||||
GET(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer, true);
|
||||
GET(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation, true);
|
||||
GET(PFNGLUNIFORM1IPROC, glUniform1i, true);
|
||||
GET(PFNGLUNIFORM1FPROC, glUniform1f, true);
|
||||
GET(PFNGLUNIFORM1FVPROC, glUniform1fv, true);
|
||||
GET(PFNGLUNIFORM2FPROC, glUniform2f, true);
|
||||
GET(PFNGLUNIFORM3FPROC, glUniform3f, true);
|
||||
GET(PFNGLUNIFORM4FPROC, glUniform4f, true);
|
||||
GET(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers, true);
|
||||
GET(PFNGLGENBUFFERSPROC, glGenBuffers, true);
|
||||
GET(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D, true);
|
||||
GET(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers, true);
|
||||
GET(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer, true);
|
||||
GET(PFNGLBINDBUFFERPROC, glBindBuffer, true);
|
||||
GET(PFNGLBUFFERDATAPROC, glBufferData, true);
|
||||
GET(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage, true);
|
||||
GET(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer, true);
|
||||
GET(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus, true);
|
||||
GET(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers, true);
|
||||
GET(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers, true);
|
||||
GET(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer, true);
|
||||
GET(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray, true);
|
||||
GET(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray, true);
|
||||
GET(PFNGLUNIFORMMATRIX4FVARBPROC, glUniformMatrix4fv, true);
|
||||
GET(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation, true);
|
||||
GET2(PFNGLCOMPRESSEDTEXIMAGE2DPROC, glCompressedTexImage2D, true);
|
||||
GET(PFNGLGETSHADERIVPROC, glGetShaderiv, true);
|
||||
GET(PFNGLGETPROGRAMIVPROC, glGetProgramiv, true);
|
||||
GET(PFNGLDELETESHADERPROC, glDeleteShader, true);
|
||||
GET(PFNGLDELETEBUFFERSPROC, glDeleteBuffers, true);
|
||||
GET(PFNGLDELETEPROGRAMPROC, glDeleteProgram, true);
|
||||
GET(PFNGLDETACHSHADERPROC, glDetachShader, true);
|
||||
GET(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog, true);
|
||||
GET(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog, true);
|
||||
GET(PFNGLGETSTRINGIPROC, glGetStringi, true);
|
||||
GET(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray, true);
|
||||
GET(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays, true);
|
||||
GET(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays, true);
|
||||
GET(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer, true);
|
||||
GET(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample,
|
||||
true);
|
||||
}
|
||||
#undef GET
|
||||
#undef GET2
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL && BA_OSTYPE_WINDOWS
|
||||
91
src/ballistica/base/graphics/gl/gl_sys_windows.h
Normal file
91
src/ballistica/base/graphics/gl/gl_sys_windows.h
Normal file
@ -0,0 +1,91 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_GL_SYS_WINDOWS_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_GL_SYS_WINDOWS_H_
|
||||
|
||||
// System GL bits for windows.
|
||||
|
||||
#if BA_ENABLE_OPENGL && BA_OSTYPE_WINDOWS
|
||||
|
||||
// We don't *actually* need this because gl_sys.h includes it before
|
||||
// it includes us, but this keeps things from erroring if we look at
|
||||
// the header by itself.
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
// We run some init code to grab function ptrs/etc.
|
||||
#define BA_HAS_SYS_GL_INIT
|
||||
|
||||
#ifndef WGL_EXT_swap_control
|
||||
#define WGL_EXT_swap_control 1
|
||||
typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC)(int interval);
|
||||
typedef int(WINAPI* PFNWGLGETSWAPINTERVALEXTPROC)(VOID); // NOLINT
|
||||
#endif
|
||||
|
||||
// These seem to be defined by the SDL GL headers even though we asked them
|
||||
// nicely not to (by not defining GL_GLEXT_PROTOTYPES). So we need to import
|
||||
// and use it via a custom name.
|
||||
#define glActiveTexture glActiveTextureBA
|
||||
#define glCompressedTexImage2D glCompressedTexImage2DBA
|
||||
|
||||
extern PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ;
|
||||
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC
|
||||
glGetFramebufferAttachmentParameteriv;
|
||||
extern PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate;
|
||||
extern PFNGLACTIVETEXTUREPROC glActiveTextureBA;
|
||||
// extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
|
||||
// extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
|
||||
extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
|
||||
extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
|
||||
extern PFNGLCREATEPROGRAMPROC glCreateProgram;
|
||||
extern PFNGLCREATESHADERPROC glCreateShader;
|
||||
extern PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
extern PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
extern PFNGLLINKPROGRAMPROC glLinkProgram;
|
||||
extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
|
||||
extern PFNGLATTACHSHADERPROC glAttachShader;
|
||||
extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgram;
|
||||
extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
|
||||
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
||||
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
|
||||
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
||||
extern PFNGLUNIFORM1IPROC glUniform1i;
|
||||
extern PFNGLUNIFORM1FPROC glUniform1f;
|
||||
extern PFNGLUNIFORM1FVPROC glUniform1fv;
|
||||
extern PFNGLUNIFORM2FPROC glUniform2f;
|
||||
extern PFNGLUNIFORM3FPROC glUniform3f;
|
||||
extern PFNGLUNIFORM4FPROC glUniform4f;
|
||||
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
||||
extern PFNGLGENBUFFERSPROC glGenBuffers;
|
||||
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||
extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
||||
extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
||||
extern PFNGLBINDBUFFERPROC glBindBuffer;
|
||||
extern PFNGLBUFFERDATAPROC glBufferData;
|
||||
extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
||||
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
|
||||
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
||||
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
|
||||
extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
|
||||
extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
|
||||
extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
|
||||
extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
|
||||
extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fv;
|
||||
extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
|
||||
extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2DBA;
|
||||
extern PFNGLGETSHADERIVPROC glGetShaderiv;
|
||||
extern PFNGLGETPROGRAMIVPROC glGetProgramiv;
|
||||
extern PFNGLDELETESHADERPROC glDeleteShader;
|
||||
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
||||
extern PFNGLDELETEBUFFERSPROC glDeleteBuffers;
|
||||
extern PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
||||
extern PFNGLDETACHSHADERPROC glDetachShader;
|
||||
extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
||||
extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
||||
extern PFNGLGETSTRINGIPROC glGetStringi;
|
||||
|
||||
#endif // BA_ENABLE_OPENGL && BA_OSTYPE_WINDOWS
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_GL_SYS_WINDOWS_H_
|
||||
159
src/ballistica/base/graphics/gl/mesh/mesh_asset_data_gl.h
Normal file
159
src/ballistica/base/graphics/gl/mesh/mesh_asset_data_gl.h
Normal file
@ -0,0 +1,159 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_ASSET_DATA_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_ASSET_DATA_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/gl_sys.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/graphics/mesh/mesh_renderer_data.h"
|
||||
#include "ballistica/shared/ballistica.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::MeshAssetDataGL : public MeshAssetRendererData {
|
||||
public:
|
||||
enum BufferType { kVertices, kIndices, kBufferCount };
|
||||
|
||||
MeshAssetDataGL(const MeshAsset& model, RendererGL* renderer)
|
||||
: renderer_(renderer), fake_vao_(nullptr) {
|
||||
#if BA_DEBUG_BUILD
|
||||
name_ = model.GetName();
|
||||
#endif
|
||||
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
// Create our vertex array to hold all this state.
|
||||
|
||||
glGenVertexArrays(1, &vao_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
renderer->BindVertexArray_(vao_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
glGenBuffers(kBufferCount, vbos_);
|
||||
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
// Fill our vertex data buffer.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertices]);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
static_cast_check_fit<GLsizeiptr>(model.vertices().size()
|
||||
* sizeof(VertexObjectFull)),
|
||||
&(model.vertices()[0]), GL_STATIC_DRAW);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexObjectFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexObjectFull, position)));
|
||||
glEnableVertexAttribArray(kVertexAttrPosition);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(VertexObjectFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexObjectFull, uv)));
|
||||
glEnableVertexAttribArray(kVertexAttrUV);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrNormal, 3, GL_SHORT, GL_TRUE, sizeof(VertexObjectFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexObjectFull, normal)));
|
||||
glEnableVertexAttribArray(kVertexAttrNormal);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
// Fill our index data buffer.
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos_[kIndices]);
|
||||
|
||||
const GLvoid* index_data;
|
||||
switch (model.GetIndexSize()) {
|
||||
case 1: {
|
||||
elem_count_ = static_cast<uint32_t>(model.indices8().size());
|
||||
index_type_ = GL_UNSIGNED_BYTE;
|
||||
index_data = static_cast<const GLvoid*>(model.indices8().data());
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
elem_count_ = static_cast<uint32_t>(model.indices16().size());
|
||||
index_type_ = GL_UNSIGNED_SHORT;
|
||||
index_data = static_cast<const GLvoid*>(model.indices16().data());
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
BA_LOG_ONCE(
|
||||
LogLevel::kWarning,
|
||||
"GL WARNING - USING 32 BIT INDICES WHICH WONT WORK IN ES2!!");
|
||||
elem_count_ = static_cast<uint32_t>(model.indices32().size());
|
||||
index_type_ = GL_UNSIGNED_INT;
|
||||
index_data = static_cast<const GLvoid*>(model.indices32().data());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Exception();
|
||||
}
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER,
|
||||
static_cast_check_fit<GLsizeiptr>(elem_count_ * model.GetIndexSize()),
|
||||
index_data, GL_STATIC_DRAW);
|
||||
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
~MeshAssetDataGL() override {
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
// Unbind if we're bound; otherwise if a new vao pops up with our same
|
||||
// ID it'd be prevented from binding.
|
||||
if (vao_ == renderer_->current_vertex_array_) {
|
||||
renderer_->BindVertexArray_(0);
|
||||
}
|
||||
if (!g_base->graphics_server->renderer_context_lost()) {
|
||||
glDeleteVertexArrays(1, &vao_);
|
||||
}
|
||||
|
||||
// Make sure our dying buffer isn't current (don't wanna prevent binding
|
||||
// to a new buffer with a recycled id).
|
||||
for (unsigned int vbo : vbos_) {
|
||||
if (vbo == renderer_->active_array_buffer_) {
|
||||
renderer_->active_array_buffer_ = -1;
|
||||
}
|
||||
}
|
||||
if (!g_base->graphics_server->renderer_context_lost()) {
|
||||
glDeleteBuffers(kBufferCount, vbos_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void Bind() {
|
||||
renderer_->BindVertexArray_(vao_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
void Draw() {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
if (elem_count_ > 0) {
|
||||
glDrawElements(GL_TRIANGLES, elem_count_, index_type_, nullptr);
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
#if BA_DEBUG_BUILD
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if BA_DEBUG_BUILD
|
||||
std::string name_;
|
||||
#endif
|
||||
|
||||
RendererGL* renderer_{};
|
||||
uint32_t elem_count_{};
|
||||
GLuint index_type_{};
|
||||
GLuint vao_{};
|
||||
GLuint vbos_[kBufferCount]{};
|
||||
FakeVertexArrayObject* fake_vao_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_ASSET_DATA_GL_H_
|
||||
@ -0,0 +1,44 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_DUAL_TEXTURE_FULL_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_DUAL_TEXTURE_FULL_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/mesh/mesh_data_gl.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::MeshDataDualTextureFullGL : public RendererGL::MeshDataGL {
|
||||
public:
|
||||
explicit MeshDataDualTextureFullGL(RendererGL* renderer)
|
||||
: MeshDataGL(renderer, kUsesIndexBuffer) {
|
||||
// Set up our vertex data.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
sizeof(VertexDualTextureFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexDualTextureFull, uv)));
|
||||
glEnableVertexAttribArray(kVertexAttrUV);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrUV2, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
sizeof(VertexDualTextureFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexDualTextureFull, uv2)));
|
||||
glEnableVertexAttribArray(kVertexAttrUV2);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE,
|
||||
sizeof(VertexDualTextureFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexDualTextureFull, position)));
|
||||
glEnableVertexAttribArray(kVertexAttrPosition);
|
||||
}
|
||||
void SetData(MeshBuffer<VertexDualTextureFull>* data) {
|
||||
UpdateBufferData(kVertexBufferPrimary, data, &primary_state_,
|
||||
&have_primary_data_,
|
||||
dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||
}
|
||||
};
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_DUAL_TEXTURE_FULL_GL_H_
|
||||
212
src/ballistica/base/graphics/gl/mesh/mesh_data_gl.h
Normal file
212
src/ballistica/base/graphics/gl/mesh/mesh_data_gl.h
Normal file
@ -0,0 +1,212 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::MeshDataGL : public MeshRendererData {
|
||||
public:
|
||||
enum BufferType {
|
||||
kVertexBufferPrimary,
|
||||
kIndexBuffer,
|
||||
kVertexBufferSecondary
|
||||
};
|
||||
|
||||
enum Flags {
|
||||
kUsesIndexBuffer = 1u,
|
||||
kUsesSecondaryBuffer = 1u << 1u,
|
||||
kUsesDynamicDraw = 1u << 2u
|
||||
};
|
||||
|
||||
MeshDataGL(RendererGL* renderer, uint32_t flags)
|
||||
: renderer_(renderer),
|
||||
uses_secondary_data_(static_cast<bool>(flags & kUsesSecondaryBuffer)),
|
||||
uses_index_data_(static_cast<bool>(flags & kUsesIndexBuffer)) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
// Create our vertex array to hold all this state.
|
||||
|
||||
glGenVertexArrays(1, &vao_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
renderer->BindVertexArray_(vao_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
glGenBuffers(GetBufferCount(), vbos_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (uses_index_data_) {
|
||||
renderer_->BindVertexArray_(vao_);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos_[kIndexBuffer]);
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
auto uses_index_data() const -> bool { return uses_index_data_; }
|
||||
|
||||
// Set us up to be recycled.
|
||||
void Reset() {
|
||||
index_state_ = primary_state_ = secondary_state_ = 0;
|
||||
have_index_data_ = have_secondary_data_ = have_primary_data_ = false;
|
||||
}
|
||||
|
||||
void Bind() {
|
||||
renderer_->BindVertexArray_(vao_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
void Draw(DrawType draw_type) {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
assert(have_primary_data_);
|
||||
assert(have_index_data_ || !uses_index_data_);
|
||||
assert(have_secondary_data_ || !uses_secondary_data_);
|
||||
GLuint gl_draw_type;
|
||||
switch (draw_type) {
|
||||
case DrawType::kTriangles:
|
||||
gl_draw_type = GL_TRIANGLES;
|
||||
break;
|
||||
case DrawType::kPoints:
|
||||
gl_draw_type = GL_POINTS;
|
||||
break;
|
||||
default:
|
||||
throw Exception();
|
||||
}
|
||||
if (uses_index_data_) {
|
||||
glDrawElements(gl_draw_type, elem_count_, index_type_, nullptr);
|
||||
} else {
|
||||
glDrawArrays(gl_draw_type, 0, elem_count_);
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
~MeshDataGL() override {
|
||||
assert(g_base->InGraphicsThread());
|
||||
// Unbind if we're bound; otherwise we might prevent a new vao that
|
||||
// reuses our ID from binding.
|
||||
if (vao_ == renderer_->current_vertex_array_) {
|
||||
renderer_->BindVertexArray_(0);
|
||||
}
|
||||
if (!g_base->graphics_server->renderer_context_lost()) {
|
||||
glDeleteVertexArrays(1, &vao_);
|
||||
}
|
||||
|
||||
// Make sure our dying buffer isn't current (don't wanna prevent binding
|
||||
// to a new buffer with a recycled id).
|
||||
for (int i = 0; i < GetBufferCount(); i++) {
|
||||
if (vbos_[i] == renderer_->active_array_buffer_) {
|
||||
renderer_->active_array_buffer_ = -1;
|
||||
}
|
||||
}
|
||||
if (!g_base->graphics_server->renderer_context_lost()) {
|
||||
glDeleteBuffers(GetBufferCount(), vbos_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void SetIndexData(MeshIndexBuffer32* data) {
|
||||
assert(uses_index_data_);
|
||||
if (data->state != index_state_) {
|
||||
renderer_->BindVertexArray_(vao_);
|
||||
elem_count_ = static_cast<uint32_t>(data->elements.size());
|
||||
assert(elem_count_ > 0);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
static_cast_check_fit<GLsizeiptr>(
|
||||
data->elements.size() * sizeof(data->elements[0])),
|
||||
&data->elements[0],
|
||||
dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||
index_state_ = data->state;
|
||||
have_index_data_ = true;
|
||||
BA_LOG_ONCE(LogLevel::kWarning,
|
||||
"GL WARNING - USING 32 BIT INDICES WHICH WONT WORK IN ES2!!");
|
||||
index_type_ = GL_UNSIGNED_INT;
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
void SetIndexData(MeshIndexBuffer16* data) {
|
||||
assert(uses_index_data_);
|
||||
if (data->state != index_state_) {
|
||||
renderer_->BindVertexArray_(vao_);
|
||||
elem_count_ = static_cast<uint32_t>(data->elements.size());
|
||||
assert(elem_count_ > 0);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
static_cast_check_fit<GLsizeiptr>(
|
||||
data->elements.size() * sizeof(data->elements[0])),
|
||||
&data->elements[0],
|
||||
dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||
index_state_ = data->state;
|
||||
have_index_data_ = true;
|
||||
index_type_ = GL_UNSIGNED_SHORT;
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
// When dynamic-draw is on, it means *all* buffers should be flagged as
|
||||
// dynamic.
|
||||
void set_dynamic_draw(bool enable) { dynamic_draw_ = enable; }
|
||||
|
||||
auto vao() const -> GLuint { return vao_; }
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
void UpdateBufferData(BufferType buffer_type, MeshBuffer<T>* data,
|
||||
uint32_t* state, bool* have, GLuint draw_type) {
|
||||
assert(state && have);
|
||||
if (data->state != *state) {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
// Hmmm didnt think we had to have vao bound here but causes problems
|
||||
// on qualcomm if not.
|
||||
// #if BA_OSTYPE_ANDROID
|
||||
// if (g_vao_support && renderer_->is_adreno_) {
|
||||
// renderer_->BindVertexArray(vao_);
|
||||
// }
|
||||
// #endif
|
||||
renderer_->BindArrayBuffer(vbos_[buffer_type]);
|
||||
assert(!data->elements.empty());
|
||||
if (!uses_index_data_ && buffer_type == kVertexBufferPrimary) {
|
||||
elem_count_ = static_cast<uint32_t>(data->elements.size());
|
||||
}
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
static_cast<GLsizeiptr>(data->elements.size()
|
||||
* sizeof(data->elements[0])),
|
||||
&(data->elements[0]), draw_type);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
*state = data->state;
|
||||
*have = true;
|
||||
} else {
|
||||
assert(*have);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Should do some sort of ring-buffer system.
|
||||
GLuint vbos_[3]{};
|
||||
GLuint vao_{};
|
||||
auto GetBufferCount() const -> int {
|
||||
return uses_secondary_data_ ? 3 : (uses_index_data_ ? 2 : 1);
|
||||
}
|
||||
uint32_t index_state_{};
|
||||
uint32_t primary_state_{};
|
||||
uint32_t secondary_state_{};
|
||||
bool uses_index_data_{};
|
||||
bool uses_secondary_data_{};
|
||||
bool dynamic_draw_{};
|
||||
bool have_index_data_{};
|
||||
bool have_primary_data_{};
|
||||
bool have_secondary_data_{};
|
||||
RendererGL* renderer_{};
|
||||
uint32_t elem_count_{};
|
||||
GLuint index_type_{GL_UNSIGNED_SHORT};
|
||||
FakeVertexArrayObject* fake_vao_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_GL_H_
|
||||
@ -0,0 +1,53 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_OBJECT_SPLIT_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_OBJECT_SPLIT_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/mesh/mesh_data_gl.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::MeshDataObjectSplitGL : public RendererGL::MeshDataGL {
|
||||
public:
|
||||
explicit MeshDataObjectSplitGL(RendererGL* renderer)
|
||||
: MeshDataGL(renderer, kUsesSecondaryBuffer | kUsesIndexBuffer) {
|
||||
// Set up our static vertex data.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
sizeof(VertexObjectSplitStatic),
|
||||
reinterpret_cast<void*>(offsetof(VertexObjectSplitStatic, uv)));
|
||||
glEnableVertexAttribArray(kVertexAttrUV);
|
||||
|
||||
// ..and our dynamic vertex data.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertexBufferSecondary]);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE,
|
||||
sizeof(VertexObjectSplitDynamic),
|
||||
reinterpret_cast<void*>(offsetof(VertexObjectSplitDynamic, position)));
|
||||
glEnableVertexAttribArray(kVertexAttrPosition);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrNormal, 3, GL_SHORT, GL_TRUE,
|
||||
sizeof(VertexObjectSplitDynamic),
|
||||
reinterpret_cast<void*>(offsetof(VertexObjectSplitDynamic, normal)));
|
||||
glEnableVertexAttribArray(kVertexAttrNormal);
|
||||
}
|
||||
void SetStaticData(MeshBuffer<VertexObjectSplitStatic>* data) {
|
||||
UpdateBufferData(kVertexBufferPrimary, data, &primary_state_,
|
||||
&have_primary_data_, GL_STATIC_DRAW);
|
||||
}
|
||||
void SetDynamicData(MeshBuffer<VertexObjectSplitDynamic>* data) {
|
||||
assert(uses_secondary_data_);
|
||||
UpdateBufferData(kVertexBufferSecondary, data, &secondary_state_,
|
||||
&have_secondary_data_,
|
||||
GL_DYNAMIC_DRAW); // this is *always* dynamic
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_OBJECT_SPLIT_GL_H_
|
||||
@ -0,0 +1,39 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SIMPLE_FULL_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SIMPLE_FULL_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/mesh/mesh_data_gl.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::MeshDataSimpleFullGL : public RendererGL::MeshDataGL {
|
||||
public:
|
||||
explicit MeshDataSimpleFullGL(RendererGL* renderer)
|
||||
: MeshDataGL(renderer, kUsesIndexBuffer) {
|
||||
// Set up our vertex data.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(VertexSimpleFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexSimpleFull, uv)));
|
||||
glEnableVertexAttribArray(kVertexAttrUV);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexSimpleFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexSimpleFull, position)));
|
||||
glEnableVertexAttribArray(kVertexAttrPosition);
|
||||
}
|
||||
|
||||
void SetData(MeshBuffer<VertexSimpleFull>* data) {
|
||||
UpdateBufferData(kVertexBufferPrimary, data, &primary_state_,
|
||||
&have_primary_data_,
|
||||
dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SIMPLE_FULL_GL_H_
|
||||
@ -0,0 +1,48 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SIMPLE_SPLIT_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SIMPLE_SPLIT_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/mesh/mesh_data_gl.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::MeshDataSimpleSplitGL : public RendererGL::MeshDataGL {
|
||||
public:
|
||||
explicit MeshDataSimpleSplitGL(RendererGL* renderer)
|
||||
: MeshDataGL(renderer, kUsesSecondaryBuffer | kUsesIndexBuffer) {
|
||||
// Set up our static vertex data.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
sizeof(VertexSimpleSplitStatic),
|
||||
reinterpret_cast<void*>(offsetof(VertexSimpleSplitStatic, uv)));
|
||||
glEnableVertexAttribArray(kVertexAttrUV);
|
||||
|
||||
// ..and our dynamic vertex data.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertexBufferSecondary]);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE,
|
||||
sizeof(VertexSimpleSplitDynamic),
|
||||
reinterpret_cast<void*>(offsetof(VertexSimpleSplitDynamic, position)));
|
||||
glEnableVertexAttribArray(kVertexAttrPosition);
|
||||
}
|
||||
void SetStaticData(MeshBuffer<VertexSimpleSplitStatic>* data) {
|
||||
UpdateBufferData(kVertexBufferPrimary, data, &primary_state_,
|
||||
&have_primary_data_, GL_STATIC_DRAW);
|
||||
}
|
||||
void SetDynamicData(MeshBuffer<VertexSimpleSplitDynamic>* data) {
|
||||
assert(uses_secondary_data_);
|
||||
UpdateBufferData(kVertexBufferSecondary, data, &secondary_state_,
|
||||
&have_secondary_data_,
|
||||
GL_DYNAMIC_DRAW); // this is *always* dynamic
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SIMPLE_SPLIT_GL_H_
|
||||
@ -0,0 +1,51 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SMOKE_FULL_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SMOKE_FULL_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/mesh/mesh_data_gl.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::MeshDataSmokeFullGL : public RendererGL::MeshDataGL {
|
||||
public:
|
||||
explicit MeshDataSmokeFullGL(RendererGL* renderer)
|
||||
: MeshDataGL(renderer, kUsesIndexBuffer) {
|
||||
// Set up our vertex data.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrUV, 2, GL_FLOAT, GL_FALSE, sizeof(VertexSmokeFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexSmokeFull, uv)));
|
||||
glEnableVertexAttribArray(kVertexAttrUV);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexSmokeFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexSmokeFull, position)));
|
||||
glEnableVertexAttribArray(kVertexAttrPosition);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrErode, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VertexSmokeFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexSmokeFull, erode)));
|
||||
glEnableVertexAttribArray(kVertexAttrErode);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrDiffuse, 1, GL_UNSIGNED_BYTE, GL_TRUE,
|
||||
sizeof(VertexSmokeFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexSmokeFull, diffuse)));
|
||||
glEnableVertexAttribArray(kVertexAttrDiffuse);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VertexSmokeFull),
|
||||
reinterpret_cast<void*>(offsetof(VertexSmokeFull, color)));
|
||||
glEnableVertexAttribArray(kVertexAttrColor);
|
||||
}
|
||||
void SetData(MeshBuffer<VertexSmokeFull>* data) {
|
||||
UpdateBufferData(kVertexBufferPrimary, data, &primary_state_,
|
||||
&have_primary_data_,
|
||||
dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SMOKE_FULL_GL_H_
|
||||
46
src/ballistica/base/graphics/gl/mesh/mesh_data_sprite_gl.h
Normal file
46
src/ballistica/base/graphics/gl/mesh/mesh_data_sprite_gl.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SPRITE_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SPRITE_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/mesh/mesh_data_gl.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::MeshDataSpriteGL : public RendererGL::MeshDataGL {
|
||||
public:
|
||||
explicit MeshDataSpriteGL(RendererGL* renderer)
|
||||
: MeshDataGL(renderer, kUsesIndexBuffer) {
|
||||
// Set up our vertex data.
|
||||
renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexSprite),
|
||||
reinterpret_cast<void*>(offsetof(VertexSprite, position)));
|
||||
glEnableVertexAttribArray(kVertexAttrPosition);
|
||||
glVertexAttribPointer(kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
sizeof(VertexSprite),
|
||||
reinterpret_cast<void*>(offsetof(VertexSprite, uv)));
|
||||
glEnableVertexAttribArray(kVertexAttrUV);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrSize, 1, GL_FLOAT, GL_FALSE, sizeof(VertexSprite),
|
||||
reinterpret_cast<void*>(offsetof(VertexSprite, size)));
|
||||
glEnableVertexAttribArray(kVertexAttrSize);
|
||||
glVertexAttribPointer(
|
||||
kVertexAttrColor, 4, GL_FLOAT, GL_FALSE, sizeof(VertexSprite),
|
||||
reinterpret_cast<void*>(offsetof(VertexSprite, color)));
|
||||
glEnableVertexAttribArray(kVertexAttrColor);
|
||||
}
|
||||
void SetData(MeshBuffer<VertexSprite>* data) {
|
||||
UpdateBufferData(kVertexBufferPrimary, data, &primary_state_,
|
||||
&have_primary_data_,
|
||||
dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_MESH_MESH_DATA_SPRITE_GL_H_
|
||||
138
src/ballistica/base/graphics/gl/program/program_blur_gl.h
Normal file
138
src/ballistica/base/graphics/gl/program/program_blur_gl.h
Normal file
@ -0,0 +1,138 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_BLUR_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_BLUR_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/program/program_gl.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::ProgramBlurGL : public RendererGL::ProgramGL {
|
||||
public:
|
||||
enum TextureUnit {
|
||||
kColorTexUnit,
|
||||
};
|
||||
|
||||
ProgramBlurGL(RendererGL* renderer, int flags)
|
||||
: RendererGL::ProgramGL(
|
||||
renderer, Object::New<VertexShaderGL>(GetVertexCode(flags)),
|
||||
Object::New<FragmentShaderGL>(GetFragmentCode(flags)), GetName(flags),
|
||||
GetPFlags(flags)),
|
||||
flags_(flags),
|
||||
pixel_size_x_(0.0f),
|
||||
pixel_size_y_(0.0f) {
|
||||
SetTextureUnit("colorTex", kColorTexUnit);
|
||||
pixel_size_location_ = glGetUniformLocation(program(), "pixelSize");
|
||||
assert(pixel_size_location_ != -1);
|
||||
}
|
||||
|
||||
void SetPixelSize(float x, float y) {
|
||||
assert(IsBound());
|
||||
if (x != pixel_size_x_ || y != pixel_size_y_) {
|
||||
pixel_size_x_ = x;
|
||||
pixel_size_y_ = y;
|
||||
glUniform2f(pixel_size_location_, pixel_size_x_, pixel_size_y_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorTexture(const TextureAsset* t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorTexUnit);
|
||||
}
|
||||
|
||||
void SetColorTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorTexUnit);
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetName(int flags) -> std::string {
|
||||
return std::string("BlurProgramGL");
|
||||
}
|
||||
|
||||
auto GetPFlags(int flags) -> int {
|
||||
int pflags = PFLAG_USES_POSITION_ATTR | PFLAG_USES_UV_ATTR;
|
||||
return pflags;
|
||||
}
|
||||
|
||||
auto GetVertexCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform mat4 modelViewProjectionMatrix;\n" BA_GLSL_VERTEX_IN
|
||||
" vec4 position;\n" BA_GLSL_VERTEX_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 uv;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV1;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV2;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV3;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV4;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV5;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV6;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV7;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV8;\n"
|
||||
"uniform " BA_GLSL_MEDIUMP
|
||||
"vec2 pixelSize;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = modelViewProjectionMatrix*position;\n"
|
||||
" vUV1 = uv+vec2(-0.5,0)*pixelSize;\n"
|
||||
" vUV2 = uv+vec2(-1.5,0)*pixelSize;\n"
|
||||
" vUV3 = uv+vec2(0.5,0)*pixelSize;\n"
|
||||
" vUV4 = uv+vec2(1.5,0)*pixelSize;\n"
|
||||
" vUV5 = uv+vec2(-0.5,1.0)*pixelSize;\n"
|
||||
" vUV6 = uv+vec2(0.5,1.0)*pixelSize;\n"
|
||||
" vUV7 = uv+vec2(-0.5,-1.0)*pixelSize;\n"
|
||||
" vUV8 = uv+vec2(0.5,-1.0)*pixelSize;\n";
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
auto GetFragmentCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform " BA_GLSL_MEDIUMP "sampler2D colorTex;\n" BA_GLSL_FRAG_IN
|
||||
" " BA_GLSL_MEDIUMP "vec2 vUV1;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV2;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV3;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV4;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV5;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV6;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV7;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV8;\n"
|
||||
"void main() {\n"
|
||||
" " BA_GLSL_FRAGCOLOR " = 0.125*(" BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV1)\n"
|
||||
" + " BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV2)\n"
|
||||
" + " BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV3)\n"
|
||||
" + " BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV4)\n"
|
||||
" + " BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV5)\n"
|
||||
" + " BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV6)\n"
|
||||
" + " BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV7)\n"
|
||||
" + " BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV8));\n"
|
||||
"}";
|
||||
if (flags & SHD_DEBUG_PRINT) {
|
||||
Log(LogLevel::kInfo,
|
||||
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int flags_;
|
||||
GLint pixel_size_location_;
|
||||
float pixel_size_x_, pixel_size_y_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_BLUR_GL_H_
|
||||
358
src/ballistica/base/graphics/gl/program/program_gl.h
Normal file
358
src/ballistica/base/graphics/gl/program/program_gl.h
Normal file
@ -0,0 +1,358 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// Base class for fragment/vertex shaders.
|
||||
class RendererGL::ShaderGL : public Object {
|
||||
public:
|
||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
||||
return EventLoopID::kMain;
|
||||
}
|
||||
|
||||
ShaderGL(GLenum type_in, const std::string& src_in) : type_(type_in) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
assert(type_ == GL_FRAGMENT_SHADER || type_ == GL_VERTEX_SHADER);
|
||||
shader_ = glCreateShader(type_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
BA_PRECONDITION(shader_);
|
||||
#if !BA_OPENGL_IS_ES
|
||||
std::string src_fin = src_in;
|
||||
if (type_ == GL_FRAGMENT_SHADER) {
|
||||
// gl_FragColor is no more. Define our equivalent.
|
||||
src_fin = "out vec4 " BA_GLSL_FRAGCOLOR ";\n" + src_fin;
|
||||
}
|
||||
src_fin = "#version 150 core\n" + src_fin;
|
||||
#else
|
||||
std::string src_fin = src_in;
|
||||
#endif
|
||||
const char* s = src_fin.c_str();
|
||||
glShaderSource(shader_, 1, &s, nullptr);
|
||||
glCompileShader(shader_);
|
||||
GLint compile_status;
|
||||
glGetShaderiv(shader_, GL_COMPILE_STATUS, &compile_status);
|
||||
if (compile_status == GL_FALSE) {
|
||||
const char* version = (const char*)glGetString(GL_VERSION);
|
||||
const char* vendor = (const char*)glGetString(GL_VENDOR);
|
||||
const char* renderer = (const char*)glGetString(GL_RENDERER);
|
||||
// Let's not crash here. We have a better chance of calling home this
|
||||
// way and theres a chance the game will still be playable.
|
||||
Log(LogLevel::kError,
|
||||
std::string("Compile failed for ") + GetTypeName()
|
||||
+ " shader:\n------------SOURCE BEGIN-------------\n" + src_fin
|
||||
+ "\n-----------SOURCE END-------------\n" + GetInfo()
|
||||
+ "\nrenderer: " + renderer + "\nvendor: " + vendor
|
||||
+ "\nversion:" + version);
|
||||
} else {
|
||||
assert(compile_status == GL_TRUE);
|
||||
std::string info = GetInfo();
|
||||
if (!info.empty()
|
||||
&& (strstr(info.c_str(), "error:") || strstr(info.c_str(), "warning:")
|
||||
|| strstr(info.c_str(), "Error:")
|
||||
|| strstr(info.c_str(), "Warning:"))) {
|
||||
const char* version = (const char*)glGetString(GL_VERSION);
|
||||
const char* vendor = (const char*)glGetString(GL_VENDOR);
|
||||
const char* renderer = (const char*)glGetString(GL_RENDERER);
|
||||
Log(LogLevel::kError,
|
||||
std::string("WARNING: info returned for ") + GetTypeName()
|
||||
+ " shader:\n------------SOURCE BEGIN-------------\n" + src_fin
|
||||
+ "\n-----------SOURCE END-------------\n" + info
|
||||
+ "\nrenderer: " + renderer + "\nvendor: " + vendor
|
||||
+ "\nversion:" + version);
|
||||
}
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
~ShaderGL() override {
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (!g_base->graphics_server->renderer_context_lost()) {
|
||||
glDeleteShader(shader_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
auto shader() const -> GLuint { return shader_; }
|
||||
|
||||
private:
|
||||
auto GetTypeName() const -> const char* {
|
||||
if (type_ == GL_VERTEX_SHADER) {
|
||||
return "vertex";
|
||||
} else {
|
||||
return "fragment";
|
||||
}
|
||||
}
|
||||
|
||||
auto GetInfo() -> std::string {
|
||||
static char log[1024];
|
||||
GLsizei log_size;
|
||||
glGetShaderInfoLog(shader_, sizeof(log), &log_size, log);
|
||||
return log;
|
||||
}
|
||||
|
||||
std::string name_;
|
||||
GLuint shader_{};
|
||||
GLenum type_{};
|
||||
BA_DISALLOW_CLASS_COPIES(ShaderGL);
|
||||
};
|
||||
|
||||
class RendererGL::FragmentShaderGL : public RendererGL::ShaderGL {
|
||||
public:
|
||||
explicit FragmentShaderGL(const std::string& src_in)
|
||||
: ShaderGL(GL_FRAGMENT_SHADER, src_in) {}
|
||||
};
|
||||
|
||||
class RendererGL::VertexShaderGL : public RendererGL::ShaderGL {
|
||||
public:
|
||||
explicit VertexShaderGL(const std::string& src_in)
|
||||
: ShaderGL(GL_VERTEX_SHADER, src_in) {}
|
||||
};
|
||||
|
||||
class RendererGL::ProgramGL {
|
||||
public:
|
||||
ProgramGL(RendererGL* renderer,
|
||||
const Object::Ref<VertexShaderGL>& vertex_shader_in,
|
||||
const Object::Ref<FragmentShaderGL>& fragment_shader_in,
|
||||
std::string name, int pflags)
|
||||
: fragment_shader_(fragment_shader_in),
|
||||
vertex_shader_(vertex_shader_in),
|
||||
renderer_(renderer),
|
||||
pflags_(pflags),
|
||||
name_(std::move(name)) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
program_ = glCreateProgram();
|
||||
BA_PRECONDITION(program_);
|
||||
glAttachShader(program_, fragment_shader_->shader());
|
||||
glAttachShader(program_, vertex_shader_->shader());
|
||||
assert(pflags_ & PFLAG_USES_POSITION_ATTR);
|
||||
if (pflags_ & PFLAG_USES_POSITION_ATTR) {
|
||||
glBindAttribLocation(program_, kVertexAttrPosition, "position");
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_UV_ATTR) {
|
||||
glBindAttribLocation(program_, kVertexAttrUV, "uv");
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_NORMAL_ATTR) {
|
||||
glBindAttribLocation(program_, kVertexAttrNormal, "normal");
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_ERODE_ATTR) {
|
||||
glBindAttribLocation(program_, kVertexAttrErode, "erode");
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_COLOR_ATTR) {
|
||||
glBindAttribLocation(program_, kVertexAttrColor, "color");
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_SIZE_ATTR) {
|
||||
glBindAttribLocation(program_, kVertexAttrSize, "size");
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_DIFFUSE_ATTR) {
|
||||
glBindAttribLocation(program_, kVertexAttrDiffuse, "diffuse");
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_UV2_ATTR) {
|
||||
glBindAttribLocation(program_, kVertexAttrUV2, "uv2");
|
||||
}
|
||||
glLinkProgram(program_);
|
||||
GLint linkStatus;
|
||||
glGetProgramiv(program_, GL_LINK_STATUS, &linkStatus);
|
||||
if (linkStatus == GL_FALSE) {
|
||||
Log(LogLevel::kError,
|
||||
"Link failed for program '" + name_ + "':\n" + GetInfo());
|
||||
} else {
|
||||
assert(linkStatus == GL_TRUE);
|
||||
|
||||
std::string info = GetInfo();
|
||||
if (!info.empty()
|
||||
&& (strstr(info.c_str(), "error:") || strstr(info.c_str(), "warning:")
|
||||
|| strstr(info.c_str(), "Error:")
|
||||
|| strstr(info.c_str(), "Warning:"))) {
|
||||
Log(LogLevel::kError, "WARNING: program using frag shader '" + name_
|
||||
+ "' returned info:\n" + info);
|
||||
}
|
||||
}
|
||||
|
||||
// Go ahead and bind ourself so child classes can config uniforms and
|
||||
// whatnot.
|
||||
Bind();
|
||||
mvp_uniform_ = glGetUniformLocation(program_, "modelViewProjectionMatrix");
|
||||
assert(mvp_uniform_ != -1);
|
||||
if (pflags_ & PFLAG_USES_MODEL_WORLD_MATRIX) {
|
||||
model_world_matrix_uniform_ =
|
||||
glGetUniformLocation(program_, "modelWorldMatrix");
|
||||
assert(model_world_matrix_uniform_ != -1);
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_MODEL_VIEW_MATRIX) {
|
||||
model_view_matrix_uniform_ =
|
||||
glGetUniformLocation(program_, "modelViewMatrix");
|
||||
assert(model_view_matrix_uniform_ != -1);
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_CAM_POS) {
|
||||
cam_pos_uniform_ = glGetUniformLocation(program_, "camPos");
|
||||
assert(cam_pos_uniform_ != -1);
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_CAM_ORIENT_MATRIX) {
|
||||
cam_orient_matrix_uniform_ =
|
||||
glGetUniformLocation(program_, "camOrientMatrix");
|
||||
assert(cam_orient_matrix_uniform_ != -1);
|
||||
}
|
||||
if (pflags_ & PFLAG_USES_SHADOW_PROJECTION_MATRIX) {
|
||||
light_shadow_projection_matrix_uniform_ =
|
||||
glGetUniformLocation(program_, "lightShadowProjectionMatrix");
|
||||
assert(light_shadow_projection_matrix_uniform_ != -1);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~ProgramGL() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (!g_base->graphics_server->renderer_context_lost()) {
|
||||
glDetachShader(program_, fragment_shader_->shader());
|
||||
glDetachShader(program_, vertex_shader_->shader());
|
||||
glDeleteProgram(program_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
auto IsBound() const -> bool {
|
||||
return (renderer()->GetActiveProgram_() == this);
|
||||
}
|
||||
|
||||
auto program() const -> GLuint { return program_; }
|
||||
|
||||
void Bind() { renderer_->UseProgram_(this); }
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
|
||||
// Should grab matrices from the renderer or whatever else it needs in
|
||||
// prep for drawing.
|
||||
void PrepareToDraw() {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
assert(IsBound());
|
||||
|
||||
// Update matrices as necessary.
|
||||
|
||||
uint32_t mvpState =
|
||||
g_base->graphics_server->GetModelViewProjectionMatrixState();
|
||||
if (mvpState != mvp_state_) {
|
||||
mvp_state_ = mvpState;
|
||||
glUniformMatrix4fv(
|
||||
mvp_uniform_, 1, 0,
|
||||
g_base->graphics_server->GetModelViewProjectionMatrix().m);
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (pflags_ & PFLAG_USES_MODEL_WORLD_MATRIX) {
|
||||
// With world space points this would be identity; don't waste time.
|
||||
assert(!(pflags_ & PFLAG_WORLD_SPACE_PTS));
|
||||
uint32_t state = g_base->graphics_server->GetModelWorldMatrixState();
|
||||
if (state != model_world_matrix_state_) {
|
||||
model_world_matrix_state_ = state;
|
||||
glUniformMatrix4fv(model_world_matrix_uniform_, 1, 0,
|
||||
g_base->graphics_server->GetModelWorldMatrix().m);
|
||||
}
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (pflags_ & PFLAG_USES_MODEL_VIEW_MATRIX) {
|
||||
// With world space points this would be identity; don't waste time.
|
||||
assert(!(pflags_ & PFLAG_WORLD_SPACE_PTS));
|
||||
// There's no state for just modelview but this works.
|
||||
uint32_t state =
|
||||
g_base->graphics_server->GetModelViewProjectionMatrixState();
|
||||
if (state != model_view_matrix_state_) {
|
||||
model_view_matrix_state_ = state;
|
||||
glUniformMatrix4fv(model_view_matrix_uniform_, 1, 0,
|
||||
g_base->graphics_server->model_view_matrix().m);
|
||||
}
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (pflags_ & PFLAG_USES_CAM_POS) {
|
||||
uint32_t state = g_base->graphics_server->cam_pos_state();
|
||||
if (state != cam_pos_state_) {
|
||||
cam_pos_state_ = state;
|
||||
const Vector3f& p(g_base->graphics_server->cam_pos());
|
||||
glUniform4f(cam_pos_uniform_, p.x, p.y, p.z, 1.0f);
|
||||
}
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (pflags_ & PFLAG_USES_CAM_ORIENT_MATRIX) {
|
||||
uint32_t state = g_base->graphics_server->GetCamOrientMatrixState();
|
||||
if (state != cam_orient_matrix_state_) {
|
||||
cam_orient_matrix_state_ = state;
|
||||
glUniformMatrix4fv(cam_orient_matrix_uniform_, 1, 0,
|
||||
g_base->graphics_server->GetCamOrientMatrix().m);
|
||||
}
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (pflags_ & PFLAG_USES_SHADOW_PROJECTION_MATRIX) {
|
||||
uint32_t state =
|
||||
g_base->graphics_server->light_shadow_projection_matrix_state();
|
||||
if (state != light_shadow_projection_matrix_state_) {
|
||||
light_shadow_projection_matrix_state_ = state;
|
||||
glUniformMatrix4fv(
|
||||
light_shadow_projection_matrix_uniform_, 1, 0,
|
||||
g_base->graphics_server->light_shadow_projection_matrix().m);
|
||||
}
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetTextureUnit(const char* tex_name, int unit) {
|
||||
assert(IsBound());
|
||||
int c = glGetUniformLocation(program_, tex_name);
|
||||
if (c == -1) {
|
||||
Log(LogLevel::kError, "ShaderGL: " + name_
|
||||
+ ": Can't set texture unit for texture '"
|
||||
+ tex_name + "'");
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
} else {
|
||||
glUniform1i(c, unit);
|
||||
}
|
||||
}
|
||||
|
||||
auto GetInfo() -> std::string {
|
||||
static char log[1024];
|
||||
GLsizei log_size;
|
||||
glGetProgramInfoLog(program_, sizeof(log), &log_size, log);
|
||||
return log;
|
||||
}
|
||||
|
||||
auto renderer() const -> RendererGL* { return renderer_; }
|
||||
|
||||
private:
|
||||
RendererGL* renderer_{};
|
||||
Object::Ref<FragmentShaderGL> fragment_shader_;
|
||||
Object::Ref<VertexShaderGL> vertex_shader_;
|
||||
std::string name_;
|
||||
GLuint program_{};
|
||||
int pflags_{};
|
||||
uint32_t mvp_state_{};
|
||||
GLint mvp_uniform_{};
|
||||
GLint model_world_matrix_uniform_{};
|
||||
GLint model_view_matrix_uniform_{};
|
||||
GLint light_shadow_projection_matrix_uniform_{};
|
||||
uint32_t light_shadow_projection_matrix_state_{};
|
||||
uint32_t model_world_matrix_state_{};
|
||||
uint32_t model_view_matrix_state_{};
|
||||
GLint cam_pos_uniform_{};
|
||||
uint32_t cam_pos_state_{};
|
||||
GLint cam_orient_matrix_uniform_{};
|
||||
GLuint cam_orient_matrix_state_{};
|
||||
BA_DISALLOW_CLASS_COPIES(ProgramGL);
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_GL_H_
|
||||
345
src/ballistica/base/graphics/gl/program/program_object_gl.h
Normal file
345
src/ballistica/base/graphics/gl/program/program_object_gl.h
Normal file
@ -0,0 +1,345 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_OBJECT_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_OBJECT_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/program/program_gl.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::ProgramObjectGL : public RendererGL::ProgramGL {
|
||||
public:
|
||||
enum TextureUnit {
|
||||
kColorTexUnit,
|
||||
kReflectionTexUnit,
|
||||
kVignetteTexUnit,
|
||||
kLightShadowTexUnit,
|
||||
kColorizeTexUnit
|
||||
};
|
||||
|
||||
ProgramObjectGL(RendererGL* renderer, int flags)
|
||||
: RendererGL::ProgramGL(
|
||||
renderer, Object::New<VertexShaderGL>(GetVertexCode(flags)),
|
||||
Object::New<FragmentShaderGL>(GetFragmentCode(flags)), GetName(flags),
|
||||
GetPFlags(flags)),
|
||||
flags_(flags),
|
||||
r_(0),
|
||||
g_(0),
|
||||
b_(0),
|
||||
a_(0),
|
||||
colorize_r_(0),
|
||||
colorize_g_(0),
|
||||
colorize_b_(0),
|
||||
colorize_a_(0),
|
||||
colorize2_r_(0),
|
||||
colorize2_g_(0),
|
||||
colorize2_b_(0),
|
||||
colorize2_a_(0),
|
||||
add_r_(0),
|
||||
add_g_(0),
|
||||
add_b_(0),
|
||||
r_mult_r_(0),
|
||||
r_mult_g_(0),
|
||||
r_mult_b_(0),
|
||||
r_mult_a_(0) {
|
||||
SetTextureUnit("colorTex", kColorTexUnit);
|
||||
SetTextureUnit("vignetteTex", kVignetteTexUnit);
|
||||
color_location_ = glGetUniformLocation(program(), "color");
|
||||
assert(color_location_ != -1);
|
||||
if (flags & SHD_REFLECTION) {
|
||||
SetTextureUnit("reflectionTex", kReflectionTexUnit);
|
||||
reflect_mult_location_ = glGetUniformLocation(program(), "reflectMult");
|
||||
assert(reflect_mult_location_ != -1);
|
||||
}
|
||||
if (flags & SHD_LIGHT_SHADOW) {
|
||||
SetTextureUnit("lightShadowTex", kLightShadowTexUnit);
|
||||
}
|
||||
if (flags & SHD_ADD) {
|
||||
color_add_location_ = glGetUniformLocation(program(), "colorAdd");
|
||||
assert(color_add_location_ != -1);
|
||||
}
|
||||
if (flags & SHD_COLORIZE) {
|
||||
SetTextureUnit("colorizeTex", kColorizeTexUnit);
|
||||
colorize_color_location_ =
|
||||
glGetUniformLocation(program(), "colorizeColor");
|
||||
assert(colorize_color_location_ != -1);
|
||||
}
|
||||
if (flags & SHD_COLORIZE2) {
|
||||
colorize2_color_location_ =
|
||||
glGetUniformLocation(program(), "colorize2Color");
|
||||
assert(colorize2_color_location_ != -1);
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorTexture(const TextureAsset* t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorTexUnit);
|
||||
}
|
||||
|
||||
void SetReflectionTexture(const TextureAsset* t) {
|
||||
assert(flags_ & SHD_REFLECTION);
|
||||
renderer()->BindTexture_(GL_TEXTURE_CUBE_MAP, t, kReflectionTexUnit);
|
||||
}
|
||||
|
||||
void SetColor(float r, float g, float b, float a = 1.0f) {
|
||||
assert(IsBound());
|
||||
// include tint..
|
||||
if (r * renderer()->tint().x != r_ || g * renderer()->tint().y != g_
|
||||
|| b * renderer()->tint().z != b_ || a != a_) {
|
||||
r_ = r * renderer()->tint().x;
|
||||
g_ = g * renderer()->tint().y;
|
||||
b_ = b * renderer()->tint().z;
|
||||
a_ = a;
|
||||
glUniform4f(color_location_, r_, g_, b_, a_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetAddColor(float r, float g, float b) {
|
||||
assert(IsBound());
|
||||
if (r != add_r_ || g != add_g_ || b != add_b_) {
|
||||
add_r_ = r;
|
||||
add_g_ = g;
|
||||
add_b_ = b;
|
||||
glUniform4f(color_add_location_, add_r_, add_g_, add_b_, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void SetReflectionMult(float r, float g, float b, float a = 0.0f) {
|
||||
assert(IsBound());
|
||||
// include tint and ambient color...
|
||||
auto renderer = this->renderer();
|
||||
float rFin = r * renderer->tint().x * renderer->ambient_color().x;
|
||||
float gFin = g * renderer->tint().y * renderer->ambient_color().y;
|
||||
float bFin = b * renderer->tint().z * renderer->ambient_color().z;
|
||||
if (rFin != r_mult_r_ || gFin != r_mult_g_ || bFin != r_mult_b_
|
||||
|| a != r_mult_a_) {
|
||||
r_mult_r_ = rFin;
|
||||
r_mult_g_ = gFin;
|
||||
r_mult_b_ = bFin;
|
||||
r_mult_a_ = a;
|
||||
assert(flags_ & SHD_REFLECTION);
|
||||
glUniform4f(reflect_mult_location_, r_mult_r_, r_mult_g_, r_mult_b_,
|
||||
r_mult_a_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetVignetteTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kVignetteTexUnit);
|
||||
}
|
||||
|
||||
void SetLightShadowTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kLightShadowTexUnit);
|
||||
}
|
||||
|
||||
void SetColorizeColor(float r, float g, float b, float a = 1.0f) {
|
||||
assert(flags_ & SHD_COLORIZE);
|
||||
assert(IsBound());
|
||||
if (r != colorize_r_ || g != colorize_g_ || b != colorize_b_
|
||||
|| a != colorize_a_) {
|
||||
colorize_r_ = r;
|
||||
colorize_g_ = g;
|
||||
colorize_b_ = b;
|
||||
colorize_a_ = a;
|
||||
glUniform4f(colorize_color_location_, colorize_r_, colorize_g_,
|
||||
colorize_b_, colorize_a_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorize2Color(float r, float g, float b, float a = 1.0f) {
|
||||
assert(flags_ & SHD_COLORIZE2);
|
||||
assert(IsBound());
|
||||
if (r != colorize2_r_ || g != colorize2_g_ || b != colorize2_b_
|
||||
|| a != colorize2_a_) {
|
||||
colorize2_r_ = r;
|
||||
colorize2_g_ = g;
|
||||
colorize2_b_ = b;
|
||||
colorize2_a_ = a;
|
||||
glUniform4f(colorize2_color_location_, colorize2_r_, colorize2_g_,
|
||||
colorize2_b_, colorize2_a_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorizeTexture(const TextureAsset* t) {
|
||||
assert(flags_ & SHD_COLORIZE);
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorizeTexUnit);
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetName(int flags) -> std::string {
|
||||
return std::string("ProgramObjectGL")
|
||||
+ " reflect:" + std::to_string((flags & SHD_REFLECTION) != 0)
|
||||
+ " lightShadow:" + std::to_string((flags & SHD_LIGHT_SHADOW) != 0)
|
||||
+ " add:" + std::to_string((flags & SHD_ADD) != 0) + " colorize:"
|
||||
+ std::to_string((flags & SHD_COLORIZE) != 0) + " colorize2:"
|
||||
+ std::to_string((flags & SHD_COLORIZE2) != 0) + " transparent:"
|
||||
+ std::to_string((flags & SHD_OBJ_TRANSPARENT) != 0) + " worldSpace:"
|
||||
+ std::to_string((flags & SHD_WORLD_SPACE_PTS) != 0);
|
||||
}
|
||||
|
||||
auto GetPFlags(int flags) -> int {
|
||||
int pflags = PFLAG_USES_POSITION_ATTR | PFLAG_USES_UV_ATTR;
|
||||
if (flags & SHD_REFLECTION)
|
||||
pflags |= (PFLAG_USES_NORMAL_ATTR | PFLAG_USES_CAM_POS);
|
||||
if (((flags & SHD_REFLECTION) || (flags & SHD_LIGHT_SHADOW))
|
||||
&& !(flags & SHD_WORLD_SPACE_PTS))
|
||||
pflags |= PFLAG_USES_MODEL_WORLD_MATRIX;
|
||||
if (flags & SHD_LIGHT_SHADOW) pflags |= PFLAG_USES_SHADOW_PROJECTION_MATRIX;
|
||||
if (flags & SHD_WORLD_SPACE_PTS) pflags |= PFLAG_WORLD_SPACE_PTS;
|
||||
return pflags;
|
||||
}
|
||||
|
||||
auto GetVertexCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform mat4 modelViewProjectionMatrix;\n"
|
||||
"uniform vec4 camPos;\n" BA_GLSL_VERTEX_IN
|
||||
" vec4 position;\n" BA_GLSL_VERTEX_IN " " BA_GLSL_LOWP
|
||||
"vec2 uv;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_LOWP
|
||||
"vec2 vUV;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec4 vScreenCoord;\n";
|
||||
if ((flags & SHD_REFLECTION) || (flags & SHD_LIGHT_SHADOW))
|
||||
s += "uniform mat4 modelWorldMatrix;\n";
|
||||
if (flags & SHD_REFLECTION)
|
||||
s += BA_GLSL_VERTEX_IN " " BA_GLSL_MEDIUMP
|
||||
"vec3 normal;\n" BA_GLSL_VERTEX_OUT
|
||||
" " BA_GLSL_MEDIUMP "vec3 vReflect;\n";
|
||||
if (flags & SHD_LIGHT_SHADOW)
|
||||
s += "uniform mat4 lightShadowProjectionMatrix;\n" BA_GLSL_VERTEX_OUT
|
||||
" " BA_GLSL_MEDIUMP "vec4 vLightShadowUV;\n";
|
||||
s +=
|
||||
"void main() {\n"
|
||||
" vUV = uv;\n"
|
||||
" gl_Position = modelViewProjectionMatrix*position;\n"
|
||||
" vScreenCoord = vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n"
|
||||
" vScreenCoord.xy += vec2(1.0);\n"
|
||||
" vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n";
|
||||
if (((flags & SHD_LIGHT_SHADOW) || (flags & SHD_REFLECTION))
|
||||
&& !(flags & SHD_WORLD_SPACE_PTS)) {
|
||||
s += " vec4 worldPos = modelWorldMatrix*position;\n";
|
||||
}
|
||||
if (flags & SHD_LIGHT_SHADOW) {
|
||||
if (flags & SHD_WORLD_SPACE_PTS)
|
||||
s += " vLightShadowUV = (lightShadowProjectionMatrix*position);\n";
|
||||
else
|
||||
s += " vLightShadowUV = (lightShadowProjectionMatrix*worldPos);\n";
|
||||
}
|
||||
if (flags & SHD_REFLECTION) {
|
||||
if (flags & SHD_WORLD_SPACE_PTS)
|
||||
s += " vReflect = reflect(vec3(position - camPos),normal);\n";
|
||||
else
|
||||
s += " vReflect = reflect(vec3(worldPos - "
|
||||
"camPos),normalize(vec3(modelWorldMatrix * vec4(normal,0.0))));\n";
|
||||
}
|
||||
s += "}";
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
auto GetFragmentCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform " BA_GLSL_LOWP
|
||||
"sampler2D colorTex;\n"
|
||||
"uniform " BA_GLSL_LOWP
|
||||
"sampler2D vignetteTex;\n"
|
||||
"uniform " BA_GLSL_LOWP "vec4 color;\n" BA_GLSL_FRAG_IN " " BA_GLSL_LOWP
|
||||
"vec2 vUV;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec4 vScreenCoord;\n";
|
||||
if (flags & SHD_ADD) {
|
||||
s += "uniform " BA_GLSL_LOWP "vec4 colorAdd;\n";
|
||||
}
|
||||
if (flags & SHD_REFLECTION) {
|
||||
s += "uniform " BA_GLSL_LOWP
|
||||
"samplerCube reflectionTex;\n" BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec3 vReflect;\n"
|
||||
"uniform " BA_GLSL_LOWP "vec4 reflectMult;\n";
|
||||
}
|
||||
if (flags & SHD_COLORIZE) {
|
||||
s += "uniform " BA_GLSL_LOWP
|
||||
"sampler2D colorizeTex;\n"
|
||||
"uniform " BA_GLSL_LOWP "vec4 colorizeColor;\n";
|
||||
}
|
||||
if (flags & SHD_COLORIZE2) {
|
||||
s += "uniform " BA_GLSL_LOWP "vec4 colorize2Color;\n";
|
||||
}
|
||||
if (flags & SHD_LIGHT_SHADOW) {
|
||||
s += "uniform " BA_GLSL_LOWP "sampler2D lightShadowTex;\n" BA_GLSL_FRAG_IN
|
||||
" " BA_GLSL_MEDIUMP "vec4 vLightShadowUV;\n";
|
||||
}
|
||||
s += "void main() {\n";
|
||||
if (flags & SHD_LIGHT_SHADOW) {
|
||||
s += " " BA_GLSL_LOWP "vec4 lightShadVal = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(lightShadowTex, vLightShadowUV);\n";
|
||||
}
|
||||
if ((flags & SHD_COLORIZE) || (flags & SHD_COLORIZE2)) {
|
||||
s += " " BA_GLSL_LOWP "vec4 colorizeVal = " BA_GLSL_TEXTURE2D
|
||||
"(colorizeTex, vUV);\n";
|
||||
}
|
||||
if (flags & SHD_COLORIZE) {
|
||||
s += " " BA_GLSL_LOWP "float colorizeA = colorizeVal.r;\n";
|
||||
}
|
||||
if (flags & SHD_COLORIZE2) {
|
||||
s += " " BA_GLSL_LOWP "float colorizeB = colorizeVal.g;\n";
|
||||
}
|
||||
s += " " BA_GLSL_FRAGCOLOR " = (color * " BA_GLSL_TEXTURE2D
|
||||
"(colorTex, vUV)";
|
||||
if (flags & SHD_COLORIZE) {
|
||||
s += " * (vec4(1.0-colorizeA)+colorizeColor*colorizeA)";
|
||||
}
|
||||
if (flags & SHD_COLORIZE2) {
|
||||
s += " * (vec4(1.0-colorizeB)+colorize2Color*colorizeB)";
|
||||
}
|
||||
s += ")";
|
||||
|
||||
// add in lights/shadows
|
||||
if (flags & SHD_LIGHT_SHADOW) {
|
||||
if (flags & SHD_OBJ_TRANSPARENT) {
|
||||
s += " * vec4((2.0 * lightShadVal).rgb, 1) + "
|
||||
"vec4((lightShadVal - 0.5).rgb,0)";
|
||||
} else {
|
||||
s += " * (2.0 * lightShadVal) + (lightShadVal - 0.5)";
|
||||
}
|
||||
}
|
||||
|
||||
// add glow and reflection
|
||||
if (flags & SHD_REFLECTION)
|
||||
s += " + (reflectMult*" BA_GLSL_TEXTURECUBE "(reflectionTex, vReflect))";
|
||||
if (flags & SHD_ADD) s += " + colorAdd";
|
||||
|
||||
// subtract vignette
|
||||
s += " - vec4(" BA_GLSL_TEXTURE2DPROJ "(vignetteTex, vScreenCoord).rgb,0)";
|
||||
|
||||
s += ";\n";
|
||||
// s += BA_GLSL_FRAGCOLOR " = 0.999 * " BA_GLSL_TEXTURE2DPROJ
|
||||
// "(vignetteTex,vScreenCoord)
|
||||
// + 0.01 * BA_GLSL_FRAGCOLOR ";";
|
||||
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
float r_, g_, b_, a_;
|
||||
float colorize_r_, colorize_g_, colorize_b_, colorize_a_;
|
||||
float colorize2_r_, colorize2_g_, colorize2_b_, colorize2_a_;
|
||||
float add_r_, add_g_, add_b_;
|
||||
float r_mult_r_, r_mult_g_, r_mult_b_, r_mult_a_;
|
||||
GLint color_location_;
|
||||
GLint colorize_color_location_;
|
||||
GLint colorize2_color_location_;
|
||||
GLint color_add_location_;
|
||||
GLint reflect_mult_location_;
|
||||
int flags_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_OBJECT_GL_H_
|
||||
@ -0,0 +1,327 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_POST_PROCESS_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_POST_PROCESS_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/program/program_gl.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::ProgramPostProcessGL : public RendererGL::ProgramGL {
|
||||
public:
|
||||
enum TextureUnit {
|
||||
kColorTexUnit,
|
||||
kDepthTexUnit,
|
||||
kColorSlightBlurredTexUnit,
|
||||
kColorBlurredTexUnit,
|
||||
kColorBlurredMoreTexUnit
|
||||
};
|
||||
|
||||
ProgramPostProcessGL(RendererGL* renderer, int flags)
|
||||
: RendererGL::ProgramGL(
|
||||
renderer, Object::New<VertexShaderGL>(GetVertexCode(flags)),
|
||||
Object::New<FragmentShaderGL>(GetFragmentCode(flags)), GetName(flags),
|
||||
GetPFlags(flags)),
|
||||
flags_(flags),
|
||||
dof_near_min_(0),
|
||||
dof_near_max_(0),
|
||||
dof_far_min_(0),
|
||||
dof_far_max_(0),
|
||||
distort_(0.0f) {
|
||||
SetTextureUnit("colorTex", kColorTexUnit);
|
||||
|
||||
if (UsesSlightBlurredTex()) {
|
||||
SetTextureUnit("colorSlightBlurredTex", kColorSlightBlurredTexUnit);
|
||||
}
|
||||
if (UsesBlurredTexture()) {
|
||||
SetTextureUnit("colorBlurredTex", kColorBlurredTexUnit);
|
||||
}
|
||||
SetTextureUnit("colorBlurredMoreTex", kColorBlurredMoreTexUnit);
|
||||
SetTextureUnit("depthTex", kDepthTexUnit);
|
||||
|
||||
dof_location_ = glGetUniformLocation(program(), "dofRange");
|
||||
assert(dof_location_ != -1);
|
||||
|
||||
if (flags & SHD_DISTORT) {
|
||||
distort_location_ = glGetUniformLocation(program(), "distort");
|
||||
assert(distort_location_ != -1);
|
||||
}
|
||||
}
|
||||
|
||||
auto UsesSlightBlurredTex() -> bool {
|
||||
return static_cast<bool>(flags_ & SHD_EYES);
|
||||
}
|
||||
auto UsesBlurredTexture() -> bool {
|
||||
return static_cast<bool>(flags_ & (SHD_HIGHER_QUALITY | SHD_EYES));
|
||||
}
|
||||
void SetColorTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorTexUnit);
|
||||
}
|
||||
void SetColorSlightBlurredTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorSlightBlurredTexUnit);
|
||||
}
|
||||
void SetColorBlurredMoreTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorBlurredMoreTexUnit);
|
||||
}
|
||||
void SetColorBlurredTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorBlurredTexUnit);
|
||||
}
|
||||
void SetDepthTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kDepthTexUnit);
|
||||
}
|
||||
|
||||
void SetDepthOfFieldRanges(float near_min, float near_max, float far_min,
|
||||
float far_max) {
|
||||
assert(IsBound());
|
||||
if (near_min != dof_near_min_ || near_max != dof_near_max_
|
||||
|| far_min != dof_far_min_ || far_max != dof_far_max_) {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
dof_near_min_ = near_min;
|
||||
dof_near_max_ = near_max;
|
||||
dof_far_min_ = far_min;
|
||||
dof_far_max_ = far_max;
|
||||
float vals[4] = {dof_near_min_, dof_near_max_, dof_far_min_,
|
||||
dof_far_max_};
|
||||
glUniform1fv(dof_location_, 4, vals);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDistort(float distort) {
|
||||
assert(IsBound());
|
||||
assert(flags_ & SHD_DISTORT);
|
||||
if (distort != distort_) {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
distort_ = distort;
|
||||
glUniform1f(distort_location_, distort_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetName(int flags) -> std::string {
|
||||
return std::string("PostProcessProgramGL");
|
||||
}
|
||||
|
||||
auto GetPFlags(int flags) -> int {
|
||||
int pflags = PFLAG_USES_POSITION_ATTR;
|
||||
if (flags & SHD_DISTORT) {
|
||||
pflags |= (PFLAG_USES_NORMAL_ATTR | PFLAG_USES_MODEL_VIEW_MATRIX);
|
||||
}
|
||||
return pflags;
|
||||
}
|
||||
|
||||
auto GetVertexCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform mat4 modelViewProjectionMatrix;\n" BA_GLSL_VERTEX_IN
|
||||
" vec4 position;\n";
|
||||
if (flags & SHD_DISTORT)
|
||||
s += BA_GLSL_VERTEX_IN " " BA_GLSL_LOWP
|
||||
"vec3 normal;\n"
|
||||
"uniform mat4 modelViewMatrix;\n"
|
||||
"uniform float distort;\n";
|
||||
if (flags & SHD_EYES) {
|
||||
s += BA_GLSL_VERTEX_OUT " " BA_GLSL_HIGHP "float calcedDepth;\n";
|
||||
}
|
||||
|
||||
s += BA_GLSL_VERTEX_OUT
|
||||
" " BA_GLSL_MEDIUMP
|
||||
"vec4 vScreenCoord;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = modelViewProjectionMatrix*position;\n";
|
||||
if (flags & SHD_DISTORT) {
|
||||
s += " float eyeDot = "
|
||||
"abs(normalize(modelViewMatrix*vec4(normal,0.0))).z;\n"
|
||||
" vec4 posDistorted = "
|
||||
"modelViewProjectionMatrix*(position-eyeDot*distort*vec4(normal,0));"
|
||||
"\n"
|
||||
" vScreenCoord = "
|
||||
"vec4(posDistorted.xy/posDistorted.w,posDistorted.zw);\n"
|
||||
" vScreenCoord.xy += vec2(1.0);\n"
|
||||
" vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n";
|
||||
} else {
|
||||
s += " vScreenCoord = "
|
||||
"vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n"
|
||||
" vScreenCoord.xy += vec2(1.0);\n"
|
||||
" vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n";
|
||||
}
|
||||
if (flags & SHD_EYES) {
|
||||
s += " calcedDepth = " + std::to_string(kBackingDepth3) + "+"
|
||||
+ std::to_string(kBackingDepth4 - kBackingDepth3)
|
||||
+ "*(0.5*(gl_Position.z/gl_Position.w)+0.5);\n";
|
||||
}
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
auto GetFragmentCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform " BA_GLSL_LOWP
|
||||
"sampler2D colorTex;\n"
|
||||
"uniform " BA_GLSL_LOWP
|
||||
"sampler2D colorBlurredMoreTex;\n"
|
||||
"uniform " BA_GLSL_HIGHP "sampler2D depthTex;\n" BA_GLSL_FRAG_IN
|
||||
" " BA_GLSL_MEDIUMP
|
||||
"vec4 vScreenCoord;\n"
|
||||
"uniform " BA_GLSL_LOWP "float dofRange[4];\n";
|
||||
if (flags & (SHD_HIGHER_QUALITY | SHD_EYES)) {
|
||||
s += "uniform " BA_GLSL_LOWP "sampler2D colorBlurredTex;\n";
|
||||
}
|
||||
if (flags & SHD_EYES) {
|
||||
s += "uniform " BA_GLSL_LOWP
|
||||
"sampler2D colorSlightBlurredTex;\n" BA_GLSL_FRAG_IN
|
||||
" " BA_GLSL_HIGHP "float calcedDepth;\n";
|
||||
}
|
||||
|
||||
s += "void main() {\n"
|
||||
" " BA_GLSL_MEDIUMP "float depth = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(depthTex,vScreenCoord).r;\n";
|
||||
|
||||
bool doConditional = ((flags & SHD_CONDITIONAL) && !(flags & (SHD_EYES)));
|
||||
|
||||
if (doConditional) {
|
||||
// special-case completely out of focus areas and completely in-focus
|
||||
// areas.
|
||||
s += " if (depth > dofRange[1] && depth < dofRange[2]) {\n";
|
||||
if (flags & SHD_HIGHER_QUALITY) {
|
||||
s += " " BA_GLSL_LOWP "vec4 color = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorTex,vScreenCoord);\n"
|
||||
" " BA_GLSL_LOWP "vec4 colorBlurred = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorBlurredTex,vScreenCoord);\n"
|
||||
" " BA_GLSL_LOWP
|
||||
"vec4 colorBlurredMore = "
|
||||
"0.4*" BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorBlurredMoreTex,vScreenCoord);\n"
|
||||
" " BA_GLSL_MEDIUMP
|
||||
"vec4 diff = colorBlurred-color;\n"
|
||||
" diff = sign(diff) * max(vec4(0.0),abs(diff)-0.12);\n"
|
||||
" " BA_GLSL_FRAGCOLOR
|
||||
" = (0.55*colorBlurredMore) + "
|
||||
"(0.62+colorBlurredMore)*(color-diff);\n\n";
|
||||
} else {
|
||||
s += " " BA_GLSL_FRAGCOLOR " = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorTex,vScreenCoord);\n";
|
||||
}
|
||||
s += " }\n"
|
||||
" else if (depth < dofRange[0] || depth > dofRange[3]) {\n";
|
||||
if (flags & SHD_HIGHER_QUALITY) {
|
||||
s += " " BA_GLSL_LOWP "vec4 colorBlurred = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorBlurredTex,vScreenCoord);\n"
|
||||
" " BA_GLSL_LOWP
|
||||
"vec4 colorBlurredMore = "
|
||||
"0.4*" BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorBlurredMoreTex,vScreenCoord);\n"
|
||||
" " BA_GLSL_FRAGCOLOR
|
||||
" = (0.55*colorBlurredMore) + "
|
||||
"(0.62+colorBlurredMore)*colorBlurred;\n\n";
|
||||
} else {
|
||||
s += " " BA_GLSL_FRAGCOLOR
|
||||
" = "
|
||||
"" BA_GLSL_TEXTURE2DPROJ "(colorBlurredMoreTex,vScreenCoord);\n";
|
||||
}
|
||||
s += " }\n"
|
||||
" else{\n";
|
||||
}
|
||||
|
||||
// Transition areas.
|
||||
s += " " BA_GLSL_LOWP "vec4 color = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorTex,vScreenCoord);\n";
|
||||
if (flags & SHD_EYES)
|
||||
s += " " BA_GLSL_LOWP
|
||||
"vec4 colorSlightBlurred = "
|
||||
"" BA_GLSL_TEXTURE2DPROJ "(colorSlightBlurredTex,vScreenCoord);\n";
|
||||
|
||||
// FIXME: Should make proper blur work in VR (perhaps just pass a uniform?
|
||||
// FIXME2: This will break 2D mode on the VR build.
|
||||
// #if BA_VR_BUILD
|
||||
// #define BLURSCALE "0.3 * "
|
||||
// #else
|
||||
#define BLURSCALE
|
||||
// #endif
|
||||
|
||||
if (flags & (SHD_HIGHER_QUALITY | SHD_EYES)) {
|
||||
s += " " BA_GLSL_LOWP "vec4 colorBlurred = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorBlurredTex,vScreenCoord);\n"
|
||||
" " BA_GLSL_LOWP
|
||||
"vec4 colorBlurredMore = "
|
||||
"0.4*" BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorBlurredMoreTex,vScreenCoord);\n"
|
||||
" " BA_GLSL_LOWP "float blur = " BLURSCALE
|
||||
" (smoothstep(dofRange[2],dofRange[3],depth)\n"
|
||||
" + 1.0 - "
|
||||
"smoothstep(dofRange[0],dofRange[1],depth));\n"
|
||||
" " BA_GLSL_MEDIUMP
|
||||
"vec4 diff = colorBlurred-color;\n"
|
||||
" diff = sign(diff) * max(vec4(0.0),abs(diff)-0.12);\n"
|
||||
" " BA_GLSL_FRAGCOLOR
|
||||
" = (0.55*colorBlurredMore) + "
|
||||
"(0.62+colorBlurredMore)*mix(color-diff,colorBlurred,blur);\n\n";
|
||||
} else {
|
||||
s += " " BA_GLSL_LOWP
|
||||
"vec4 colorBlurredMore = "
|
||||
"" BA_GLSL_TEXTURE2DPROJ
|
||||
"(colorBlurredMoreTex,vScreenCoord);\n"
|
||||
" " BA_GLSL_LOWP "float blur = " BLURSCALE
|
||||
" (smoothstep(dofRange[2],dofRange[3],depth)\n"
|
||||
" + 1.0 - "
|
||||
"smoothstep(dofRange[0],dofRange[1],depth));\n"
|
||||
" " BA_GLSL_FRAGCOLOR " = mix(color,colorBlurredMore,blur);\n\n";
|
||||
}
|
||||
|
||||
#undef BLURSCALE
|
||||
|
||||
if (flags & SHD_EYES) {
|
||||
s += " " BA_GLSL_MEDIUMP "vec4 diffEye = colorBlurred-color;\n";
|
||||
s += " diffEye = sign(diffEye) * max(vec4(0.0),abs(diffEye)-0.06);\n";
|
||||
s += " " BA_GLSL_LOWP
|
||||
"vec4 baseColorEye = "
|
||||
"mix(color-10.0*(diffEye),colorSlightBlurred,0.83);\n";
|
||||
s += " " BA_GLSL_LOWP
|
||||
"vec4 eyeColor = (0.55*colorBlurredMore) + "
|
||||
"(0.62+colorBlurredMore)*mix(baseColorEye,colorBlurred,blur);\n\n";
|
||||
s += " " BA_GLSL_LOWP
|
||||
"float dBlend = smoothstep(-0.0004,-0.0001,depth-calcedDepth);\n"
|
||||
" " BA_GLSL_FRAGCOLOR " = mix(" BA_GLSL_FRAGCOLOR
|
||||
",eyeColor,dBlend);\n";
|
||||
}
|
||||
if (doConditional) {
|
||||
s += " }\n";
|
||||
}
|
||||
|
||||
// Demonstrates MSAA striation issue:
|
||||
// s += " gl_FragColor =
|
||||
// mix(gl_FragColor,vec4(vec3(14.0*(depth-0.76)),1),0.999);\n";
|
||||
// s += " gl_FragColor =
|
||||
// vec4(vec3(14.0*(" BA_GLSL_TEXTURE2DPROJ
|
||||
// "(depthTex,vScreenCoord).r-0.76)),1);\n";
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
int flags_;
|
||||
float dof_near_min_;
|
||||
float dof_near_max_;
|
||||
float dof_far_min_;
|
||||
float dof_far_max_;
|
||||
GLint dof_location_;
|
||||
float distort_;
|
||||
GLint distort_location_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_POST_PROCESS_GL_H_
|
||||
128
src/ballistica/base/graphics/gl/program/program_shield_gl.h
Normal file
128
src/ballistica/base/graphics/gl/program/program_shield_gl.h
Normal file
@ -0,0 +1,128 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SHIELD_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SHIELD_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/program/program_gl.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::ProgramShieldGL : public RendererGL::ProgramGL {
|
||||
public:
|
||||
enum TextureUnit {
|
||||
kDepthTexUnit,
|
||||
};
|
||||
|
||||
ProgramShieldGL(RendererGL* renderer, int flags)
|
||||
: RendererGL::ProgramGL(
|
||||
renderer, Object::New<VertexShaderGL>(GetVertexCode(flags)),
|
||||
Object::New<FragmentShaderGL>(GetFragmentCode(flags)), GetName(flags),
|
||||
GetPFlags(flags)),
|
||||
flags_(flags) {
|
||||
SetTextureUnit("depthTex", kDepthTexUnit);
|
||||
}
|
||||
void SetDepthTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kDepthTexUnit);
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetName(int flags) -> std::string {
|
||||
return std::string("ShieldProgramGL");
|
||||
}
|
||||
|
||||
auto GetPFlags(int flags) -> int {
|
||||
int pflags = PFLAG_USES_POSITION_ATTR;
|
||||
return pflags;
|
||||
}
|
||||
|
||||
auto GetVertexCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform mat4 modelViewProjectionMatrix;\n" BA_GLSL_VERTEX_IN
|
||||
" vec4 position;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_HIGHP
|
||||
"vec4 vScreenCoord;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = modelViewProjectionMatrix * position;\n"
|
||||
" vScreenCoord = vec4(gl_Position.xy / gl_Position.w,"
|
||||
" gl_Position.zw);\n"
|
||||
" vScreenCoord.xy += vec2(1.0);\n"
|
||||
" vScreenCoord.xy *= vec2(0.5 * vScreenCoord.w);\n";
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
auto GetFragmentCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform " BA_GLSL_HIGHP "sampler2D depthTex;\n" BA_GLSL_FRAG_IN
|
||||
" " BA_GLSL_HIGHP
|
||||
"vec4 vScreenCoord;\n"
|
||||
"void main() {\n"
|
||||
" " BA_GLSL_HIGHP "float depth = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(depthTex, vScreenCoord).r;\n";
|
||||
|
||||
// Work around Adreno bug where depth is returned as 0..1 instead of
|
||||
// glDepthRange().
|
||||
if (GetFunkyDepthIssue_()) {
|
||||
s += " depth = " + std::to_string(kBackingDepth3) + " + depth * ("
|
||||
+ std::to_string(kBackingDepth4) + "-"
|
||||
+ std::to_string(kBackingDepth3) + ");\n";
|
||||
}
|
||||
// s+= " depth =
|
||||
// "+std::to_string(kBackingDepth3)+"0.15+depth*(0.9-0.15);\n"; " depth
|
||||
// *=
|
||||
// 0.936;\n" " depth = 1.0/(65535.0*((1.0/depth)/16777216.0));\n" " depth
|
||||
//= 1.0/((1.0/depth)+0.08);\n" " depth += 0.1f;\n"
|
||||
s += " " BA_GLSL_HIGHP
|
||||
"float d = abs(depth - gl_FragCoord.z);\n"
|
||||
" d = 1.0 - smoothstep(0.0, 0.0006, d);\n"
|
||||
" d = 0.2 * smoothstep(0.96, 1.0, d)"
|
||||
" + 0.2 * d + 0.4 * d * d * d;\n";
|
||||
|
||||
// Some mali chips seem to have no high precision and thus this looks
|
||||
// terrible; in those cases lets done down the intersection effect
|
||||
// significantly
|
||||
// if (GetDrawsShieldsFunny_()) {
|
||||
// s += " " BA_GLSL_FRAGCOLOR " = vec4(d*0.13,d*0.1,d,0);\n";
|
||||
// } else {
|
||||
s += " " BA_GLSL_FRAGCOLOR " = vec4(d*0.5, d*0.4, d, 0);\n";
|
||||
// }
|
||||
s += "}";
|
||||
|
||||
// This shows msaa depth error on bridgit.
|
||||
//" " BA_GLSL_FRAGCOLOR " =
|
||||
// vec4(smoothstep(0.73,0.77,depth),0.0,0.0,0.5);\n"
|
||||
|
||||
// " d = 1.0 - smoothstep(0.0,0.0006,d);\n"
|
||||
// " d = 0.2*smoothstep(0.96,1.0,d)+0.2*d+0.4*d*d*d;\n"
|
||||
//" if (d < 0.01) " BA_GLSL_FRAGCOLOR " = vec4(0.0,1.0,0.0,0.5);\n"
|
||||
|
||||
//" " BA_GLSL_FRAGCOLOR " =
|
||||
// vec4(vec3(10.0*abs(depth-gl_FragCoord.z)),1);\n"
|
||||
// " " BA_GLSL_FRAGCOLOR " =
|
||||
// vec4(0,10.0*abs(depth-gl_FragCoord.z),0,0.1);\n" " if (depth <
|
||||
// gl_FragCoord.z) " BA_GLSL_FRAGCOLOR " =
|
||||
// vec4(1.0-10.0*(gl_FragCoord.z-depth),0,0,1);\n" " else "
|
||||
// BA_GLSL_FRAGCOLOR " = vec4(0,1.0-10.0*(depth-gl_FragCoord.z),0,1);\n"
|
||||
//" " BA_GLSL_FRAGCOLOR " = vec4(vec3(depth),1);\n"
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
int flags_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SHIELD_GL_H_
|
||||
413
src/ballistica/base/graphics/gl/program/program_simple_gl.h
Normal file
413
src/ballistica/base/graphics/gl/program/program_simple_gl.h
Normal file
@ -0,0 +1,413 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SIMPLE_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SIMPLE_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/program/program_gl.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
class RendererGL::ProgramSimpleGL : public RendererGL::ProgramGL {
|
||||
public:
|
||||
enum TextureUnit {
|
||||
kColorTexUnit,
|
||||
kColorizeTexUnit,
|
||||
kMaskTexUnit,
|
||||
kMaskUV2TexUnit,
|
||||
kBlurTexUnit
|
||||
};
|
||||
|
||||
ProgramSimpleGL(RendererGL* renderer, int flags)
|
||||
: RendererGL::ProgramGL(
|
||||
renderer, Object::New<VertexShaderGL>(GetVertexCode(flags)),
|
||||
Object::New<FragmentShaderGL>(GetFragmentCode(flags)), GetName(flags),
|
||||
GetPFlags(flags)),
|
||||
flags_(flags) {
|
||||
if (flags & SHD_TEXTURE) {
|
||||
SetTextureUnit("colorTex", kColorTexUnit);
|
||||
}
|
||||
if (flags & SHD_COLORIZE) {
|
||||
SetTextureUnit("colorizeTex", kColorizeTexUnit);
|
||||
colorize_color_location_ =
|
||||
glGetUniformLocation(program(), "colorizeColor");
|
||||
assert(colorize_color_location_ != -1);
|
||||
}
|
||||
if (flags & SHD_COLORIZE2) {
|
||||
colorize2_color_location_ =
|
||||
glGetUniformLocation(program(), "colorize2Color");
|
||||
assert(colorize2_color_location_ != -1);
|
||||
}
|
||||
if ((!(flags & SHD_TEXTURE)) || (flags & SHD_MODULATE)) {
|
||||
color_location_ = glGetUniformLocation(program(), "color");
|
||||
assert(color_location_ != -1);
|
||||
}
|
||||
if (flags & SHD_SHADOW) {
|
||||
shadow_params_location_ = glGetUniformLocation(program(), "shadowParams");
|
||||
assert(shadow_params_location_ != -1);
|
||||
}
|
||||
if (flags & SHD_GLOW) {
|
||||
glow_params_location_ = glGetUniformLocation(program(), "glowParams");
|
||||
assert(glow_params_location_ != -1);
|
||||
}
|
||||
if (flags & SHD_FLATNESS) {
|
||||
flatness_location = glGetUniformLocation(program(), "flatness");
|
||||
assert(flatness_location != -1);
|
||||
}
|
||||
if (flags & SHD_MASKED) {
|
||||
SetTextureUnit("maskTex", kMaskTexUnit);
|
||||
}
|
||||
if (flags & SHD_MASK_UV2) {
|
||||
SetTextureUnit("maskUV2Tex", kMaskUV2TexUnit);
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorTexture(const TextureAsset* t) {
|
||||
assert(flags_ & SHD_TEXTURE);
|
||||
assert(IsBound());
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorTexUnit);
|
||||
}
|
||||
|
||||
void SetColorTexture(GLuint t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorTexUnit);
|
||||
}
|
||||
|
||||
void SetColor(float r, float g, float b, float a = 1.0f) {
|
||||
assert((flags_ & SHD_MODULATE) || !(flags_ & SHD_TEXTURE));
|
||||
assert(IsBound());
|
||||
if (r != r_ || g != g_ || b != b_ || a != a_) {
|
||||
r_ = r;
|
||||
g_ = g;
|
||||
b_ = b;
|
||||
a_ = a;
|
||||
glUniform4f(color_location_, r_, g_, b_, a_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorizeColor(float r, float g, float b, float a = 1.0f) {
|
||||
assert(flags_ & SHD_COLORIZE);
|
||||
assert(IsBound());
|
||||
if (r != colorize_r_ || g != colorize_g_ || b != colorize_b_
|
||||
|| a != colorize_a_) {
|
||||
colorize_r_ = r;
|
||||
colorize_g_ = g;
|
||||
colorize_b_ = b;
|
||||
colorize_a_ = a;
|
||||
glUniform4f(colorize_color_location_, colorize_r_, colorize_g_,
|
||||
colorize_b_, colorize_a_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetShadow(float shadow_offset_x, float shadow_offset_y,
|
||||
float shadow_blur, float shadow_density) {
|
||||
assert(flags_ & SHD_SHADOW);
|
||||
assert(IsBound());
|
||||
if (shadow_offset_x != shadow_offset_x_
|
||||
|| shadow_offset_y != shadow_offset_y_ || shadow_blur != shadow_blur_
|
||||
|| shadow_density != shadow_density_) {
|
||||
shadow_offset_x_ = shadow_offset_x;
|
||||
shadow_offset_y_ = shadow_offset_y;
|
||||
shadow_blur_ = shadow_blur;
|
||||
shadow_density_ = shadow_density;
|
||||
glUniform4f(shadow_params_location_, shadow_offset_x_, shadow_offset_y_,
|
||||
shadow_blur_, shadow_density_ * 0.4f);
|
||||
}
|
||||
}
|
||||
|
||||
void SetGlow(float glow_amount, float glow_blur) {
|
||||
assert(flags_ & SHD_GLOW);
|
||||
assert(IsBound());
|
||||
if (glow_amount != glow_amount_ || glow_blur != glow_blur_) {
|
||||
glow_amount_ = glow_amount;
|
||||
glow_blur_ = glow_blur;
|
||||
glUniform2f(glow_params_location_, glow_amount_, glow_blur_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetFlatness(float flatness) {
|
||||
assert(flags_ & SHD_FLATNESS);
|
||||
assert(IsBound());
|
||||
if (flatness != flatness_) {
|
||||
flatness_ = flatness;
|
||||
glUniform1f(flatness_location, flatness_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorize2Color(float r, float g, float b, float a = 1.0f) {
|
||||
assert(flags_ & SHD_COLORIZE2);
|
||||
assert(IsBound());
|
||||
if (r != colorize2_r_ || g != colorize2_g_ || b != colorize2_b_
|
||||
|| a != colorize2_a_) {
|
||||
colorize2_r_ = r;
|
||||
colorize2_g_ = g;
|
||||
colorize2_b_ = b;
|
||||
colorize2_a_ = a;
|
||||
glUniform4f(colorize2_color_location_, colorize2_r_, colorize2_g_,
|
||||
colorize2_b_, colorize2_a_);
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorizeTexture(const TextureAsset* t) {
|
||||
assert(flags_ & SHD_COLORIZE);
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorizeTexUnit);
|
||||
}
|
||||
|
||||
void SetMaskTexture(const TextureAsset* t) {
|
||||
assert(flags_ & SHD_MASKED);
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kMaskTexUnit);
|
||||
}
|
||||
|
||||
void SetMaskUV2Texture(const TextureAsset* t) {
|
||||
assert(flags_ & SHD_MASK_UV2);
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kMaskUV2TexUnit);
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetName(int flags) -> std::string {
|
||||
return "SimpleProgramGL texture:"
|
||||
+ std::to_string((flags & SHD_TEXTURE) != 0)
|
||||
+ " modulate:" + std::to_string((flags & SHD_MODULATE) != 0)
|
||||
+ " colorize:" + std::to_string((flags & SHD_COLORIZE) != 0)
|
||||
+ " colorize2:" + std::to_string((flags & SHD_COLORIZE2) != 0)
|
||||
+ " premultiply:" + std::to_string((flags & SHD_PREMULTIPLY) != 0)
|
||||
+ " shadow:" + std::to_string((flags & SHD_SHADOW) != 0)
|
||||
+ " glow:" + std::to_string((flags & SHD_GLOW) != 0) + " masked:"
|
||||
+ std::to_string((flags & SHD_MASKED) != 0) + " maskedUV2:"
|
||||
+ std::to_string((flags & SHD_MASK_UV2) != 0) + " depthBugTest:"
|
||||
+ std::to_string((flags & SHD_DEPTH_BUG_TEST) != 0)
|
||||
+ " flatness:" + std::to_string((flags & SHD_FLATNESS) != 0);
|
||||
}
|
||||
|
||||
auto GetPFlags(int flags) -> int {
|
||||
int pflags = PFLAG_USES_POSITION_ATTR;
|
||||
if (flags & SHD_TEXTURE) {
|
||||
pflags |= PFLAG_USES_UV_ATTR;
|
||||
}
|
||||
if (flags & SHD_MASK_UV2) {
|
||||
pflags |= PFLAG_USES_UV2_ATTR;
|
||||
}
|
||||
return pflags;
|
||||
}
|
||||
|
||||
auto GetVertexCode(int flags) -> std::string {
|
||||
// clang-format off
|
||||
std::string s;
|
||||
s = "uniform mat4 modelViewProjectionMatrix;\n"
|
||||
BA_GLSL_VERTEX_IN " vec4 position;\n";
|
||||
if ((flags & SHD_TEXTURE) || (flags & SHD_COLORIZE)
|
||||
|| (flags & SHD_COLORIZE2)) {
|
||||
s += BA_GLSL_VERTEX_IN " vec2 uv;\n"
|
||||
BA_GLSL_VERTEX_OUT " vec2 vUV;\n";
|
||||
}
|
||||
if (flags & SHD_MASK_UV2) {
|
||||
s += BA_GLSL_VERTEX_IN " vec2 uv2;\n"
|
||||
BA_GLSL_VERTEX_OUT " vec2 vUV2;\n";
|
||||
}
|
||||
if (flags & SHD_SHADOW) {
|
||||
s += BA_GLSL_VERTEX_OUT " vec2 vUVShadow;\n"
|
||||
BA_GLSL_VERTEX_OUT " vec2 vUVShadow2;\n"
|
||||
BA_GLSL_VERTEX_OUT " vec2 vUVShadow3;\n"
|
||||
"uniform " BA_GLSL_LOWP "vec4 shadowParams;\n";
|
||||
}
|
||||
s += "void main() {\n";
|
||||
if (flags & SHD_TEXTURE) {
|
||||
s += " vUV = uv;\n";
|
||||
}
|
||||
if (flags & SHD_MASK_UV2) {
|
||||
s += " vUV2 = uv2;\n";
|
||||
}
|
||||
if (flags & SHD_SHADOW) {
|
||||
s += " vUVShadow = uv + 0.4 *"
|
||||
" vec2(shadowParams.x, shadowParams.y);\n";
|
||||
}
|
||||
if (flags & SHD_SHADOW) {
|
||||
s += " vUVShadow2 = uv + 0.8 *"
|
||||
" vec2(shadowParams.x, shadowParams.y);\n";
|
||||
}
|
||||
if (flags & SHD_SHADOW) {
|
||||
s += " vUVShadow3 = uv + 1.3 * vec2(shadowParams.x, shadowParams.y);\n";
|
||||
}
|
||||
s += " gl_Position = modelViewProjectionMatrix * position;\n"
|
||||
"}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT) {
|
||||
Log(LogLevel::kInfo,
|
||||
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
return s;
|
||||
}
|
||||
|
||||
auto GetFragmentCode(int flags) -> std::string {
|
||||
// clang-format off
|
||||
std::string s;
|
||||
if (flags & SHD_TEXTURE) {
|
||||
s += "uniform " BA_GLSL_LOWP "sampler2D colorTex;\n";
|
||||
}
|
||||
if ((flags & SHD_COLORIZE)) {
|
||||
s += "uniform " BA_GLSL_LOWP "sampler2D colorizeTex;\n"
|
||||
"uniform " BA_GLSL_LOWP "vec4 colorizeColor;\n";
|
||||
}
|
||||
if ((flags & SHD_COLORIZE2)) {
|
||||
s += "uniform " BA_GLSL_LOWP "vec4 colorize2Color;\n";
|
||||
}
|
||||
if ((flags & SHD_TEXTURE) || (flags & SHD_COLORIZE)
|
||||
|| (flags & SHD_COLORIZE2)) {
|
||||
s += BA_GLSL_FRAG_IN " " BA_GLSL_LOWP "vec2 vUV;\n";
|
||||
}
|
||||
if (flags & SHD_MASK_UV2) {
|
||||
s += BA_GLSL_FRAG_IN " " BA_GLSL_LOWP "vec2 vUV2;\n";
|
||||
}
|
||||
if (flags & SHD_FLATNESS) {
|
||||
s += "uniform " BA_GLSL_LOWP "float flatness;\n";
|
||||
}
|
||||
if (flags & SHD_SHADOW) {
|
||||
s += BA_GLSL_FRAG_IN " " BA_GLSL_LOWP "vec2 vUVShadow;\n"
|
||||
BA_GLSL_FRAG_IN " " BA_GLSL_LOWP "vec2 vUVShadow2;\n"
|
||||
BA_GLSL_FRAG_IN " " BA_GLSL_LOWP "vec2 vUVShadow3;\n"
|
||||
"uniform " BA_GLSL_LOWP "vec4 shadowParams;\n";
|
||||
}
|
||||
if (flags & SHD_GLOW) {
|
||||
s += "uniform " BA_GLSL_LOWP "vec2 glowParams;\n";
|
||||
}
|
||||
if ((flags & SHD_MODULATE) || (!(flags & SHD_TEXTURE))) {
|
||||
s += "uniform " BA_GLSL_LOWP "vec4 color;\n";
|
||||
}
|
||||
if (flags & SHD_MASKED) {
|
||||
s += "uniform " BA_GLSL_LOWP "sampler2D maskTex;\n";
|
||||
}
|
||||
if (flags & SHD_MASK_UV2) {
|
||||
s += "uniform " BA_GLSL_LOWP "sampler2D maskUV2Tex;\n";
|
||||
}
|
||||
s += "void main() {\n";
|
||||
if (!(flags & SHD_TEXTURE)) {
|
||||
s += " " BA_GLSL_FRAGCOLOR " = color;\n";
|
||||
} else {
|
||||
std::string blur_arg;
|
||||
if (flags & SHD_GLOW) {
|
||||
s += " " BA_GLSL_LOWP
|
||||
"vec4 cVal = " BA_GLSL_TEXTURE2D "(colorTex, vUV, glowParams.g);\n"
|
||||
" " BA_GLSL_FRAGCOLOR
|
||||
" = vec4(color.rgb * cVal.rgb * cVal.a * "
|
||||
"glowParams.r, 0.0)"; // we premultiply this.
|
||||
if (flags & SHD_MASK_UV2) {
|
||||
s += " * vec4(" BA_GLSL_TEXTURE2D "(maskUV2Tex, vUV2).a)";
|
||||
}
|
||||
s += ";\n";
|
||||
} else {
|
||||
if ((flags & SHD_COLORIZE) || (flags & SHD_COLORIZE2)) {
|
||||
// TEMP TEST
|
||||
s += " " BA_GLSL_LOWP
|
||||
"vec4 colorizeVal = " BA_GLSL_TEXTURE2D "(colorizeTex, vUV);\n";
|
||||
}
|
||||
if (flags & SHD_COLORIZE) {
|
||||
s += " " BA_GLSL_LOWP "float colorizeA = colorizeVal.r;\n";
|
||||
}
|
||||
if (flags & SHD_COLORIZE2) {
|
||||
s += " " BA_GLSL_LOWP "float colorizeB = colorizeVal.g;\n";
|
||||
}
|
||||
if (flags & SHD_MASKED) {
|
||||
s += " " BA_GLSL_MEDIUMP "vec4 mask = "
|
||||
BA_GLSL_TEXTURE2D "(maskTex, vUV);";
|
||||
}
|
||||
|
||||
if (flags & SHD_MODULATE) {
|
||||
if (flags & SHD_FLATNESS) {
|
||||
s += " " BA_GLSL_LOWP
|
||||
"vec4 rawTexColor = " BA_GLSL_TEXTURE2D "(colorTex, vUV);\n"
|
||||
" " BA_GLSL_FRAGCOLOR " = color * "
|
||||
"vec4(mix(rawTexColor.rgb, vec3(1.0), flatness),"
|
||||
" rawTexColor.a)";
|
||||
} else {
|
||||
s += " " BA_GLSL_FRAGCOLOR " = color * "
|
||||
BA_GLSL_TEXTURE2D "(colorTex, vUV)";
|
||||
}
|
||||
} else {
|
||||
s += " " BA_GLSL_FRAGCOLOR " = "
|
||||
BA_GLSL_TEXTURE2D "(colorTex, vUV)";
|
||||
}
|
||||
|
||||
if (flags & SHD_COLORIZE) {
|
||||
s += " * (vec4(1.0 - colorizeA) + colorizeColor * colorizeA)";
|
||||
}
|
||||
if (flags & SHD_COLORIZE2) {
|
||||
s += " * (vec4(1.0 - colorizeB) + colorize2Color * colorizeB)";
|
||||
}
|
||||
if (flags & SHD_MASKED) {
|
||||
s += " * vec4(vec3(mask.r), mask.a) + "
|
||||
"vec4(vec3(mask.g) * colorizeColor.rgb + vec3(mask.b), 0.0)";
|
||||
}
|
||||
s += ";\n";
|
||||
|
||||
if (flags & SHD_SHADOW) {
|
||||
s += " " BA_GLSL_LOWP
|
||||
"float shadowA = ("
|
||||
BA_GLSL_TEXTURE2D "(colorTex, vUVShadow).a + "
|
||||
"" BA_GLSL_TEXTURE2D "(colorTex, vUVShadow2, 1.0).a + "
|
||||
"" BA_GLSL_TEXTURE2D
|
||||
"(colorTex, vUVShadow3, 2.0).a) * shadowParams.a";
|
||||
|
||||
if (flags & SHD_MASK_UV2) {
|
||||
s += " * " BA_GLSL_TEXTURE2D "(maskUV2Tex, vUV2).a";
|
||||
}
|
||||
s += ";\n";
|
||||
s += " " BA_GLSL_FRAGCOLOR
|
||||
" = "
|
||||
"vec4(" BA_GLSL_FRAGCOLOR ".rgb * " BA_GLSL_FRAGCOLOR
|
||||
".a," BA_GLSL_FRAGCOLOR
|
||||
".a) + "
|
||||
"(1.0 - " BA_GLSL_FRAGCOLOR ".a) * vec4(0, 0, 0, shadowA);\n";
|
||||
s += " " BA_GLSL_FRAGCOLOR
|
||||
" = "
|
||||
"vec4(" BA_GLSL_FRAGCOLOR
|
||||
".rgb / max(0.001, " BA_GLSL_FRAGCOLOR ".a), "
|
||||
BA_GLSL_FRAGCOLOR ".a);\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & SHD_DEPTH_BUG_TEST) {
|
||||
s += " " BA_GLSL_FRAGCOLOR " = vec4(abs(gl_FragCoord.z - "
|
||||
BA_GLSL_FRAGCOLOR ".r));\n";
|
||||
}
|
||||
|
||||
if (flags & SHD_PREMULTIPLY) {
|
||||
s += " " BA_GLSL_FRAGCOLOR " = vec4(" BA_GLSL_FRAGCOLOR
|
||||
".rgb * "
|
||||
"" BA_GLSL_FRAGCOLOR ".a, " BA_GLSL_FRAGCOLOR ".a);";
|
||||
}
|
||||
}
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT) {
|
||||
Log(LogLevel::kInfo,
|
||||
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
return s;
|
||||
}
|
||||
|
||||
float r_{}, g_{}, b_{}, a_{};
|
||||
float colorize_r_{}, colorize_g_{}, colorize_b_{}, colorize_a_{};
|
||||
float colorize2_r_{}, colorize2_g_{}, colorize2_b_{}, colorize2_a_{};
|
||||
float shadow_offset_x_{}, shadow_offset_y_{}, shadow_blur_{},
|
||||
shadow_density_{};
|
||||
float glow_amount_{}, glow_blur_{};
|
||||
float flatness_{};
|
||||
GLint color_location_{};
|
||||
GLint colorize_color_location_{};
|
||||
GLint colorize2_color_location_{};
|
||||
GLint shadow_params_location_{};
|
||||
GLint glow_params_location_{};
|
||||
GLint flatness_location{};
|
||||
int flags_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SIMPLE_GL_H_
|
||||
176
src/ballistica/base/graphics/gl/program/program_smoke_gl.h
Normal file
176
src/ballistica/base/graphics/gl/program/program_smoke_gl.h
Normal file
@ -0,0 +1,176 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SMOKE_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SMOKE_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/program/program_gl.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::ProgramSmokeGL : public RendererGL::ProgramGL {
|
||||
public:
|
||||
enum TextureUnit { kColorTexUnit, kDepthTexUnit, kBlurTexUnit };
|
||||
|
||||
ProgramSmokeGL(RendererGL* renderer, int flags)
|
||||
: RendererGL::ProgramGL(
|
||||
renderer, Object::New<VertexShaderGL>(GetVertexCode(flags)),
|
||||
Object::New<FragmentShaderGL>(GetFragmentCode(flags)), GetName(flags),
|
||||
GetPFlags(flags)),
|
||||
flags_(flags),
|
||||
r_(0),
|
||||
g_(0),
|
||||
b_(0),
|
||||
a_(0) {
|
||||
SetTextureUnit("colorTex", kColorTexUnit);
|
||||
if (flags & SHD_OVERLAY) {
|
||||
SetTextureUnit("depthTex", kDepthTexUnit);
|
||||
SetTextureUnit("blurTex", kBlurTexUnit);
|
||||
}
|
||||
color_location_ = glGetUniformLocation(program(), "colorMult");
|
||||
assert(color_location_ != -1);
|
||||
}
|
||||
|
||||
void SetColorTexture(const TextureAsset* t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorTexUnit);
|
||||
}
|
||||
|
||||
void SetDepthTexture(GLuint t) {
|
||||
assert(flags_ & SHD_OVERLAY);
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kDepthTexUnit);
|
||||
}
|
||||
|
||||
void SetBlurTexture(GLuint t) {
|
||||
assert(flags_ & SHD_OVERLAY);
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kBlurTexUnit);
|
||||
}
|
||||
|
||||
void SetColor(float r, float g, float b, float a = 1.0f) {
|
||||
assert(IsBound());
|
||||
// include tint..
|
||||
if (r * renderer()->tint().x != r_ || g * renderer()->tint().y != g_
|
||||
|| b * renderer()->tint().z != b_ || a != a_) {
|
||||
r_ = r * renderer()->tint().x;
|
||||
g_ = g * renderer()->tint().y;
|
||||
b_ = b * renderer()->tint().z;
|
||||
a_ = a;
|
||||
glUniform4f(color_location_, r_, g_, b_, a_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetName(int flags) -> std::string {
|
||||
return std::string("SmokeProgramGL");
|
||||
}
|
||||
|
||||
auto GetPFlags(int flags) -> int {
|
||||
int pflags = PFLAG_USES_POSITION_ATTR | PFLAG_USES_DIFFUSE_ATTR
|
||||
| PFLAG_USES_UV_ATTR | PFLAG_WORLD_SPACE_PTS
|
||||
| PFLAG_USES_ERODE_ATTR | PFLAG_USES_COLOR_ATTR;
|
||||
return pflags;
|
||||
}
|
||||
|
||||
auto GetVertexCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform mat4 modelViewProjectionMatrix;\n" BA_GLSL_VERTEX_IN
|
||||
" vec4 position;\n" BA_GLSL_VERTEX_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 uv;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP
|
||||
"vec2 vUV;\n" BA_GLSL_VERTEX_IN " " BA_GLSL_LOWP
|
||||
"float erode;\n" BA_GLSL_VERTEX_IN " " BA_GLSL_MEDIUMP
|
||||
"float diffuse;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_LOWP
|
||||
"float vErode;\n" BA_GLSL_VERTEX_IN " " BA_GLSL_MEDIUMP
|
||||
"vec4 color;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_LOWP
|
||||
"vec4 vColor;\n"
|
||||
"uniform " BA_GLSL_MEDIUMP "vec4 colorMult;\n";
|
||||
if (flags & SHD_OVERLAY) {
|
||||
s += BA_GLSL_VERTEX_OUT " " BA_GLSL_LOWP
|
||||
"vec4 cDiffuse;\n" BA_GLSL_VERTEX_OUT
|
||||
" " BA_GLSL_MEDIUMP "vec4 vScreenCoord;\n";
|
||||
}
|
||||
s += "void main() {\n"
|
||||
" vUV = uv;\n"
|
||||
" gl_Position = modelViewProjectionMatrix*position;\n"
|
||||
" vErode = erode;\n";
|
||||
// in overlay mode we pass color/diffuse to the pixel-shader since we
|
||||
// combine them there with a blurred bg image to get a soft look. In the
|
||||
// simple version we just use a flat ambient color here.
|
||||
if (flags & SHD_OVERLAY) {
|
||||
s += " vScreenCoord = "
|
||||
"vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n"
|
||||
" vColor = vec4(vec3(7.0*diffuse),0.7) * color * colorMult;\n"
|
||||
" cDiffuse = colorMult*(0.3+0.8*diffuse);\n"
|
||||
" vScreenCoord.xy += vec2(1.0);\n"
|
||||
" vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n";
|
||||
} else {
|
||||
s += " vColor = "
|
||||
"(vec4(vec3(7.0),1.0)*color+vec4(vec3(0.4),0))*vec4(vec3(diffuse),0."
|
||||
"4) * colorMult;\n";
|
||||
}
|
||||
s += " vColor *= vec4(vec3(vColor.a),1.0);\n"; // premultiply
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
auto GetFragmentCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s = "uniform " BA_GLSL_LOWP "sampler2D colorTex;\n" BA_GLSL_FRAG_IN
|
||||
" " BA_GLSL_MEDIUMP "vec2 vUV;\n" BA_GLSL_FRAG_IN " " BA_GLSL_LOWP
|
||||
"float vErode;\n" BA_GLSL_FRAG_IN " " BA_GLSL_LOWP "vec4 vColor;\n";
|
||||
if (flags & SHD_OVERLAY) {
|
||||
s += BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec4 vScreenCoord;\n"
|
||||
"uniform " BA_GLSL_LOWP
|
||||
"sampler2D depthTex;\n"
|
||||
"uniform " BA_GLSL_LOWP
|
||||
"sampler2D blurTex;\n" BA_GLSL_FRAG_IN
|
||||
" " BA_GLSL_LOWP "vec4 cDiffuse;\n";
|
||||
}
|
||||
s += "void main() {\n";
|
||||
s += " " BA_GLSL_LOWP
|
||||
"float erodeMult = smoothstep(vErode,1.0," BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV).r);\n"
|
||||
" " BA_GLSL_FRAGCOLOR " = (vColor*vec4(erodeMult));";
|
||||
if (flags & SHD_OVERLAY) {
|
||||
s += " " BA_GLSL_FRAGCOLOR " += vec4(vec3(" BA_GLSL_FRAGCOLOR
|
||||
".a),0) * cDiffuse * "
|
||||
"(0.11+0.8*" BA_GLSL_TEXTURE2DPROJ "(blurTex,vScreenCoord));\n";
|
||||
s += " " BA_GLSL_MEDIUMP " float depth =" BA_GLSL_TEXTURE2DPROJ
|
||||
"(depthTex,vScreenCoord).r;\n";
|
||||
|
||||
// Work around Adreno bug where depth is returned as 0..1 instead of
|
||||
// glDepthRange().
|
||||
if (GetFunkyDepthIssue_()) {
|
||||
s += " depth = " + std::to_string(kBackingDepth3) + "+depth*("
|
||||
+ std::to_string(kBackingDepth4) + "-"
|
||||
+ std::to_string(kBackingDepth3) + ");\n";
|
||||
}
|
||||
s += " " BA_GLSL_FRAGCOLOR
|
||||
" *= "
|
||||
"(1.0-smoothstep(0.0,0.002,gl_FragCoord.z-depth));\n";
|
||||
}
|
||||
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT)
|
||||
Log(LogLevel::kInfo,
|
||||
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
return s;
|
||||
}
|
||||
|
||||
float r_, g_, b_, a_;
|
||||
GLint color_location_;
|
||||
int flags_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SMOKE_GL_H_
|
||||
180
src/ballistica/base/graphics/gl/program/program_sprite_gl.h
Normal file
180
src/ballistica/base/graphics/gl/program/program_sprite_gl.h
Normal file
@ -0,0 +1,180 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SPRITE_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SPRITE_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/program/program_gl.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::ProgramSpriteGL : public RendererGL::ProgramGL {
|
||||
public:
|
||||
enum TextureUnit { kColorTexUnit, kDepthTexUnit };
|
||||
|
||||
ProgramSpriteGL(RendererGL* renderer, int flags)
|
||||
: RendererGL::ProgramGL(
|
||||
renderer, Object::New<VertexShaderGL>(GetVertexCode(flags)),
|
||||
Object::New<FragmentShaderGL>(GetFragmentCode(flags)), GetName(flags),
|
||||
GetPFlags(flags)),
|
||||
flags_(flags),
|
||||
r_(0),
|
||||
g_(0),
|
||||
b_(0),
|
||||
a_(0) {
|
||||
SetTextureUnit("colorTex", kColorTexUnit);
|
||||
|
||||
if (flags & SHD_OVERLAY) {
|
||||
SetTextureUnit("depthTex", kDepthTexUnit);
|
||||
}
|
||||
|
||||
if (flags & SHD_COLOR) {
|
||||
color_location_ = glGetUniformLocation(program(), "colorU");
|
||||
assert(color_location_ != -1);
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
void SetColorTexture(const TextureAsset* t) {
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kColorTexUnit);
|
||||
}
|
||||
|
||||
void SetDepthTexture(GLuint t) {
|
||||
assert(flags_ & SHD_OVERLAY);
|
||||
renderer()->BindTexture_(GL_TEXTURE_2D, t, kDepthTexUnit);
|
||||
}
|
||||
|
||||
void SetColor(float r, float g, float b, float a = 1.0f) {
|
||||
assert(flags_ & SHD_COLOR);
|
||||
assert(IsBound());
|
||||
if (r != r_ || g != g_ || b != b_ || a != a_) {
|
||||
r_ = r;
|
||||
g_ = g;
|
||||
b_ = b;
|
||||
a_ = a;
|
||||
glUniform4f(color_location_, r_, g_, b_, a_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetName(int flags) -> std::string {
|
||||
return std::string("SpriteProgramGL");
|
||||
}
|
||||
|
||||
auto GetPFlags(int flags) -> int {
|
||||
int pflags = PFLAG_USES_POSITION_ATTR | PFLAG_USES_SIZE_ATTR
|
||||
| PFLAG_USES_COLOR_ATTR | PFLAG_USES_UV_ATTR;
|
||||
if (flags & SHD_CAMERA_ALIGNED) pflags |= PFLAG_USES_CAM_ORIENT_MATRIX;
|
||||
return pflags;
|
||||
}
|
||||
|
||||
auto GetVertexCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
s += "uniform mat4 modelViewProjectionMatrix;\n" BA_GLSL_VERTEX_IN
|
||||
" vec4 position;\n" BA_GLSL_VERTEX_IN " " BA_GLSL_MEDIUMP
|
||||
"vec2 uv;\n" BA_GLSL_VERTEX_IN " " BA_GLSL_MEDIUMP
|
||||
"float size;\n" BA_GLSL_VERTEX_OUT " " BA_GLSL_MEDIUMP "vec2 vUV;\n";
|
||||
|
||||
if (flags & SHD_COLOR) {
|
||||
s += "uniform " BA_GLSL_LOWP "vec4 colorU;\n";
|
||||
}
|
||||
|
||||
if (flags & SHD_CAMERA_ALIGNED) {
|
||||
s += "uniform mat4 camOrientMatrix;\n";
|
||||
}
|
||||
|
||||
if (flags & SHD_OVERLAY) {
|
||||
s += BA_GLSL_VERTEX_OUT " " BA_GLSL_LOWP "vec4 vScreenCoord;\n";
|
||||
}
|
||||
|
||||
s += BA_GLSL_VERTEX_IN " " BA_GLSL_LOWP "vec4 color;\n" BA_GLSL_VERTEX_OUT
|
||||
" " BA_GLSL_LOWP
|
||||
"vec4 vColor;\n"
|
||||
"void main() {\n";
|
||||
|
||||
if (flags & SHD_CAMERA_ALIGNED) {
|
||||
s += " " BA_GLSL_HIGHP
|
||||
"vec4 pLocal = "
|
||||
"(position+camOrientMatrix*vec4((uv.s-0.5)*size,0,(uv.t-0.5)*size,0)"
|
||||
");\n";
|
||||
} else {
|
||||
s += " " BA_GLSL_HIGHP
|
||||
"vec4 pLocal = "
|
||||
"(position+vec4((uv.s-0.5)*size,0,(uv.t-0.5)*size,0));\n";
|
||||
}
|
||||
s += " gl_Position = modelViewProjectionMatrix*pLocal;\n"
|
||||
" vUV = uv;\n";
|
||||
if (flags & SHD_COLOR) {
|
||||
s += " vColor = color*colorU;\n";
|
||||
} else {
|
||||
s += " vColor = color;\n";
|
||||
}
|
||||
if (flags & SHD_OVERLAY)
|
||||
s += " vScreenCoord = "
|
||||
"vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n"
|
||||
" vScreenCoord.xy += vec2(1.0);\n"
|
||||
" vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n";
|
||||
s += "}";
|
||||
|
||||
if (flags & SHD_DEBUG_PRINT) {
|
||||
Log(LogLevel::kInfo,
|
||||
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
auto GetFragmentCode(int flags) -> std::string {
|
||||
std::string s;
|
||||
|
||||
s += "uniform " BA_GLSL_LOWP "sampler2D colorTex;\n" BA_GLSL_FRAG_IN
|
||||
" " BA_GLSL_MEDIUMP "vec2 vUV;\n" BA_GLSL_FRAG_IN " " BA_GLSL_LOWP
|
||||
"vec4 vColor;\n";
|
||||
if (flags & SHD_OVERLAY) {
|
||||
s += BA_GLSL_FRAG_IN " " BA_GLSL_MEDIUMP
|
||||
"vec4 vScreenCoord;\n"
|
||||
"uniform " BA_GLSL_MEDIUMP "sampler2D depthTex;\n";
|
||||
}
|
||||
|
||||
s += "void main() {\n"
|
||||
" " BA_GLSL_FRAGCOLOR " = vColor*vec4(" BA_GLSL_TEXTURE2D
|
||||
"(colorTex,vUV).r);\n";
|
||||
if (flags & SHD_EXP2)
|
||||
s += " " BA_GLSL_FRAGCOLOR
|
||||
" = vec4(vUV,0,0) + "
|
||||
"vec4(" BA_GLSL_FRAGCOLOR ".rgb*" BA_GLSL_FRAGCOLOR
|
||||
".rgb," BA_GLSL_FRAGCOLOR ".a);\n";
|
||||
if (flags & SHD_OVERLAY) {
|
||||
s += " " BA_GLSL_MEDIUMP "float depth = " BA_GLSL_TEXTURE2DPROJ
|
||||
"(depthTex,vScreenCoord).r;\n";
|
||||
// Adreno 320 bug where depth is returned as 0..1 instead of
|
||||
// glDepthRange().
|
||||
if (GetFunkyDepthIssue_()) {
|
||||
s += " depth = " + std::to_string(kBackingDepth3) + "+depth*("
|
||||
+ std::to_string(kBackingDepth4) + "-"
|
||||
+ std::to_string(kBackingDepth3) + ");\n";
|
||||
}
|
||||
s += " " BA_GLSL_FRAGCOLOR
|
||||
" *= "
|
||||
"(1.0-smoothstep(0.0,0.001,gl_FragCoord.z-depth));\n";
|
||||
}
|
||||
s += "}";
|
||||
if (flags & SHD_DEBUG_PRINT) {
|
||||
Log(LogLevel::kInfo,
|
||||
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
float r_, g_, b_, a_;
|
||||
GLint color_location_;
|
||||
int flags_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_PROGRAM_PROGRAM_SPRITE_GL_H_
|
||||
129
src/ballistica/base/graphics/gl/render_target_gl.h
Normal file
129
src/ballistica/base/graphics/gl/render_target_gl.h
Normal file
@ -0,0 +1,129 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_RENDER_TARGET_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_RENDER_TARGET_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/graphics/gl/framebuffer_object_gl.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::RenderTargetGL : public RenderTarget {
|
||||
public:
|
||||
void Bind() {
|
||||
if (type_ == Type::kFramebuffer) {
|
||||
assert(framebuffer_.Exists());
|
||||
framebuffer_->Bind();
|
||||
} else {
|
||||
assert(type_ == Type::kScreen);
|
||||
renderer_->BindFramebuffer(renderer_->screen_framebuffer_);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawBegin(bool must_clear_color, float clear_r, float clear_g,
|
||||
float clear_b, float clear_a) override {
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
Bind();
|
||||
|
||||
#if BA_CARDBOARD_BUILD
|
||||
int x, y;
|
||||
// Viewport offsets only apply to the screen render-target.
|
||||
if (type_ == Type::kScreen) {
|
||||
x = renderer_->VRGetViewportX();
|
||||
y = renderer_->VRGetViewportY();
|
||||
} else {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
renderer_->SetViewport_(x, y, physical_width_, physical_height_);
|
||||
#else
|
||||
renderer_->SetViewport_(0, 0, static_cast<GLsizei>(physical_width_),
|
||||
static_cast<GLsizei>(physical_height_));
|
||||
#endif
|
||||
|
||||
{
|
||||
// Clear depth, color, etc.
|
||||
GLuint clear_mask = 0;
|
||||
|
||||
// If they *requested* a clear for color, do so. Otherwise invalidate.
|
||||
if (must_clear_color) {
|
||||
clear_mask |= GL_COLOR_BUFFER_BIT;
|
||||
} else {
|
||||
renderer_->InvalidateFramebuffer(true, false, false);
|
||||
}
|
||||
|
||||
if (depth_) {
|
||||
// FIXME make sure depth writing is turned on at this point.
|
||||
// this needs to be on for glClear to work on depth.
|
||||
if (!renderer_->depth_writing_enabled_) {
|
||||
BA_LOG_ONCE(
|
||||
LogLevel::kWarning,
|
||||
"RendererGL: depth-writing not enabled when clearing depth");
|
||||
}
|
||||
clear_mask |= GL_DEPTH_BUFFER_BIT;
|
||||
}
|
||||
|
||||
if (clear_mask != 0) {
|
||||
if (clear_mask & GL_COLOR_BUFFER_BIT) {
|
||||
glClearColor(clear_r, clear_g, clear_b, clear_a);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
glClear(clear_mask);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto GetFramebufferID() -> GLuint {
|
||||
if (type_ == Type::kFramebuffer) {
|
||||
assert(framebuffer_.Exists());
|
||||
return framebuffer_->id();
|
||||
} else {
|
||||
return 0; // screen
|
||||
}
|
||||
}
|
||||
|
||||
auto framebuffer() -> FramebufferObjectGL* {
|
||||
assert(type_ == Type::kFramebuffer);
|
||||
return framebuffer_.Get();
|
||||
}
|
||||
|
||||
// Screen constructor.
|
||||
explicit RenderTargetGL(RendererGL* renderer)
|
||||
: RenderTarget(Type::kScreen), renderer_(renderer) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
depth_ = true;
|
||||
|
||||
// This will update our width/height values.
|
||||
OnScreenSizeChange();
|
||||
}
|
||||
|
||||
// Framebuffer constructor.
|
||||
RenderTargetGL(RendererGL* renderer, int width, int height,
|
||||
bool linear_interp, bool depth, bool texture,
|
||||
bool depth_texture, bool high_quality, bool msaa, bool alpha)
|
||||
: RenderTarget(Type::kFramebuffer), renderer_(renderer) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
framebuffer_ = Object::New<FramebufferObjectGL>(
|
||||
renderer, width, height, linear_interp, depth, texture, depth_texture,
|
||||
high_quality, msaa, alpha);
|
||||
physical_width_ = static_cast<float>(width);
|
||||
physical_height_ = static_cast<float>(height);
|
||||
depth_ = depth;
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
private:
|
||||
Object::Ref<FramebufferObjectGL> framebuffer_;
|
||||
RendererGL* renderer_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_RENDER_TARGET_GL_H_
|
||||
File diff suppressed because it is too large
Load Diff
@ -15,10 +15,27 @@
|
||||
#include "ballistica/base/graphics/renderer/renderer.h"
|
||||
#include "ballistica/shared/foundation/object.h"
|
||||
|
||||
// Can be handy to check GL errors on opt builds.
|
||||
#define BA_FORCE_CHECK_GL_ERRORS 0
|
||||
|
||||
#define BA_CHECK_GL_ERROR CheckGLError(__FILE__, __LINE__)
|
||||
#if BA_DEBUG_BUILD || BA_FORCE_CHECK_GL_ERRORS
|
||||
#define BA_DEBUG_CHECK_GL_ERROR CheckGLError(__FILE__, __LINE__)
|
||||
#else
|
||||
#define BA_DEBUG_CHECK_GL_ERROR ((void)0)
|
||||
#endif
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// for now lets not go above 8 since that's what the iPhone 3gs has..
|
||||
// ...haha perhaps should revisit this
|
||||
// extern int g_msaa_max_samples_rgb565;
|
||||
// extern int g_msaa_max_samples_rgb8;
|
||||
// extern bool g_vao_support;
|
||||
// extern bool g_running_es3;
|
||||
// extern bool g_anisotropic_support;
|
||||
// extern float g_max_anisotropy;
|
||||
|
||||
// For now lets not go above 8 since that's what the iPhone 3gs has. ...haha
|
||||
// perhaps can reconsider that since the 3gs was 15 years ago.
|
||||
constexpr int kMaxGLTexUnitsUsed = 5;
|
||||
|
||||
class RendererGL : public Renderer {
|
||||
@ -38,22 +55,72 @@ class RendererGL : public Renderer {
|
||||
class FragmentShaderGL;
|
||||
class VertexShaderGL;
|
||||
class ProgramGL;
|
||||
class SimpleProgramGL;
|
||||
class ObjectProgramGL;
|
||||
class SmokeProgramGL;
|
||||
class BlurProgramGL;
|
||||
class ShieldProgramGL;
|
||||
class PostProcessProgramGL;
|
||||
class SpriteProgramGL;
|
||||
class ProgramSimpleGL;
|
||||
class ProgramObjectGL;
|
||||
class ProgramSmokeGL;
|
||||
class ProgramBlurGL;
|
||||
class ProgramShieldGL;
|
||||
class ProgramPostProcessGL;
|
||||
class ProgramSpriteGL;
|
||||
|
||||
public:
|
||||
static void CheckGLError(const char* file, int line);
|
||||
static auto GLErrorToString(GLenum err) -> std::string;
|
||||
static auto GetGLTextureFormat(TextureFormat f) -> GLenum;
|
||||
|
||||
RendererGL();
|
||||
~RendererGL() override;
|
||||
void Unload() override;
|
||||
void Load() override;
|
||||
void PostLoad() override;
|
||||
|
||||
// our vertex attrs
|
||||
// Flags used internally by shaders.
|
||||
enum ShaderPrivateFlags {
|
||||
PFLAG_USES_POSITION_ATTR = 1,
|
||||
PFLAG_USES_UV_ATTR = 1 << 1,
|
||||
PFLAG_USES_NORMAL_ATTR = 1 << 2,
|
||||
PFLAG_USES_MODEL_WORLD_MATRIX = 1 << 3,
|
||||
PFLAG_USES_CAM_POS = 1 << 4,
|
||||
PFLAG_USES_SHADOW_PROJECTION_MATRIX = 1 << 5,
|
||||
PFLAG_WORLD_SPACE_PTS = 1 << 6,
|
||||
PFLAG_USES_ERODE_ATTR = 1 << 7,
|
||||
PFLAG_USES_COLOR_ATTR = 1 << 8,
|
||||
PFLAG_USES_SIZE_ATTR = 1 << 9,
|
||||
PFLAG_USES_DIFFUSE_ATTR = 1 << 10,
|
||||
PFLAG_USES_CAM_ORIENT_MATRIX = 1 << 11,
|
||||
PFLAG_USES_MODEL_VIEW_MATRIX = 1 << 12,
|
||||
PFLAG_USES_UV2_ATTR = 1 << 13
|
||||
};
|
||||
|
||||
// Flags affecting shader creation.
|
||||
enum ShaderFlag {
|
||||
SHD_REFLECTION = 1,
|
||||
SHD_TEXTURE = 1 << 1,
|
||||
SHD_MODULATE = 1 << 2,
|
||||
SHD_COLORIZE = 1 << 3,
|
||||
SHD_LIGHT_SHADOW = 1 << 4,
|
||||
SHD_WORLD_SPACE_PTS = 1 << 5,
|
||||
SHD_DEBUG_PRINT = 1 << 6,
|
||||
SHD_ADD = 1 << 7,
|
||||
SHD_OBJ_TRANSPARENT = 1 << 8,
|
||||
SHD_COLOR = 1 << 9,
|
||||
SHD_EXP2 = 1 << 10,
|
||||
SHD_CAMERA_ALIGNED = 1 << 11,
|
||||
SHD_DISTORT = 1 << 12,
|
||||
SHD_PREMULTIPLY = 1 << 13,
|
||||
SHD_OVERLAY = 1 << 14,
|
||||
SHD_EYES = 1 << 15,
|
||||
SHD_COLORIZE2 = 1 << 16,
|
||||
SHD_HIGHER_QUALITY = 1 << 17,
|
||||
SHD_SHADOW = 1 << 18,
|
||||
SHD_GLOW = 1 << 19,
|
||||
SHD_MASKED = 1 << 20,
|
||||
SHD_MASK_UV2 = 1 << 21,
|
||||
SHD_CONDITIONAL = 1 << 22,
|
||||
SHD_FLATNESS = 1 << 23,
|
||||
SHD_DEPTH_BUG_TEST = 1 << 24
|
||||
};
|
||||
|
||||
enum VertexAttr {
|
||||
kVertexAttrPosition,
|
||||
kVertexAttrUV,
|
||||
@ -66,12 +133,12 @@ class RendererGL : public Renderer {
|
||||
kVertexAttrCount
|
||||
};
|
||||
|
||||
void CheckCapabilities() override;
|
||||
auto GetAutoGraphicsQuality() -> GraphicsQuality override;
|
||||
auto GetAutoTextureQuality() -> TextureQuality override;
|
||||
|
||||
#if BA_OSTYPE_ANDROID
|
||||
std::string GetAutoAndroidRes() override;
|
||||
#endif // BA_OSTYPE_ANDROID
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void DrawDebug() override;
|
||||
@ -119,36 +186,66 @@ class RendererGL : public Renderer {
|
||||
|
||||
#if BA_VR_BUILD
|
||||
void VRSyncRenderStates() override;
|
||||
#endif // BA_VR_BUILD
|
||||
#endif
|
||||
|
||||
// TEMP
|
||||
auto current_vertex_array() const -> GLuint { return current_vertex_array_; }
|
||||
|
||||
auto anisotropic_support() const { return anisotropic_support_; }
|
||||
auto max_anisotropy() const {
|
||||
assert(anisotropic_support_);
|
||||
return max_anisotropy_;
|
||||
}
|
||||
auto invalidate_framebuffer_support() const {
|
||||
return invalidate_framebuffer_support_;
|
||||
}
|
||||
|
||||
auto msaa_max_samples_rgb565() const {
|
||||
assert(msaa_max_samples_rgb565_ != -1);
|
||||
return msaa_max_samples_rgb565_;
|
||||
}
|
||||
|
||||
auto msaa_max_samples_rgb8() const {
|
||||
assert(msaa_max_samples_rgb8_ != -1);
|
||||
return msaa_max_samples_rgb8_;
|
||||
}
|
||||
|
||||
auto gl_is_es() const -> bool {
|
||||
#if BA_OPENGL_IS_ES
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto DebugGLGetInt(GLenum name) -> int;
|
||||
|
||||
private:
|
||||
void CheckFunkyDepthIssue();
|
||||
auto GetMSAASamplesForFramebuffer(int width, int height) -> int;
|
||||
void UpdateMSAAEnabled() override;
|
||||
void CheckGLExtensions();
|
||||
void UpdateVignetteTex(bool force) override;
|
||||
void StandardPostProcessSetup(PostProcessProgramGL* p,
|
||||
const RenderPass& pass);
|
||||
void SyncGLState();
|
||||
void RetainShader(ProgramGL* p);
|
||||
void SetViewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void UseProgram(ProgramGL* p);
|
||||
auto GetActiveProgram() const -> ProgramGL* {
|
||||
static auto GetFunkyDepthIssue_() -> bool;
|
||||
// static auto GetDrawsShieldsFunny_()->bool;
|
||||
void CheckFunkyDepthIssue_();
|
||||
auto GetMSAASamplesForFramebuffer_(int width, int height) -> int;
|
||||
void UpdateMSAAEnabled_() override;
|
||||
void CheckGLCapabilities_();
|
||||
void UpdateVignetteTex_(bool force) override;
|
||||
void StandardPostProcessSetup_(ProgramPostProcessGL* p,
|
||||
const RenderPass& pass);
|
||||
void SyncGLState_();
|
||||
void RetainShader_(ProgramGL* p);
|
||||
void SetViewport_(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void UseProgram_(ProgramGL* p);
|
||||
auto GetActiveProgram_() const -> ProgramGL* {
|
||||
assert(current_program_);
|
||||
return current_program_;
|
||||
}
|
||||
void SetDoubleSided(bool d);
|
||||
void ScissorPush(const Rect& rIn, RenderTarget* render_target);
|
||||
void ScissorPop(RenderTarget* render_target);
|
||||
void BindVertexArray(GLuint v);
|
||||
void SetDoubleSided_(bool d);
|
||||
void ScissorPush_(const Rect& rIn, RenderTarget* render_target);
|
||||
void ScissorPop_(RenderTarget* render_target);
|
||||
void BindVertexArray_(GLuint v);
|
||||
|
||||
// Note: This is only for use when VAOs aren't supported.
|
||||
void SetVertexAttribArrayEnabled(GLuint i, bool enabled);
|
||||
void BindTexture(GLuint type, const TextureAsset* t, GLuint tex_unit = 0);
|
||||
void BindTexture(GLuint type, GLuint tex, GLuint tex_unit = 0);
|
||||
// void SetVertexAttributeArrayEnabled_(GLuint i, bool enabled);
|
||||
void BindTexture_(GLuint type, const TextureAsset* t, GLuint tex_unit = 0);
|
||||
void BindTexture_(GLuint type, GLuint tex, GLuint tex_unit = 0);
|
||||
void BindTextureUnit(uint32_t tex_unit);
|
||||
void BindFramebuffer(GLuint fb);
|
||||
void BindArrayBuffer(GLuint b);
|
||||
@ -156,7 +253,7 @@ class RendererGL : public Renderer {
|
||||
void SetBlendPremult(bool b);
|
||||
millisecs_t dof_update_time_{};
|
||||
std::vector<Object::Ref<FramebufferObjectGL> > blur_buffers_;
|
||||
bool supports_depth_textures_{};
|
||||
// bool supports_depth_textures_{};
|
||||
bool first_extension_check_{true};
|
||||
bool is_tegra_4_{};
|
||||
bool is_tegra_k1_{};
|
||||
@ -179,56 +276,54 @@ class RendererGL : public Renderer {
|
||||
bool depth_testing_enabled_{};
|
||||
bool data_loaded_{};
|
||||
bool draw_front_{};
|
||||
GLuint screen_framebuffer_{};
|
||||
bool got_screen_framebuffer_{};
|
||||
GLuint screen_framebuffer_{};
|
||||
GLuint random_tex_{};
|
||||
GLuint vignette_tex_{};
|
||||
GraphicsQuality vignette_quality_{};
|
||||
std::vector<std::unique_ptr<ProgramGL> > shaders_;
|
||||
GLint viewport_x_{};
|
||||
GLint viewport_y_{};
|
||||
GLint viewport_width_{};
|
||||
GLint viewport_height_{};
|
||||
SimpleProgramGL* simple_color_prog_{};
|
||||
SimpleProgramGL* simple_tex_prog_{};
|
||||
SimpleProgramGL* simple_tex_dtest_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_flatness_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_shadow_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_shadow_flatness_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_glow_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_glow_maskuv2_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_colorized_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_colorized2_prog_{};
|
||||
SimpleProgramGL* simple_tex_mod_colorized2_masked_prog_{};
|
||||
ObjectProgramGL* obj_prog_{};
|
||||
ObjectProgramGL* obj_transparent_prog_{};
|
||||
ObjectProgramGL* obj_lightshad_transparent_prog_{};
|
||||
ObjectProgramGL* obj_refl_prog_{};
|
||||
ObjectProgramGL* obj_refl_worldspace_prog_{};
|
||||
ObjectProgramGL* obj_refl_transparent_prog_{};
|
||||
ObjectProgramGL* obj_refl_add_transparent_prog_{};
|
||||
ObjectProgramGL* obj_lightshad_prog_{};
|
||||
ObjectProgramGL* obj_lightshad_worldspace_prog_{};
|
||||
ObjectProgramGL* obj_refl_lightshad_prog_{};
|
||||
ObjectProgramGL* obj_refl_lightshad_worldspace_prog_{};
|
||||
ObjectProgramGL* obj_refl_lightshad_colorize_prog_{};
|
||||
ObjectProgramGL* obj_refl_lightshad_colorize2_prog_{};
|
||||
ObjectProgramGL* obj_refl_lightshad_add_prog_{};
|
||||
ObjectProgramGL* obj_refl_lightshad_add_colorize_prog_{};
|
||||
ObjectProgramGL* obj_refl_lightshad_add_colorize2_prog_{};
|
||||
SmokeProgramGL* smoke_prog_{};
|
||||
SmokeProgramGL* smoke_overlay_prog_{};
|
||||
SpriteProgramGL* sprite_prog_{};
|
||||
SpriteProgramGL* sprite_camalign_prog_{};
|
||||
SpriteProgramGL* sprite_camalign_overlay_prog_{};
|
||||
BlurProgramGL* blur_prog_{};
|
||||
ShieldProgramGL* shield_prog_{};
|
||||
PostProcessProgramGL* postprocess_prog_{};
|
||||
PostProcessProgramGL* postprocess_eyes_prog_{};
|
||||
PostProcessProgramGL* postprocess_distort_prog_{};
|
||||
static auto GetFunkyDepthIssue() -> bool;
|
||||
static auto GetDrawsShieldsFunny() -> bool;
|
||||
std::vector<std::unique_ptr<ProgramGL> > shaders_;
|
||||
ProgramSimpleGL* simple_color_prog_{};
|
||||
ProgramSimpleGL* simple_tex_prog_{};
|
||||
ProgramSimpleGL* simple_tex_dtest_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_flatness_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_shadow_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_shadow_flatness_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_glow_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_glow_maskuv2_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_colorized_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_colorized2_prog_{};
|
||||
ProgramSimpleGL* simple_tex_mod_colorized2_masked_prog_{};
|
||||
ProgramObjectGL* obj_prog_{};
|
||||
ProgramObjectGL* obj_transparent_prog_{};
|
||||
ProgramObjectGL* obj_lightshad_transparent_prog_{};
|
||||
ProgramObjectGL* obj_refl_prog_{};
|
||||
ProgramObjectGL* obj_refl_worldspace_prog_{};
|
||||
ProgramObjectGL* obj_refl_transparent_prog_{};
|
||||
ProgramObjectGL* obj_refl_add_transparent_prog_{};
|
||||
ProgramObjectGL* obj_lightshad_prog_{};
|
||||
ProgramObjectGL* obj_lightshad_worldspace_prog_{};
|
||||
ProgramObjectGL* obj_refl_lightshad_prog_{};
|
||||
ProgramObjectGL* obj_refl_lightshad_worldspace_prog_{};
|
||||
ProgramObjectGL* obj_refl_lightshad_colorize_prog_{};
|
||||
ProgramObjectGL* obj_refl_lightshad_colorize2_prog_{};
|
||||
ProgramObjectGL* obj_refl_lightshad_add_prog_{};
|
||||
ProgramObjectGL* obj_refl_lightshad_add_colorize_prog_{};
|
||||
ProgramObjectGL* obj_refl_lightshad_add_colorize2_prog_{};
|
||||
ProgramSmokeGL* smoke_prog_{};
|
||||
ProgramSmokeGL* smoke_overlay_prog_{};
|
||||
ProgramSpriteGL* sprite_prog_{};
|
||||
ProgramSpriteGL* sprite_camalign_prog_{};
|
||||
ProgramSpriteGL* sprite_camalign_overlay_prog_{};
|
||||
ProgramBlurGL* blur_prog_{};
|
||||
ProgramShieldGL* shield_prog_{};
|
||||
ProgramPostProcessGL* postprocess_prog_{};
|
||||
ProgramPostProcessGL* postprocess_eyes_prog_{};
|
||||
ProgramPostProcessGL* postprocess_distort_prog_{};
|
||||
static bool funky_depth_issue_set_;
|
||||
static bool funky_depth_issue_;
|
||||
static bool draws_shields_funny_set_;
|
||||
@ -236,7 +331,7 @@ class RendererGL : public Renderer {
|
||||
#if BA_OSTYPE_ANDROID
|
||||
static bool is_speedy_android_device_;
|
||||
static bool is_extra_speedy_android_device_;
|
||||
#endif // BA_OSTYPE_ANDROID
|
||||
#endif
|
||||
ProgramGL* current_program_{};
|
||||
bool double_sided_{};
|
||||
std::vector<Rect> scissor_rects_;
|
||||
@ -257,6 +352,12 @@ class RendererGL : public Renderer {
|
||||
std::vector<MeshDataSmokeFullGL*> recycle_mesh_datas_smoke_full_;
|
||||
std::vector<MeshDataSpriteGL*> recycle_mesh_datas_sprite_;
|
||||
int error_check_counter_{};
|
||||
GLint combined_texture_image_unit_count_{};
|
||||
GLint anisotropic_support_{};
|
||||
GLfloat max_anisotropy_{};
|
||||
bool invalidate_framebuffer_support_{};
|
||||
int msaa_max_samples_rgb565_{-1};
|
||||
int msaa_max_samples_rgb8_{-1};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
329
src/ballistica/base/graphics/gl/texture_data_gl.h
Normal file
329
src/ballistica/base/graphics/gl/texture_data_gl.h
Normal file
@ -0,0 +1,329 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_GL_TEXTURE_DATA_GL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_GL_TEXTURE_DATA_GL_H_
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
#include "ballistica/base/assets/texture_asset_preload_data.h"
|
||||
#include "ballistica/base/assets/texture_asset_renderer_data.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class RendererGL::TextureDataGL : public TextureAssetRendererData {
|
||||
public:
|
||||
TextureDataGL(const TextureAsset& texture_in, RendererGL* renderer_in)
|
||||
: tex_media_(&texture_in), texture_(0), renderer_(renderer_in) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
glGenTextures(1, &texture_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
~TextureDataGL() override {
|
||||
if (!g_base->InGraphicsThread()) {
|
||||
Log(LogLevel::kError, "TextureDataGL dying outside of graphics thread.");
|
||||
} else {
|
||||
// If we're currently bound as anything, clear that out (otherwise a
|
||||
// new texture with that same ID won't be bindable).
|
||||
for (int i = 0; i < kMaxGLTexUnitsUsed; i++) {
|
||||
if ((renderer_->bound_textures_2d_[i]) == texture_) {
|
||||
renderer_->bound_textures_2d_[i] = -1;
|
||||
}
|
||||
if ((renderer_->bound_textures_cube_map_[i]) == texture_) {
|
||||
renderer_->bound_textures_cube_map_[i] = -1;
|
||||
}
|
||||
}
|
||||
if (!g_base->graphics_server->renderer_context_lost()) {
|
||||
glDeleteTextures(1, &texture_);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto GetTexture() const -> GLuint { return texture_; }
|
||||
|
||||
void Load() override {
|
||||
assert(g_base->InGraphicsThread());
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (tex_media_->texture_type() == TextureType::k2D) {
|
||||
renderer_->BindTexture_(GL_TEXTURE_2D, texture_);
|
||||
const TextureAssetPreloadData* preload_data =
|
||||
&tex_media_->preload_datas()[0];
|
||||
int base_src_level = preload_data->base_level;
|
||||
assert(preload_data->buffers[base_src_level]);
|
||||
GraphicsQuality q = g_base->graphics_server->quality();
|
||||
|
||||
// Determine whether to use anisotropic sampling on this texture:
|
||||
// basically all the UI stuff that is only ever seen from straight on
|
||||
// doesn't need it.
|
||||
bool allow_ani = true;
|
||||
|
||||
// FIXME: filtering based on filename. Once we get this stuff on a
|
||||
// server we should include this as metadata instead.
|
||||
const char* n = tex_media_->file_name().c_str();
|
||||
|
||||
// The following exceptions should *never* need aniso-sampling.
|
||||
{
|
||||
if (!strcmp(n, "fontBig")) {
|
||||
allow_ani = false;
|
||||
|
||||
// Lets splurge on this for higher but not high (names over
|
||||
// characters might benefit, though most text doesnt).
|
||||
} else if (strstr(n, "Icon")) {
|
||||
allow_ani = false;
|
||||
} else if (strstr(n, "characterIconMask")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "bg")) {
|
||||
allow_ani = false;
|
||||
} else if (strstr(n, "light")) {
|
||||
allow_ani = false;
|
||||
} else if (strstr(n, "shadow")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "sparks")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "smoke")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "scorch")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "scorchBig")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "white")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "buttonBomb")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "buttonJump")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "buttonPickUp")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "buttonPunch")) {
|
||||
allow_ani = false;
|
||||
} else if (strstr(n, "touchArrows")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "actionButtons")) {
|
||||
allow_ani = false;
|
||||
}
|
||||
}
|
||||
|
||||
// The following are considered 'nice to have' - we turn aniso. off for
|
||||
// them in anything less than 'higher' mode.
|
||||
if (allow_ani && (q < GraphicsQuality::kHigher)) {
|
||||
if (strstr(n, "ColorMask")) {
|
||||
allow_ani = false; // character color-masks
|
||||
} else if (strstr(n, "softRect")) {
|
||||
allow_ani = false;
|
||||
} else if (strstr(n, "BG")) {
|
||||
allow_ani = false; // level backgrounds
|
||||
} else if (!strcmp(n, "explosion")) {
|
||||
allow_ani = false;
|
||||
} else if (!strcmp(n, "bar")) {
|
||||
allow_ani = false;
|
||||
}
|
||||
}
|
||||
|
||||
// In higher quality we do anisotropic trilinear mipmap.
|
||||
if (q >= GraphicsQuality::kHigher) {
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
if (renderer_->anisotropic_support() && allow_ani) {
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
std::min(16.0f, renderer_->max_anisotropy()));
|
||||
}
|
||||
} else if (q >= GraphicsQuality::kHigh) {
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
if (renderer_->anisotropic_support() && allow_ani)
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
std::min(16.0f, renderer_->max_anisotropy()));
|
||||
} else if (q >= GraphicsQuality::kMedium) {
|
||||
// In medium quality we don't do anisotropy but do trilinear.
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
} else {
|
||||
// In low quality we do bilinear.
|
||||
assert(q == GraphicsQuality::kLow);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_NEAREST);
|
||||
}
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
int src_level = base_src_level;
|
||||
int level = 0;
|
||||
bool all_levels_handled = false;
|
||||
while (preload_data->buffers[src_level] != nullptr
|
||||
&& !all_levels_handled) {
|
||||
switch (preload_data->formats[src_level]) {
|
||||
case TextureFormat::kRGBA_8888: {
|
||||
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA,
|
||||
preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, preload_data->buffers[src_level]);
|
||||
|
||||
// At the moment we always just let GL generate mipmaps for
|
||||
// uncompressed textures; is there any reason not to?
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
all_levels_handled = true;
|
||||
break;
|
||||
}
|
||||
case TextureFormat::kRGBA_4444: {
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D, level, GL_RGBA, preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0, GL_RGBA,
|
||||
GL_UNSIGNED_SHORT_4_4_4_4, preload_data->buffers[src_level]);
|
||||
|
||||
// At the moment we always just let GL generate mipmaps for
|
||||
// uncompressed textures; is there any reason not to?
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
all_levels_handled = true;
|
||||
break;
|
||||
}
|
||||
case TextureFormat::kRGB_565: {
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D, level, GL_RGB, preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0, GL_RGB,
|
||||
GL_UNSIGNED_SHORT_5_6_5, preload_data->buffers[src_level]);
|
||||
|
||||
// At the moment we always just let GL generate mipmaps for
|
||||
// uncompressed textures; is there any reason not to?
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
all_levels_handled = true;
|
||||
break;
|
||||
}
|
||||
case TextureFormat::kRGB_888: {
|
||||
glTexImage2D(GL_TEXTURE_2D, level, GL_RGB,
|
||||
preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0, GL_RGB,
|
||||
GL_UNSIGNED_BYTE, preload_data->buffers[src_level]);
|
||||
|
||||
// At the moment we always just let GL generate mipmaps for
|
||||
// uncompressed textures; is there any reason not to?
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
all_levels_handled = true;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
glCompressedTexImage2D(
|
||||
GL_TEXTURE_2D, level,
|
||||
GetGLTextureFormat(preload_data->formats[src_level]),
|
||||
preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0,
|
||||
static_cast_check_fit<GLsizei>(preload_data->sizes[src_level]),
|
||||
preload_data->buffers[src_level]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
src_level++;
|
||||
level++;
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
BA_GL_LABEL_OBJECT(GL_TEXTURE, texture_, tex_media_->GetName().c_str());
|
||||
} else if (tex_media_->texture_type() == TextureType::kCubeMap) {
|
||||
// Cube map.
|
||||
renderer_->BindTexture_(GL_TEXTURE_CUBE_MAP, texture_);
|
||||
|
||||
bool do_generate_mips = false;
|
||||
for (uint32_t i = 0; i < 6; i++) {
|
||||
const TextureAssetPreloadData* preload_data =
|
||||
&tex_media_->preload_datas()[i];
|
||||
int base_src_level = preload_data->base_level;
|
||||
assert(preload_data->buffers[base_src_level]);
|
||||
|
||||
GraphicsQuality q = g_base->graphics_server->quality();
|
||||
|
||||
// Do trilinear in higher quality; otherwise bilinear is good enough.
|
||||
if (q >= GraphicsQuality::kHigher) {
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
} else {
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_NEAREST);
|
||||
}
|
||||
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
|
||||
int src_level = base_src_level;
|
||||
int level = 0;
|
||||
bool generating_remaining_mips = false;
|
||||
while (preload_data->buffers[src_level] != nullptr
|
||||
&& !generating_remaining_mips) {
|
||||
switch (preload_data->formats[src_level]) {
|
||||
case TextureFormat::kRGBA_8888:
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, GL_RGBA,
|
||||
preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, preload_data->buffers[src_level]);
|
||||
generating_remaining_mips = do_generate_mips = true;
|
||||
break;
|
||||
case TextureFormat::kRGBA_4444:
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, GL_RGBA,
|
||||
preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0, GL_RGBA,
|
||||
GL_UNSIGNED_SHORT_4_4_4_4,
|
||||
preload_data->buffers[src_level]);
|
||||
generating_remaining_mips = do_generate_mips = true;
|
||||
break;
|
||||
case TextureFormat::kRGB_565:
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, GL_RGB,
|
||||
preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0, GL_RGB,
|
||||
GL_UNSIGNED_SHORT_5_6_5,
|
||||
preload_data->buffers[src_level]);
|
||||
generating_remaining_mips = do_generate_mips = true;
|
||||
break;
|
||||
case TextureFormat::kRGB_888:
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, GL_RGB,
|
||||
preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0, GL_RGB,
|
||||
GL_UNSIGNED_BYTE, preload_data->buffers[src_level]);
|
||||
generating_remaining_mips = do_generate_mips = true;
|
||||
break;
|
||||
default:
|
||||
glCompressedTexImage2D(
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level,
|
||||
GetGLTextureFormat(preload_data->formats[src_level]),
|
||||
preload_data->widths[src_level],
|
||||
preload_data->heights[src_level], 0,
|
||||
static_cast_check_fit<GLsizei>(
|
||||
preload_data->sizes[src_level]),
|
||||
preload_data->buffers[src_level]);
|
||||
break;
|
||||
}
|
||||
src_level++;
|
||||
level++;
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're generating remaining mips on the gpu, do so.
|
||||
if (do_generate_mips) {
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
}
|
||||
|
||||
BA_GL_LABEL_OBJECT(GL_TEXTURE, texture_, tex_media_->GetName().c_str());
|
||||
} else {
|
||||
throw Exception();
|
||||
}
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
}
|
||||
|
||||
private:
|
||||
const TextureAsset* tex_media_;
|
||||
RendererGL* renderer_;
|
||||
GLuint texture_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_GL_TEXTURE_DATA_GL_H_
|
||||
@ -11,13 +11,14 @@
|
||||
#include "ballistica/base/graphics/component/simple_component.h"
|
||||
#include "ballistica/base/graphics/component/special_component.h"
|
||||
#include "ballistica/base/graphics/component/sprite_component.h"
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/graphics/graphics_vr.h"
|
||||
#include "ballistica/base/graphics/support/camera.h"
|
||||
#include "ballistica/base/graphics/support/net_graph.h"
|
||||
#include "ballistica/base/graphics/text/text_graphics.h"
|
||||
#include "ballistica/base/input/input.h"
|
||||
#include "ballistica/base/logic/logic.h"
|
||||
#include "ballistica/base/platform/base_platform.h"
|
||||
#include "ballistica/base/python/support/python_context_call.h"
|
||||
#include "ballistica/base/support/app_config.h"
|
||||
#include "ballistica/base/ui/dev_console.h"
|
||||
@ -35,6 +36,14 @@ const float kProgressBarZDepth{0.0f};
|
||||
const int kProgressBarFadeTime{500};
|
||||
const float kDebugImgZDepth{-0.04f};
|
||||
|
||||
auto Graphics::Create() -> Graphics* {
|
||||
#if BA_VR_BUILD
|
||||
return new GraphicsVR();
|
||||
#else
|
||||
return new Graphics();
|
||||
#endif
|
||||
}
|
||||
|
||||
auto Graphics::IsShaderTransparent(ShadingType c) -> bool {
|
||||
switch (c) {
|
||||
case ShadingType::kSimpleColorTransparent:
|
||||
@ -106,94 +115,10 @@ void Graphics::OnAppShutdownComplete() { assert(g_base->InLogicThread()); }
|
||||
void Graphics::DoApplyAppConfig() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Not relevant for fullscreen anymore since we use fullscreen windows.
|
||||
// everywhere.
|
||||
int width = 800;
|
||||
int height = 600;
|
||||
|
||||
// Texture quality.
|
||||
TextureQualityRequest texture_quality_requested;
|
||||
std::string texqualstr =
|
||||
g_base->app_config->Resolve(AppConfig::StringID::kTextureQuality);
|
||||
|
||||
if (texqualstr == "Auto") {
|
||||
texture_quality_requested = TextureQualityRequest::kAuto;
|
||||
} else if (texqualstr == "High") {
|
||||
texture_quality_requested = TextureQualityRequest::kHigh;
|
||||
} else if (texqualstr == "Medium") {
|
||||
texture_quality_requested = TextureQualityRequest::kMedium;
|
||||
} else if (texqualstr == "Low") {
|
||||
texture_quality_requested = TextureQualityRequest::kLow;
|
||||
} else {
|
||||
Log(LogLevel::kError,
|
||||
"Invalid texture quality: '" + texqualstr + "'; defaulting to low.");
|
||||
texture_quality_requested = TextureQualityRequest::kLow;
|
||||
}
|
||||
|
||||
// Graphics quality.
|
||||
std::string gqualstr =
|
||||
g_base->app_config->Resolve(AppConfig::StringID::kGraphicsQuality);
|
||||
GraphicsQualityRequest graphics_quality_requested;
|
||||
|
||||
if (gqualstr == "Auto") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kAuto;
|
||||
} else if (gqualstr == "Higher") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kHigher;
|
||||
} else if (gqualstr == "High") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kHigh;
|
||||
} else if (gqualstr == "Medium") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kMedium;
|
||||
} else if (gqualstr == "Low") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kLow;
|
||||
} else {
|
||||
Log(LogLevel::kError,
|
||||
"Invalid graphics quality: '" + gqualstr + "'; defaulting to auto.");
|
||||
graphics_quality_requested = GraphicsQualityRequest::kAuto;
|
||||
}
|
||||
|
||||
// Android res string.
|
||||
std::string android_res =
|
||||
g_base->app_config->Resolve(AppConfig::StringID::kResolutionAndroid);
|
||||
|
||||
bool fullscreen = g_base->app_config->Resolve(AppConfig::BoolID::kFullscreen);
|
||||
|
||||
// Note: when the graphics-thread applies the first set-screen event it will
|
||||
// trigger the remainder of startup such as media-loading; make sure nothing
|
||||
// below this point will affect that.
|
||||
g_base->graphics_server->PushSetScreenCall(
|
||||
fullscreen, width, height, texture_quality_requested,
|
||||
graphics_quality_requested, android_res);
|
||||
|
||||
show_fps_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowFPS);
|
||||
show_ping_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowPing);
|
||||
tv_border_ = g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder);
|
||||
|
||||
g_base->graphics_server->PushSetScreenGammaCall(
|
||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenGamma));
|
||||
g_base->graphics_server->PushSetScreenPixelScaleCall(
|
||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenPixelScale));
|
||||
|
||||
// V-sync setting.
|
||||
std::string v_sync =
|
||||
g_base->app_config->Resolve(AppConfig::StringID::kVerticalSync);
|
||||
bool do_v_sync{};
|
||||
bool auto_v_sync{};
|
||||
if (v_sync == "Auto") {
|
||||
do_v_sync = true;
|
||||
auto_v_sync = true;
|
||||
} else if (v_sync == "Always") {
|
||||
do_v_sync = true;
|
||||
auto_v_sync = false;
|
||||
} else if (v_sync == "Never") {
|
||||
do_v_sync = false;
|
||||
auto_v_sync = false;
|
||||
} else {
|
||||
do_v_sync = false;
|
||||
auto_v_sync = false;
|
||||
Log(LogLevel::kError, "Invalid 'Vertical Sync' value: '" + v_sync + "'");
|
||||
}
|
||||
g_base->graphics_server->PushSetVSyncCall(do_v_sync, auto_v_sync);
|
||||
|
||||
bool disable_camera_shake =
|
||||
g_base->app_config->Resolve(AppConfig::BoolID::kDisableCameraShake);
|
||||
set_camera_shake_disabled(disable_camera_shake);
|
||||
@ -218,6 +143,66 @@ void Graphics::RunCleanFrameCommands() {
|
||||
clean_frame_commands_.clear();
|
||||
}
|
||||
|
||||
auto Graphics::TextureQualityFromAppConfig() -> TextureQualityRequest {
|
||||
// Texture quality.
|
||||
TextureQualityRequest texture_quality_requested;
|
||||
std::string texqualstr =
|
||||
g_base->app_config->Resolve(AppConfig::StringID::kTextureQuality);
|
||||
|
||||
if (texqualstr == "Auto") {
|
||||
texture_quality_requested = TextureQualityRequest::kAuto;
|
||||
} else if (texqualstr == "High") {
|
||||
texture_quality_requested = TextureQualityRequest::kHigh;
|
||||
} else if (texqualstr == "Medium") {
|
||||
texture_quality_requested = TextureQualityRequest::kMedium;
|
||||
} else if (texqualstr == "Low") {
|
||||
texture_quality_requested = TextureQualityRequest::kLow;
|
||||
} else {
|
||||
Log(LogLevel::kError,
|
||||
"Invalid texture quality: '" + texqualstr + "'; defaulting to low.");
|
||||
texture_quality_requested = TextureQualityRequest::kLow;
|
||||
}
|
||||
return texture_quality_requested;
|
||||
}
|
||||
|
||||
auto Graphics::VSyncFromAppConfig() -> VSyncRequest {
|
||||
std::string v_sync =
|
||||
g_base->app_config->Resolve(AppConfig::StringID::kVerticalSync);
|
||||
if (v_sync == "Auto") {
|
||||
return VSyncRequest::kAuto;
|
||||
} else if (v_sync == "Always") {
|
||||
return VSyncRequest::kAuto;
|
||||
} else if (v_sync == "Never") {
|
||||
return VSyncRequest::kNever;
|
||||
}
|
||||
Log(LogLevel::kError, "Invalid 'Vertical Sync' value: '" + v_sync + "'");
|
||||
return VSyncRequest::kNever;
|
||||
}
|
||||
|
||||
auto Graphics::GraphicsQualityFromAppConfig() -> GraphicsQualityRequest {
|
||||
// Graphics quality.
|
||||
std::string gqualstr =
|
||||
g_base->app_config->Resolve(AppConfig::StringID::kGraphicsQuality);
|
||||
GraphicsQualityRequest graphics_quality_requested;
|
||||
|
||||
if (gqualstr == "Auto") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kAuto;
|
||||
} else if (gqualstr == "Higher") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kHigher;
|
||||
} else if (gqualstr == "High") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kHigh;
|
||||
} else if (gqualstr == "Medium") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kMedium;
|
||||
} else if (gqualstr == "Low") {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kLow;
|
||||
} else {
|
||||
Log(LogLevel::kError,
|
||||
"Invalid graphics quality: '" + gqualstr + "'; defaulting to auto.");
|
||||
graphics_quality_requested = GraphicsQualityRequest::kAuto;
|
||||
}
|
||||
return graphics_quality_requested;
|
||||
}
|
||||
|
||||
void Graphics::SetGyroEnabled(bool enable) {
|
||||
// If we're turning back on, suppress gyro updates for a bit.
|
||||
if (enable && !gyro_enabled_) {
|
||||
@ -1452,9 +1437,9 @@ void Graphics::DrawCursor(FrameDef* frame_def) {
|
||||
|| real_time - last_cursor_visibility_event_time_ > 2000) {
|
||||
hardware_cursor_visible_ = new_cursor_visibility;
|
||||
last_cursor_visibility_event_time_ = real_time;
|
||||
g_core->main_event_loop()->PushCall([this] {
|
||||
g_base->app_adapter->PushMainThreadCall([this] {
|
||||
assert(g_core && g_core->InMainThread());
|
||||
g_core->platform->SetHardwareCursorVisible(hardware_cursor_visible_);
|
||||
g_base->platform->SetHardwareCursorVisible(hardware_cursor_visible_);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -1899,6 +1884,10 @@ void Graphics::SetScreenSize(float virtual_width, float virtual_height,
|
||||
|
||||
// Need to rebuild internal components (some are sized to the screen).
|
||||
internal_components_inited_ = false;
|
||||
|
||||
// This will inform all applicable logic thread subsystems.
|
||||
g_base->logic->OnScreenSizeChange(virtual_width, virtual_height, pixel_width,
|
||||
pixel_height);
|
||||
}
|
||||
|
||||
void Graphics::ScreenMessageEntry::UpdateTranslation() {
|
||||
|
||||
@ -50,8 +50,8 @@ const float kCursorZDepth{0.9f};
|
||||
// Client class for graphics operations (used from the logic thread).
|
||||
class Graphics {
|
||||
public:
|
||||
Graphics();
|
||||
virtual ~Graphics();
|
||||
/// Instantiate the Graphics subclass for the current build.
|
||||
static auto Create() -> Graphics*;
|
||||
|
||||
void OnAppStart();
|
||||
void OnAppPause();
|
||||
@ -61,10 +61,16 @@ class Graphics {
|
||||
void OnScreenSizeChange();
|
||||
void DoApplyAppConfig();
|
||||
|
||||
/// Called by the graphics server to keep us up to date in the logic
|
||||
/// thread. Dispatches the news to all logic subsystems that care.
|
||||
void SetScreenSize(float virtual_width, float virtual_height,
|
||||
float physical_width, float physical_height);
|
||||
void StepDisplayTime();
|
||||
|
||||
auto TextureQualityFromAppConfig() -> TextureQualityRequest;
|
||||
auto GraphicsQualityFromAppConfig() -> GraphicsQualityRequest;
|
||||
auto VSyncFromAppConfig() -> VSyncRequest;
|
||||
|
||||
static auto IsShaderTransparent(ShadingType c) -> bool;
|
||||
static auto CubeMapFromReflectionType(ReflectionType reflection_type)
|
||||
-> SysCubeMapTextureID;
|
||||
@ -265,11 +271,13 @@ class Graphics {
|
||||
}
|
||||
return y * (res_y_virtual_ / res_y_);
|
||||
}
|
||||
|
||||
// FIXME: This should probably move to Renderer or AppAdapter once we
|
||||
// support switching renderers.
|
||||
auto supports_high_quality_graphics() const -> bool {
|
||||
assert(has_supports_high_quality_graphics_value_);
|
||||
return supports_high_quality_graphics_;
|
||||
}
|
||||
|
||||
void SetSupportsHighQualityGraphics(bool s);
|
||||
auto has_supports_high_quality_graphics_value() const -> bool {
|
||||
return has_supports_high_quality_graphics_value_;
|
||||
@ -319,6 +327,8 @@ class Graphics {
|
||||
}
|
||||
|
||||
protected:
|
||||
Graphics();
|
||||
virtual ~Graphics();
|
||||
virtual void DoDrawFade(FrameDef* frame_def, float amt);
|
||||
|
||||
private:
|
||||
|
||||
@ -2,50 +2,35 @@
|
||||
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
|
||||
// Kill this.
|
||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||
#include "ballistica/base/logic/logic.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
|
||||
// FIXME: clear out this conditional stuff.
|
||||
#if BA_SDL_BUILD
|
||||
#include "ballistica/base/app_adapter/app_adapter_sdl.h"
|
||||
#else
|
||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||
#endif
|
||||
|
||||
#include "ballistica/base/assets/assets.h"
|
||||
#include "ballistica/base/graphics/mesh/mesh_data.h"
|
||||
#include "ballistica/base/graphics/renderer/renderer.h"
|
||||
#include "ballistica/base/graphics/support/frame_def.h"
|
||||
#include "ballistica/base/logic/logic.h"
|
||||
#include "ballistica/core/platform/core_platform.h"
|
||||
#endif
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_XCODE_NEW_PROJECT
|
||||
void GraphicsServer::FullscreenCheck() {
|
||||
if (!fullscreen_enabled()) {
|
||||
#if BA_ENABLE_OPENGL
|
||||
SDL_WM_ToggleFullScreen(gl_context_->sdl_screen_surface());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
GraphicsServer::GraphicsServer() : event_loop_(g_core->main_event_loop()) {}
|
||||
|
||||
GraphicsServer::~GraphicsServer() { assert(g_base->graphics); }
|
||||
GraphicsServer::GraphicsServer() {}
|
||||
GraphicsServer::~GraphicsServer() = default;
|
||||
|
||||
void GraphicsServer::SetRenderHold() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
render_hold_++;
|
||||
}
|
||||
|
||||
void GraphicsServer::OnMainThreadStartApp() {
|
||||
// For janky old non-event-push mode, just fall back on a timer for rendering.
|
||||
if (!g_core->platform->IsEventPushMode()) {
|
||||
render_timer_ = this->event_loop()->NewTimer(
|
||||
1000 / 60, true, NewLambdaRunnable([this] { TryRender(); }));
|
||||
}
|
||||
}
|
||||
void GraphicsServer::OnMainThreadStartApp() {}
|
||||
|
||||
void GraphicsServer::EnqueueFrameDef(FrameDef* framedef) {
|
||||
// Note: we're just setting the framedef directly here even though this
|
||||
@ -54,13 +39,42 @@ void GraphicsServer::EnqueueFrameDef(FrameDef* framedef) {
|
||||
// for new frames to appear which would prevent that from working; we
|
||||
// would need to change that code.
|
||||
{
|
||||
std::scoped_lock llock(frame_def_mutex_);
|
||||
std::scoped_lock frame_def_lock(frame_def_mutex_);
|
||||
assert(frame_def_ == nullptr);
|
||||
frame_def_ = framedef;
|
||||
}
|
||||
}
|
||||
|
||||
auto GraphicsServer::GetRenderFrameDef() -> FrameDef* {
|
||||
auto GraphicsServer::TryRender() -> bool {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
bool success{};
|
||||
|
||||
if (FrameDef* frame_def = WaitForRenderFrameDef_()) {
|
||||
// Apply settings such as tv-mode that were passed along via the
|
||||
// frame-def.
|
||||
ApplyFrameDefSettings(frame_def);
|
||||
|
||||
// Note: we run mesh-updates on each frame-def that comes through even
|
||||
// if we don't actually render the frame.
|
||||
RunFrameDefMeshUpdates(frame_def);
|
||||
|
||||
// Only actually render if we have a screen and aren't in a hold.
|
||||
auto target = renderer()->screen_render_target();
|
||||
if (target != nullptr && render_hold_ == 0) {
|
||||
PreprocessRenderFrameDef(frame_def);
|
||||
DrawRenderFrameDef(frame_def);
|
||||
FinishRenderFrameDef(frame_def);
|
||||
success = true;
|
||||
}
|
||||
|
||||
// Send this frame_def back to the logic thread for deletion or recycling.
|
||||
g_base->graphics->ReturnCompletedFrameDef(frame_def);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
auto GraphicsServer::WaitForRenderFrameDef_() -> FrameDef* {
|
||||
assert(g_base->InGraphicsThread());
|
||||
millisecs_t app_time = g_core->GetAppTimeMillisecs();
|
||||
|
||||
@ -68,8 +82,7 @@ auto GraphicsServer::GetRenderFrameDef() -> FrameDef* {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the app says it's minimized, don't do anything (on iOS we'll get
|
||||
// shut down if we make GL calls in this state, etc).
|
||||
// If the app is paused, never render.
|
||||
if (g_base->app_adapter->app_paused()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -95,11 +108,10 @@ auto GraphicsServer::GetRenderFrameDef() -> FrameDef* {
|
||||
return frame_def;
|
||||
}
|
||||
|
||||
// If there's no frame_def for us, sleep for a bit and wait for it.
|
||||
// But if we've been waiting for too long, give up.
|
||||
// On some platforms such as Android, this frame will still get flipped
|
||||
// whether we draw in it or not, so we *really* want to not skip drawing
|
||||
// if we can help it.
|
||||
// If there's no frame_def for us, sleep for a bit and wait for it. But
|
||||
// if we've been waiting for too long, give up. On some platforms such
|
||||
// as Android, this frame will still get flipped whether we draw in it
|
||||
// or not, so we *really* want to not skip drawing if we can help it.
|
||||
millisecs_t t = g_core->GetAppTimeMillisecs() - app_time;
|
||||
if (t >= 1000) {
|
||||
if (g_buildconfig.debug_build()) {
|
||||
@ -129,6 +141,7 @@ void GraphicsServer::RunFrameDefMeshUpdates(FrameDef* frame_def) {
|
||||
i->iterator_ = mesh_datas_.insert(mesh_datas_.end(), i);
|
||||
i->Load(renderer_);
|
||||
}
|
||||
|
||||
for (auto&& i : frame_def->mesh_data_destroys()) {
|
||||
assert(i != nullptr);
|
||||
i->Unload(renderer_);
|
||||
@ -161,40 +174,11 @@ void GraphicsServer::FinishRenderFrameDef(FrameDef* frame_def) {
|
||||
assert(renderer_);
|
||||
if (renderer_) {
|
||||
renderer_->FinishFrameDef(frame_def);
|
||||
|
||||
// Let the app know a frame render is complete (it may need to do a
|
||||
// swap/etc).
|
||||
g_base->app_adapter->DidFinishRenderingFrame(frame_def);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsServer::TryRender() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
if (FrameDef* frame_def = GetRenderFrameDef()) {
|
||||
// Apply settings such as tv-mode that were passed along on the
|
||||
// frame-def.
|
||||
ApplyFrameDefSettings(frame_def);
|
||||
|
||||
// Note: we run mesh-updates on each frame-def that comes through even
|
||||
// if we don't actually render the frame.
|
||||
RunFrameDefMeshUpdates(frame_def);
|
||||
|
||||
// Only actually render if we have a screen and aren't in a hold.
|
||||
auto target = renderer()->screen_render_target();
|
||||
if (target != nullptr && render_hold_ == 0) {
|
||||
PreprocessRenderFrameDef(frame_def);
|
||||
DrawRenderFrameDef(frame_def);
|
||||
FinishRenderFrameDef(frame_def);
|
||||
}
|
||||
|
||||
// Send this frame_def back to the logic thread for deletion or recycling.
|
||||
g_base->graphics->ReturnCompletedFrameDef(frame_def);
|
||||
}
|
||||
}
|
||||
|
||||
// Reload all media (for debugging/benchmarking purposes).
|
||||
void GraphicsServer::ReloadMedia() {
|
||||
void GraphicsServer::ReloadMedia_() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
// Immediately unload all renderer data here in this thread.
|
||||
@ -210,8 +194,8 @@ void GraphicsServer::ReloadMedia() {
|
||||
SetRenderHold();
|
||||
|
||||
// Now tell the logic thread to kick off loads for everything, flip on
|
||||
// progress bar drawing, and then tell the graphics thread to stop ignoring
|
||||
// frame-defs.
|
||||
// progress bar drawing, and then tell the graphics thread to stop
|
||||
// ignoring frame-defs.
|
||||
g_base->logic->event_loop()->PushCall([this] {
|
||||
g_base->assets->MarkAllAssetsForLoad();
|
||||
g_base->graphics->EnableProgressBar(false);
|
||||
@ -219,12 +203,12 @@ void GraphicsServer::ReloadMedia() {
|
||||
});
|
||||
}
|
||||
|
||||
// Call when renderer context has been lost.
|
||||
void GraphicsServer::RebuildLostContext() {
|
||||
// Call when a renderer context has been lost.
|
||||
void GraphicsServer::ReloadLostRenderer() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
if (!renderer_) {
|
||||
Log(LogLevel::kError, "No renderer on GraphicsServer::_rebuildContext.");
|
||||
Log(LogLevel::kError, "No renderer on GraphicsServer::ReloadLostRenderer.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -232,7 +216,7 @@ void GraphicsServer::RebuildLostContext() {
|
||||
// down itself.
|
||||
set_renderer_context_lost(true);
|
||||
|
||||
// Unload all texture and mesh data here in the render thread.
|
||||
// Unload all texture and mesh data here in the graphics thread.
|
||||
g_base->assets->UnloadRendererBits(true, true);
|
||||
|
||||
// Also unload dynamic meshes.
|
||||
@ -253,17 +237,17 @@ void GraphicsServer::RebuildLostContext() {
|
||||
i->Load(renderer_);
|
||||
}
|
||||
|
||||
renderer_->ScreenSizeChanged();
|
||||
renderer_->OnScreenSizeChange();
|
||||
|
||||
// Set a render-hold so we ignore all frame_defs up until the point at which
|
||||
// we receive the corresponding remove-hold.
|
||||
// (At which point subsequent frame-defs will be be progress-bar frame_defs so
|
||||
// we won't hitch if we actually render them.)
|
||||
// Set a render-hold so we ignore all frame_defs up until the point at
|
||||
// which we receive the corresponding remove-hold. (At which point
|
||||
// subsequent frame-defs will be be progress-bar frame_defs so we won't
|
||||
// hitch if we actually render them.)
|
||||
SetRenderHold();
|
||||
|
||||
// Now tell the logic thread to kick off loads for everything, flip on
|
||||
// progress bar drawing, and then tell the graphics thread to stop ignoring
|
||||
// frame-defs.
|
||||
// progress bar drawing, and then tell the graphics thread to stop
|
||||
// ignoring frame-defs.
|
||||
g_base->logic->event_loop()->PushCall([this] {
|
||||
g_base->assets->MarkAllAssetsForLoad();
|
||||
g_base->graphics->EnableProgressBar(false);
|
||||
@ -271,176 +255,43 @@ void GraphicsServer::RebuildLostContext() {
|
||||
});
|
||||
}
|
||||
|
||||
void GraphicsServer::SetScreen(
|
||||
bool fullscreen, int width, int height,
|
||||
TextureQualityRequest texture_quality_requested,
|
||||
GraphicsQualityRequest graphics_quality_requested,
|
||||
const std::string& android_res) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
void GraphicsServer::SetNullGraphics() {
|
||||
// We don't actually make or update a renderer in headless, but we
|
||||
// still need to set our list of supported textures types/etc. to avoid
|
||||
// complaints.
|
||||
std::list<TextureCompressionType> c_types;
|
||||
SetTextureCompressionTypes(c_types);
|
||||
graphics_quality_requested_ = GraphicsQualityRequest::kLow;
|
||||
graphics_quality_ = GraphicsQuality::kLow;
|
||||
graphics_quality_set_ = true;
|
||||
texture_quality_requested_ = TextureQualityRequest::kLow;
|
||||
texture_quality_ = TextureQuality::kLow;
|
||||
texture_quality_set_ = true;
|
||||
|
||||
// If we know what we support, filter request types to those we support.
|
||||
// (will keep us from rebuilding contexts if request type is flipping between
|
||||
// different types we don't support).
|
||||
if (g_base->graphics->has_supports_high_quality_graphics_value()) {
|
||||
if (!g_base->graphics->supports_high_quality_graphics()
|
||||
&& graphics_quality_requested > GraphicsQualityRequest::kMedium) {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kMedium;
|
||||
}
|
||||
}
|
||||
|
||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && BA_SDL_BUILD
|
||||
bool create_fullscreen_check_timer = false;
|
||||
#endif
|
||||
|
||||
bool do_toggle_fs = false;
|
||||
bool do_set_existing_fs = false;
|
||||
|
||||
if (g_core->HeadlessMode()) {
|
||||
// We don't actually make or update a renderer in headless, but we
|
||||
// still need to set our list of supported textures types/etc. to avoid
|
||||
// complaints.
|
||||
std::list<TextureCompressionType> c_types;
|
||||
SetTextureCompressionTypes(c_types);
|
||||
graphics_quality_requested_ = GraphicsQualityRequest::kLow;
|
||||
graphics_quality_ = GraphicsQuality::kLow;
|
||||
graphics_quality_set_ = true;
|
||||
texture_quality_requested_ = TextureQualityRequest::kLow;
|
||||
texture_quality_ = TextureQuality::kLow;
|
||||
texture_quality_set_ = true;
|
||||
} else {
|
||||
// OK - starting in SDL2 we never pass in specific resolution requests.
|
||||
// we request fullscreen-windows for full-screen situations and that's it.
|
||||
// (otherwise we may wind up with huge windows due to passing in desktop
|
||||
// resolutions and retina wonkiness)
|
||||
width = static_cast<int>(kBaseVirtualResX * 0.8f);
|
||||
height = static_cast<int>(kBaseVirtualResY * 0.8f);
|
||||
|
||||
// We should never have to recreate the context after the initial time on
|
||||
// our modern builds.
|
||||
bool need_full_context_rebuild = (!renderer_);
|
||||
bool need_renderer_reload;
|
||||
|
||||
// We need a full renderer reload if quality values have changed.
|
||||
need_renderer_reload =
|
||||
((texture_quality_requested_ != texture_quality_requested)
|
||||
|| (graphics_quality_requested_ != graphics_quality_requested)
|
||||
|| !texture_quality_set() || !graphics_quality_set());
|
||||
|
||||
// This stuff requires a full context rebuild.
|
||||
if (need_full_context_rebuild || need_renderer_reload) {
|
||||
HandleFullContextScreenRebuild(need_full_context_rebuild, fullscreen,
|
||||
width, height, graphics_quality_requested,
|
||||
texture_quality_requested);
|
||||
// On mac, we let window save/restore handle our fullscreen restoring for
|
||||
// us. However if document restore is turned off we'll start windowed on
|
||||
// every launch. So if we're trying to make a fullscreen setup, lets
|
||||
// check after a short delay to make sure we have it, and run a
|
||||
// full-screen-toggle ourself if not.
|
||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && BA_SDL_BUILD
|
||||
if (fullscreen) {
|
||||
create_fullscreen_check_timer = true;
|
||||
}
|
||||
#endif // BA_OSTYPE_MACOS
|
||||
|
||||
} else {
|
||||
// on SDL2 builds we can just set fullscreen on the existing window; no
|
||||
// need for a context rebuild
|
||||
#if BA_SDL2_BUILD
|
||||
do_set_existing_fs = true;
|
||||
#else
|
||||
// On our old custom SDL1.2 mac build, fullscreen toggling winds up here.
|
||||
// this doesn't require a context rebuild either.
|
||||
if (fullscreen != fullscreen_enabled()) {
|
||||
do_toggle_fs = true;
|
||||
}
|
||||
#endif // BA_SDL2_BUILD
|
||||
}
|
||||
|
||||
HandlePushAndroidRes(android_res);
|
||||
|
||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && BA_SDL_BUILD
|
||||
if (create_fullscreen_check_timer) {
|
||||
event_loop()->NewTimer(1000, false,
|
||||
NewLambdaRunnable([this] { FullscreenCheck(); }));
|
||||
}
|
||||
#endif // BA_OSTYPE_MACOS
|
||||
|
||||
HandleFullscreenToggling(do_set_existing_fs, do_toggle_fs, fullscreen);
|
||||
}
|
||||
|
||||
// The first time we complete setting up our screen, we send a message
|
||||
// back to the logic thread to complete the init process. (they can't start
|
||||
// loading graphics and things until we have our context set up so we know
|
||||
// what types of textures to load, etc)
|
||||
if (!initial_screen_created_) {
|
||||
initial_screen_created_ = true;
|
||||
g_base->logic->event_loop()->PushCall(
|
||||
[] { g_base->logic->OnInitialScreenCreated(); });
|
||||
}
|
||||
// Let the logic thread know screen creation is done (or lack thereof).
|
||||
g_base->logic->event_loop()->PushCall(
|
||||
[] { g_base->logic->OnGraphicsReady(); });
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "ConstantConditionsOC"
|
||||
#pragma ide diagnostic ignored "ConstantParameter"
|
||||
|
||||
void GraphicsServer::HandleFullContextScreenRebuild(
|
||||
bool need_full_context_rebuild, bool fullscreen, int width, int height,
|
||||
GraphicsQualityRequest graphics_quality_requested,
|
||||
TextureQualityRequest texture_quality_requested) {
|
||||
// Unload renderer-specific data (display-lists, internal textures, etc)
|
||||
if (renderer_) {
|
||||
// Unload all textures and meshes. These will be reloaded as-needed
|
||||
// automatically for the new context.
|
||||
g_base->assets->UnloadRendererBits(true, true);
|
||||
|
||||
// Also unload all dynamic meshes.
|
||||
for (auto&& i : mesh_datas_) {
|
||||
i->Unload(renderer_);
|
||||
}
|
||||
|
||||
// And all internal renderer stuff.
|
||||
renderer_->Unload();
|
||||
}
|
||||
|
||||
// Handle screen/context recreation.
|
||||
if (need_full_context_rebuild) {
|
||||
// On mac we store the values we *want* separate from those we get.. (so
|
||||
// we know when our request has changed; not our result).
|
||||
#if !(BA_OSTYPE_MACOS && BA_XCODE_BUILD)
|
||||
fullscreen_enabled_ = fullscreen;
|
||||
#endif
|
||||
|
||||
target_res_x_ = static_cast<float>(width);
|
||||
target_res_y_ = static_cast<float>(height);
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
gl_context_ = std::make_unique<GLContext>(width, height, fullscreen);
|
||||
res_x_ = static_cast<float>(gl_context_->res_x());
|
||||
res_y_ = static_cast<float>(gl_context_->res_y());
|
||||
#endif
|
||||
|
||||
UpdateVirtualScreenRes();
|
||||
|
||||
// Inform graphics client and logic thread subsystems of the change.
|
||||
g_base->logic->event_loop()->PushCall(
|
||||
[vx = res_x_virtual_, vy = res_y_virtual_, x = res_x_, y = res_y_] {
|
||||
g_base->graphics->SetScreenSize(vx, vy, x, y);
|
||||
g_base->logic->OnScreenSizeChange(vx, vy, x, y);
|
||||
});
|
||||
}
|
||||
void GraphicsServer::set_renderer(Renderer* renderer) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
assert(!renderer_loaded_);
|
||||
assert(!renderer_);
|
||||
renderer_ = renderer;
|
||||
}
|
||||
|
||||
void GraphicsServer::LoadRenderer() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (!renderer_) {
|
||||
#if BA_ENABLE_OPENGL
|
||||
renderer_ = new RendererGL();
|
||||
#endif
|
||||
Log(LogLevel::kError, "LoadRenderer() called with no renderer present.");
|
||||
return;
|
||||
}
|
||||
if (renderer_loaded_) {
|
||||
Log(LogLevel::kError,
|
||||
"LoadRenderer() called with an already-loaded renderer present.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we've done this first so we can properly set auto values and
|
||||
// whatnot.
|
||||
renderer_->CheckCapabilities();
|
||||
|
||||
// Update graphics quality based on request.
|
||||
graphics_quality_requested_ = graphics_quality_requested;
|
||||
switch (graphics_quality_requested_) {
|
||||
case GraphicsQualityRequest::kLow:
|
||||
graphics_quality_ = GraphicsQuality::kLow;
|
||||
@ -474,7 +325,6 @@ void GraphicsServer::HandleFullContextScreenRebuild(
|
||||
graphics_quality_set_ = true;
|
||||
|
||||
// Update texture quality based on request.
|
||||
texture_quality_requested_ = texture_quality_requested;
|
||||
switch (texture_quality_requested_) {
|
||||
case TextureQualityRequest::kLow:
|
||||
texture_quality_ = TextureQuality::kLow;
|
||||
@ -503,18 +353,20 @@ void GraphicsServer::HandleFullContextScreenRebuild(
|
||||
for (auto&& i : mesh_datas_) {
|
||||
i->Load(renderer_);
|
||||
}
|
||||
renderer_->ScreenSizeChanged();
|
||||
renderer_->OnScreenSizeChange();
|
||||
renderer_->PostLoad();
|
||||
|
||||
// Set a render-hold so we ignore all frame_defs up until the point at which
|
||||
// we receive the corresponding remove-hold.
|
||||
// (At which point subsequent frame-defs will be be progress-bar frame_defs
|
||||
// so we won't hitch if we actually render them.)
|
||||
renderer_loaded_ = true;
|
||||
|
||||
// Set a render-hold so we ignore all frame_defs up until the point at
|
||||
// which we receive the corresponding remove-hold. (At which point
|
||||
// subsequent frame-defs will be be progress-bar frame_defs so we won't
|
||||
// hitch if we actually render them.)
|
||||
SetRenderHold();
|
||||
|
||||
// Now tell the logic thread to kick off loads for everything, flip on
|
||||
// progress bar drawing, and then tell the graphics thread to stop ignoring
|
||||
// frame-defs.
|
||||
// progress bar drawing, and then tell the graphics thread to stop
|
||||
// ignoring frame-defs.
|
||||
g_base->logic->event_loop()->PushCall([this] {
|
||||
g_base->assets->MarkAllAssetsForLoad();
|
||||
g_base->graphics->set_internal_components_inited(false);
|
||||
@ -523,24 +375,50 @@ void GraphicsServer::HandleFullContextScreenRebuild(
|
||||
});
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
void GraphicsServer::UnloadRenderer() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (!renderer_) {
|
||||
Log(LogLevel::kError, "UnloadRenderer() called with no renderer present.");
|
||||
return;
|
||||
}
|
||||
if (!renderer_loaded_) {
|
||||
Log(LogLevel::kError,
|
||||
"UnloadRenderer() called with an already unloaded renderer present.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Unload all textures and meshes. These will be reloaded on-demand for
|
||||
// the new context.
|
||||
g_base->assets->UnloadRendererBits(true, true);
|
||||
|
||||
// Also unload all dynamic meshes.
|
||||
for (auto&& i : mesh_datas_) {
|
||||
i->Unload(renderer_);
|
||||
}
|
||||
|
||||
// And all internal renderer stuff.
|
||||
renderer_->Unload();
|
||||
|
||||
renderer_loaded_ = false;
|
||||
}
|
||||
|
||||
// Given physical res, calculate virtual res.
|
||||
void GraphicsServer::CalcVirtualRes(float* x, float* y) {
|
||||
float x_in = (*x);
|
||||
float y_in = (*y);
|
||||
if ((*x) / (*y) > static_cast<float>(kBaseVirtualResX)
|
||||
/ static_cast<float>(kBaseVirtualResY)) {
|
||||
(*y) = kBaseVirtualResY;
|
||||
(*x) = (*y) * (x_in / y_in);
|
||||
void GraphicsServer::CalcVirtualRes_(float* x, float* y) {
|
||||
float x_in = *x;
|
||||
float y_in = *y;
|
||||
if (*x / *y > static_cast<float>(kBaseVirtualResX)
|
||||
/ static_cast<float>(kBaseVirtualResY)) {
|
||||
*y = kBaseVirtualResY;
|
||||
*x = *y * (x_in / y_in);
|
||||
} else {
|
||||
*x = kBaseVirtualResX;
|
||||
*y = (*x) * (y_in / x_in);
|
||||
*y = *x * (y_in / x_in);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsServer::UpdateVirtualScreenRes() {
|
||||
void GraphicsServer::UpdateVirtualScreenRes_() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
// In vr mode our virtual res is independent of our screen size.
|
||||
// (since it gets drawn to an overlay)
|
||||
if (g_core->IsVRMode()) {
|
||||
@ -549,33 +427,30 @@ void GraphicsServer::UpdateVirtualScreenRes() {
|
||||
} else {
|
||||
res_x_virtual_ = res_x_;
|
||||
res_y_virtual_ = res_y_;
|
||||
CalcVirtualRes(&res_x_virtual_, &res_y_virtual_);
|
||||
CalcVirtualRes_(&res_x_virtual_, &res_y_virtual_);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsServer::SetScreenResolution(float h, float v) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
if (target_res_x_ == h && target_res_y_ == v) {
|
||||
// Ignore redundant sets.
|
||||
if (res_x_ == h && res_y_ == v) {
|
||||
return;
|
||||
}
|
||||
|
||||
target_res_x_ = h;
|
||||
target_res_y_ = v;
|
||||
res_x_ = h;
|
||||
res_y_ = v;
|
||||
UpdateVirtualScreenRes();
|
||||
UpdateVirtualScreenRes_();
|
||||
|
||||
// Inform renderer of the change.
|
||||
if (renderer_) {
|
||||
renderer_->ScreenSizeChanged();
|
||||
renderer_->OnScreenSizeChange();
|
||||
}
|
||||
|
||||
// Inform graphics client and logic thread subsystems of the change.
|
||||
// Inform all logic thread bits of this change.
|
||||
g_base->logic->event_loop()->PushCall(
|
||||
[vx = res_x_virtual_, vy = res_y_virtual_, x = res_x_, y = res_y_] {
|
||||
g_base->graphics->SetScreenSize(vx, vy, x, y);
|
||||
g_base->logic->OnScreenSizeChange(vx, vy, x, y);
|
||||
});
|
||||
}
|
||||
|
||||
@ -587,9 +462,10 @@ void GraphicsServer::HandlePushAndroidRes(const std::string& android_res) {
|
||||
return;
|
||||
}
|
||||
// We push android res to the java layer here. We don't actually worry
|
||||
// about screen-size-changed callbacks and whatnot, since those will happen
|
||||
// automatically once things actually change. We just want to be sure that
|
||||
// we have a renderer so we can calc what our auto res should be.
|
||||
// about screen-size-changed callbacks and whatnot, since those will
|
||||
// happen automatically once things actually change. We just want to be
|
||||
// sure that we have a renderer so we can calc what our auto res should
|
||||
// be.
|
||||
assert(renderer_);
|
||||
std::string fin_res;
|
||||
if (android_res == "Auto") {
|
||||
@ -601,52 +477,51 @@ void GraphicsServer::HandlePushAndroidRes(const std::string& android_res) {
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "ConstantConditionsOC"
|
||||
#pragma ide diagnostic ignored "ConstantParameter"
|
||||
// void GraphicsServer::HandleFullscreenToggling(bool do_set_existing_fs,
|
||||
// bool do_toggle_fs,
|
||||
// bool fullscreen) {
|
||||
// if (do_set_existing_fs) {
|
||||
// #if BA_SDL2_BUILD
|
||||
// bool rift_vr_mode = false;
|
||||
// #if BA_RIFT_BUILD
|
||||
// if (g_core->IsVRMode()) {
|
||||
// rift_vr_mode = true;
|
||||
// }
|
||||
// #endif // BA_RIFT_BUILD
|
||||
// if (explicit_bool(!rift_vr_mode)) {
|
||||
// #if BA_OSTYPE_IOS_TVOS
|
||||
// set_fullscreen_enabled(true);
|
||||
|
||||
void GraphicsServer::HandleFullscreenToggling(bool do_set_existing_fs,
|
||||
bool do_toggle_fs,
|
||||
bool fullscreen) {
|
||||
if (do_set_existing_fs) {
|
||||
#if BA_SDL2_BUILD
|
||||
bool rift_vr_mode = false;
|
||||
#if BA_RIFT_BUILD
|
||||
if (g_core->IsVRMode()) {
|
||||
rift_vr_mode = true;
|
||||
}
|
||||
#endif // BA_RIFT_BUILD
|
||||
if (explicit_bool(!rift_vr_mode)) {
|
||||
#if BA_OSTYPE_IOS_TVOS
|
||||
set_fullscreen_enabled(true);
|
||||
// #else // BA_OSTYPE_IOS_TVOS
|
||||
// auto* app_adapter_sdl = AppAdapterSDL::Get();
|
||||
// uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
// SDL_SetWindowFullscreen(app_adapter_sdl->sdl_window_,
|
||||
// fullscreen ? fullscreen_flag : 0);
|
||||
|
||||
#else // BA_OSTYPE_IOS_TVOS
|
||||
uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
SDL_SetWindowFullscreen(gl_context_->sdl_window(),
|
||||
fullscreen ? fullscreen_flag : 0);
|
||||
|
||||
// Ideally this should be driven by OS events and not just explicitly by
|
||||
// us (so, for instance, if someone presses fullscreen on mac we'd know
|
||||
// we've gone into fullscreen). But this works for now.
|
||||
set_fullscreen_enabled(fullscreen);
|
||||
#endif // BA_OSTYPE_IOS_TVOS
|
||||
}
|
||||
#endif // BA_SDL2_BUILD
|
||||
} else if (do_toggle_fs) {
|
||||
// If we're doing a fullscreen-toggle, we need to do it after coming out of
|
||||
// sync mode (because the toggle triggers sync-mode itself).
|
||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_XCODE_NEW_PROJECT
|
||||
#if BA_ENABLE_OPENGL
|
||||
SDL_WM_ToggleFullScreen(gl_context_->sdl_screen_surface());
|
||||
#endif
|
||||
#endif // macos && xcode_build
|
||||
}
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
// // Ideally this should be driven by OS events and not just explicitly
|
||||
// by
|
||||
// // us (so, for instance, if someone presses fullscreen on mac we'd know
|
||||
// // we've gone into fullscreen). But this works for now.
|
||||
// set_fullscreen_enabled(fullscreen);
|
||||
// #endif // BA_OSTYPE_IOS_TVOS
|
||||
// }
|
||||
// #endif // BA_SDL2_BUILD
|
||||
// } else if (do_toggle_fs) {
|
||||
// // If we're doing a fullscreen-toggle, we need to do it after coming out
|
||||
// of
|
||||
// // sync mode (because the toggle triggers sync-mode itself).
|
||||
// #if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_XCODE_NEW_PROJECT
|
||||
// #if BA_ENABLE_OPENGL
|
||||
// SDL_WM_ToggleFullScreen(gl_context_->sdl_screen_surface());
|
||||
// #endif
|
||||
// #endif // macos && xcode_build
|
||||
// }
|
||||
// }
|
||||
|
||||
void GraphicsServer::SetTextureCompressionTypes(
|
||||
const std::list<TextureCompressionType>& types) {
|
||||
texture_compression_types_ = 0; // Reset.
|
||||
assert(g_base->InGraphicsThread());
|
||||
texture_compression_types_ = 0;
|
||||
for (auto&& i : types) {
|
||||
texture_compression_types_ |= (0x01u << (static_cast<uint32_t>(i)));
|
||||
}
|
||||
@ -656,6 +531,7 @@ void GraphicsServer::SetTextureCompressionTypes(
|
||||
void GraphicsServer::SetOrthoProjection(float left, float right, float bottom,
|
||||
float top, float nearval,
|
||||
float farval) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
float tx = -((right + left) / (right - left));
|
||||
float ty = -((top + bottom) / (top - bottom));
|
||||
float tz = -((farval + nearval) / (farval - nearval));
|
||||
@ -695,26 +571,25 @@ void GraphicsServer::SetCamera(const Vector3f& eye, const Vector3f& target,
|
||||
auto side = Vector3f::Cross(forward, up_vector).Normalized();
|
||||
Vector3f up = Vector3f::Cross(side, forward);
|
||||
|
||||
//------------------
|
||||
model_view_matrix_.m[0] = side.x;
|
||||
model_view_matrix_.m[4] = side.y;
|
||||
model_view_matrix_.m[8] = side.z;
|
||||
model_view_matrix_.m[12] = 0.0f;
|
||||
//------------------
|
||||
|
||||
model_view_matrix_.m[1] = up.x;
|
||||
model_view_matrix_.m[5] = up.y;
|
||||
model_view_matrix_.m[9] = up.z;
|
||||
model_view_matrix_.m[13] = 0.0f;
|
||||
//------------------
|
||||
|
||||
model_view_matrix_.m[2] = -forward.x;
|
||||
model_view_matrix_.m[6] = -forward.y;
|
||||
model_view_matrix_.m[10] = -forward.z;
|
||||
model_view_matrix_.m[14] = 0.0f;
|
||||
//------------------
|
||||
|
||||
model_view_matrix_.m[3] = model_view_matrix_.m[7] = model_view_matrix_.m[11] =
|
||||
0.0f;
|
||||
model_view_matrix_.m[15] = 1.0f;
|
||||
//------------------
|
||||
|
||||
model_view_matrix_ =
|
||||
Matrix44fTranslate(-eye.x, -eye.y, -eye.z) * model_view_matrix_;
|
||||
view_world_matrix_ = model_view_matrix_.Inverse();
|
||||
@ -728,10 +603,7 @@ void GraphicsServer::SetCamera(const Vector3f& eye, const Vector3f& target,
|
||||
cam_orient_matrix_dirty_ = true;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "ConstantConditionsOC"
|
||||
|
||||
void GraphicsServer::UpdateCamOrientMatrix() {
|
||||
void GraphicsServer::UpdateCamOrientMatrix_() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (cam_orient_matrix_dirty_) {
|
||||
cam_orient_matrix_ = kMatrix44fIdentity;
|
||||
@ -758,37 +630,12 @@ void GraphicsServer::UpdateCamOrientMatrix() {
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#pragma mark PushCalls
|
||||
|
||||
void GraphicsServer::PushSetScreenCall(
|
||||
bool fullscreen, int width, int height,
|
||||
TextureQualityRequest texture_quality_request,
|
||||
GraphicsQualityRequest graphics_quality_request,
|
||||
const std::string& android_res) {
|
||||
event_loop()->PushCall([=] {
|
||||
SetScreen(fullscreen, width, height, texture_quality_request,
|
||||
graphics_quality_request, android_res);
|
||||
});
|
||||
}
|
||||
|
||||
void GraphicsServer::PushReloadMediaCall() {
|
||||
event_loop()->PushCall([this] { ReloadMedia(); });
|
||||
}
|
||||
|
||||
void GraphicsServer::PushSetScreenGammaCall(float gamma) {
|
||||
event_loop()->PushCall([this, gamma] {
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (!renderer_) {
|
||||
return;
|
||||
}
|
||||
renderer_->set_screen_gamma(gamma);
|
||||
});
|
||||
g_base->app_adapter->PushMainThreadCall([this] { ReloadMedia_(); });
|
||||
}
|
||||
|
||||
void GraphicsServer::PushSetScreenPixelScaleCall(float pixel_scale) {
|
||||
event_loop()->PushCall([this, pixel_scale] {
|
||||
g_base->app_adapter->PushMainThreadCall([this, pixel_scale] {
|
||||
assert(g_base->InGraphicsThread());
|
||||
if (!renderer_) {
|
||||
return;
|
||||
@ -797,38 +644,10 @@ void GraphicsServer::PushSetScreenPixelScaleCall(float pixel_scale) {
|
||||
});
|
||||
}
|
||||
|
||||
void GraphicsServer::PushSetVSyncCall(bool sync, bool auto_sync) {
|
||||
event_loop()->PushCall([this, sync, auto_sync] {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
#if BA_SDL_BUILD
|
||||
|
||||
// Currently only supported for AppAdapterSDL.
|
||||
// May want to revisit this later.
|
||||
if (g_buildconfig.sdl_build()) {
|
||||
// Even if we were built with SDL, we may not be running in sdl-app-mode
|
||||
// (for instance, Rift in VR mode). Only do this if we're an sdl app.
|
||||
if (auto app = dynamic_cast<AppAdapterSDL*>(g_base->app_adapter)) {
|
||||
v_sync_ = sync;
|
||||
auto_vsync_ = auto_sync;
|
||||
if (gl_context_) {
|
||||
app->SetAutoVSync(auto_vsync_);
|
||||
// Set it directly if not auto...
|
||||
if (!auto_vsync_) {
|
||||
gl_context_->SetVSync(v_sync_);
|
||||
}
|
||||
} else {
|
||||
Log(LogLevel::kError, "Got SetVSyncCall with no gl context_ref.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // BA_HEADLESS_BUILD
|
||||
});
|
||||
}
|
||||
|
||||
void GraphicsServer::PushComponentUnloadCall(
|
||||
const std::vector<Object::Ref<Asset>*>& components) {
|
||||
event_loop()->PushCall([components] {
|
||||
g_base->app_adapter->PushMainThreadCall([components] {
|
||||
assert(g_base->InGraphicsThread());
|
||||
// Unload the components.
|
||||
for (auto&& i : components) {
|
||||
(**i).Unload();
|
||||
@ -843,7 +662,8 @@ void GraphicsServer::PushComponentUnloadCall(
|
||||
}
|
||||
|
||||
void GraphicsServer::PushRemoveRenderHoldCall() {
|
||||
event_loop()->PushCall([this] {
|
||||
g_base->app_adapter->PushMainThreadCall([this] {
|
||||
assert(g_base->InGraphicsThread());
|
||||
assert(render_hold_);
|
||||
render_hold_--;
|
||||
if (render_hold_ < 0) {
|
||||
|
||||
@ -15,26 +15,58 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
/// A server that runs in the graphics thread and renders frame_defs shipped
|
||||
/// to it by the logic thread.
|
||||
/// A mechanism used by the AppAdapter to render frame-defs shipped from the
|
||||
/// logic thread. This may happen in the main thread or in other dedicated
|
||||
/// thread(s) depending on the AppAdapter and environment.
|
||||
class GraphicsServer {
|
||||
public:
|
||||
GraphicsServer();
|
||||
~GraphicsServer();
|
||||
|
||||
void OnMainThreadStartApp();
|
||||
|
||||
/// Should be called to inform ballistica of screen size changes; this
|
||||
/// will be applied to the server and then sent to the logic thread to
|
||||
/// apply to various app systems (ui, etc.).
|
||||
/// The current renderer.
|
||||
auto renderer() const { return renderer_; }
|
||||
|
||||
/// Assign a renderer.
|
||||
void set_renderer(Renderer* renderer);
|
||||
|
||||
/// Load the current renderer. This will lock in various things such as
|
||||
/// quality settings and will allow renderer-specific forms of assets and
|
||||
/// other components to be created.
|
||||
void LoadRenderer();
|
||||
|
||||
/// Unload the current renderer. Destroys all renderer-specific forms of
|
||||
/// assets and other components.
|
||||
void UnloadRenderer();
|
||||
|
||||
/// Call this if a renderer's context has been lost. This is basically
|
||||
/// an UnloadRenderer() followed by a LoadRenderer() except that the
|
||||
/// renderer is not asked to delete components during the unload.
|
||||
void ReloadLostRenderer();
|
||||
|
||||
/// Return whether the current renderer is loaded.
|
||||
auto renderer_loaded() const {
|
||||
assert(renderer_);
|
||||
return renderer_loaded_;
|
||||
}
|
||||
|
||||
/// The AppAdapter should call this to inform the engine of screen size
|
||||
/// changes. Changes will be applied to the server and then sent to the
|
||||
/// logic thread to apply to various app systems (ui, etc.).
|
||||
void SetScreenResolution(float h, float v);
|
||||
|
||||
void PushSetScreenGammaCall(float gamma);
|
||||
/// Used by headless builds to init the graphics-server into a
|
||||
/// non-functional state.
|
||||
void SetNullGraphics();
|
||||
|
||||
// void PushSetScreenGammaCall(float gamma);
|
||||
void PushSetScreenPixelScaleCall(float pixel_scale);
|
||||
void PushSetVSyncCall(bool sync, bool auto_sync);
|
||||
void PushSetScreenCall(bool fullscreen, int width, int height,
|
||||
TextureQualityRequest texture_quality_request,
|
||||
GraphicsQualityRequest graphics_quality_request,
|
||||
const std::string& android_res);
|
||||
// void PushSetVSyncCall(bool sync, bool auto_sync);
|
||||
// void PushSetScreenCall(bool fullscreen, int width, int height,
|
||||
// TextureQualityRequest texture_quality_request,
|
||||
// GraphicsQualityRequest graphics_quality_request,
|
||||
// const std::string& android_res);
|
||||
void PushReloadMediaCall();
|
||||
void PushRemoveRenderHoldCall();
|
||||
void PushComponentUnloadCall(
|
||||
@ -45,17 +77,11 @@ class GraphicsServer {
|
||||
/// rendering.
|
||||
void EnqueueFrameDef(FrameDef* framedef);
|
||||
|
||||
// Returns the next frame_def to be rendered, waiting for it to arrive if
|
||||
// necessary. this can return nullptr if no frame_defs come in within a
|
||||
// reasonable amount of time. a frame_def here *must* be rendered and
|
||||
// disposed of using the RenderFrameDef* calls.
|
||||
auto GetRenderFrameDef() -> FrameDef*;
|
||||
|
||||
void ApplyFrameDefSettings(FrameDef* frame_def);
|
||||
|
||||
void RunFrameDefMeshUpdates(FrameDef* frame_def);
|
||||
|
||||
// renders shadow passes and other common parts of a frame_def
|
||||
// Renders shadow passes and other common parts of a frame_def.
|
||||
void PreprocessRenderFrameDef(FrameDef* frame_def);
|
||||
|
||||
// Does the default drawing to the screen, either from the left or right
|
||||
@ -65,11 +91,11 @@ class GraphicsServer {
|
||||
// Clean up the frame_def once done drawing it.
|
||||
void FinishRenderFrameDef(FrameDef* frame_def);
|
||||
|
||||
// Equivalent to calling GetRenderFrameDef() and then preprocess, draw (in
|
||||
// mono), and finish.
|
||||
void TryRender();
|
||||
// Attempts to wait for a frame-def to come in and render it.
|
||||
// Returns true if a frame was rendered.
|
||||
auto TryRender() -> bool;
|
||||
|
||||
// init the modelview matrix to look here
|
||||
// Init the modelview matrix to look here.
|
||||
void SetCamera(const Vector3f& eye, const Vector3f& target,
|
||||
const Vector3f& up);
|
||||
|
||||
@ -109,42 +135,45 @@ class GraphicsServer {
|
||||
return light_shadow_projection_matrix_;
|
||||
}
|
||||
|
||||
// Returns the modelview * projection matrix.
|
||||
// Return the modelview * projection matrix.
|
||||
auto GetModelViewProjectionMatrix() -> const Matrix44f& {
|
||||
UpdateModelViewProjectionMatrix();
|
||||
UpdateModelViewProjectionMatrix_();
|
||||
return model_view_projection_matrix_;
|
||||
}
|
||||
|
||||
auto GetModelViewProjectionMatrixState() -> uint32_t {
|
||||
UpdateModelViewProjectionMatrix();
|
||||
UpdateModelViewProjectionMatrix_();
|
||||
return model_view_projection_matrix_state_;
|
||||
}
|
||||
|
||||
auto GetModelWorldMatrix() -> const Matrix44f& {
|
||||
UpdateModelWorldMatrix();
|
||||
UpdateModelWorldMatrix_();
|
||||
return model_world_matrix_;
|
||||
}
|
||||
|
||||
auto GetModelWorldMatrixState() -> uint32_t {
|
||||
UpdateModelWorldMatrix();
|
||||
UpdateModelWorldMatrix_();
|
||||
return model_world_matrix_state_;
|
||||
}
|
||||
|
||||
auto cam_pos() -> const Vector3f& { return cam_pos_; }
|
||||
|
||||
auto cam_pos_state() -> uint32_t { return cam_pos_state_; }
|
||||
|
||||
auto GetCamOrientMatrix() -> const Matrix44f& {
|
||||
UpdateCamOrientMatrix();
|
||||
UpdateCamOrientMatrix_();
|
||||
return cam_orient_matrix_;
|
||||
}
|
||||
|
||||
auto GetCamOrientMatrixState() -> uint32_t {
|
||||
UpdateCamOrientMatrix();
|
||||
UpdateCamOrientMatrix_();
|
||||
return cam_orient_matrix_state_;
|
||||
}
|
||||
|
||||
auto model_view_matrix() const -> const Matrix44f& {
|
||||
return model_view_matrix_;
|
||||
}
|
||||
|
||||
void SetModelViewMatrix(const Matrix44f& m) {
|
||||
model_view_matrix_ = m;
|
||||
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
|
||||
@ -153,6 +182,7 @@ class GraphicsServer {
|
||||
auto projection_matrix() const -> const Matrix44f& {
|
||||
return projection_matrix_;
|
||||
}
|
||||
|
||||
void PushTransform() {
|
||||
model_view_stack_.push_back(model_view_matrix_);
|
||||
assert(model_view_stack_.size() < 20);
|
||||
@ -185,10 +215,6 @@ class GraphicsServer {
|
||||
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
|
||||
}
|
||||
|
||||
void RebuildLostContext();
|
||||
~GraphicsServer();
|
||||
|
||||
auto renderer() { return renderer_; }
|
||||
auto quality() const -> GraphicsQuality {
|
||||
assert(graphics_quality_set_);
|
||||
return graphics_quality_;
|
||||
@ -203,6 +229,7 @@ class GraphicsServer {
|
||||
assert(g_base->InGraphicsThread());
|
||||
return res_x_;
|
||||
}
|
||||
|
||||
auto screen_pixel_height() const -> float {
|
||||
assert(g_base->InGraphicsThread());
|
||||
return res_y_;
|
||||
@ -212,16 +239,19 @@ class GraphicsServer {
|
||||
assert(g_base->InGraphicsThread());
|
||||
return res_x_virtual_;
|
||||
}
|
||||
|
||||
auto screen_virtual_height() const -> float {
|
||||
assert(g_base->InGraphicsThread());
|
||||
return res_y_virtual_;
|
||||
}
|
||||
|
||||
auto tv_border() const {
|
||||
assert(g_base->InGraphicsThread());
|
||||
return tv_border_;
|
||||
}
|
||||
|
||||
auto graphics_quality_set() const { return graphics_quality_set_; }
|
||||
|
||||
auto texture_quality_set() const { return texture_quality_set_; }
|
||||
|
||||
auto SupportsTextureCompressionType(TextureCompressionType t) const -> bool {
|
||||
@ -235,87 +265,90 @@ class GraphicsServer {
|
||||
auto texture_compression_types_are_set() const {
|
||||
return texture_compression_types_set_;
|
||||
}
|
||||
auto set_renderer_context_lost(bool lost) { renderer_context_lost_ = lost; }
|
||||
|
||||
void set_renderer_context_lost(bool lost) { renderer_context_lost_ = lost; }
|
||||
|
||||
auto renderer_context_lost() const { return renderer_context_lost_; }
|
||||
auto fullscreen_enabled() const { return fullscreen_enabled_; }
|
||||
|
||||
// auto fullscreen_enabled() const { return fullscreen_enabled_; }
|
||||
|
||||
// This doesn't actually toggle fullscreen. It is used to inform the game
|
||||
// when fullscreen changes under it.
|
||||
auto set_fullscreen_enabled(bool fs) { fullscreen_enabled_ = fs; }
|
||||
// auto set_fullscreen_enabled(bool fs) { fullscreen_enabled_ = fs; }
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
auto gl_context() const -> GLContext* { return gl_context_.get(); }
|
||||
#endif
|
||||
// #if BA_ENABLE_OPENGL
|
||||
// auto gl_context() const -> GLContext* { return gl_context_.get(); }
|
||||
// #endif
|
||||
|
||||
auto graphics_quality_requested() const {
|
||||
return graphics_quality_requested_;
|
||||
}
|
||||
|
||||
void set_graphics_quality_requested(GraphicsQualityRequest val) {
|
||||
graphics_quality_requested_ = val;
|
||||
}
|
||||
|
||||
void set_texture_quality_requested(TextureQualityRequest val) {
|
||||
texture_quality_requested_ = val;
|
||||
}
|
||||
|
||||
auto graphics_quality() const { return graphics_quality_; }
|
||||
|
||||
auto texture_quality_requested() const { return texture_quality_requested_; }
|
||||
auto renderer() const { return renderer_; }
|
||||
auto initial_screen_created() const { return initial_screen_created_; }
|
||||
auto event_loop() const -> EventLoop* { return event_loop_; }
|
||||
|
||||
// auto initial_screen_created() const { return initial_screen_created_; }
|
||||
|
||||
void HandlePushAndroidRes(const std::string& android_res);
|
||||
|
||||
// void HandleFullContextScreenRebuild(
|
||||
// bool need_full_context_rebuild, bool fullscreen,
|
||||
// GraphicsQualityRequest graphics_quality_requested,
|
||||
// TextureQualityRequest texture_quality_requested);
|
||||
// void HandleFullscreenToggling(bool do_set_existing_fs, bool do_toggle_fs,
|
||||
// bool fullscreen);
|
||||
|
||||
private:
|
||||
void HandleFullscreenToggling(bool do_set_existing_fs, bool do_toggle_fs,
|
||||
bool fullscreen);
|
||||
void HandlePushAndroidRes(const std::string& android_res);
|
||||
void HandleFullContextScreenRebuild(
|
||||
bool need_full_context_rebuild, bool fullscreen, int width, int height,
|
||||
GraphicsQualityRequest graphics_quality_requested,
|
||||
TextureQualityRequest texture_quality_requested);
|
||||
// Return the next frame_def to be rendered, waiting for it to arrive if
|
||||
// necessary. this can return nullptr if no frame_defs come in within a
|
||||
// reasonable amount of time. a frame_def here *must* be rendered and
|
||||
// disposed of using the RenderFrameDef* calls.
|
||||
auto WaitForRenderFrameDef_() -> FrameDef*;
|
||||
|
||||
// Update virtual screen dimensions based on the current physical ones.
|
||||
static void CalcVirtualRes(float* x, float* y);
|
||||
|
||||
void UpdateVirtualScreenRes();
|
||||
void UpdateCamOrientMatrix();
|
||||
void ReloadMedia();
|
||||
void UpdateModelViewProjectionMatrix() {
|
||||
static void CalcVirtualRes_(float* x, float* y);
|
||||
void UpdateVirtualScreenRes_();
|
||||
void UpdateCamOrientMatrix_();
|
||||
void ReloadMedia_();
|
||||
void UpdateModelViewProjectionMatrix_() {
|
||||
if (model_view_projection_matrix_dirty_) {
|
||||
model_view_projection_matrix_ = model_view_matrix_ * projection_matrix_;
|
||||
model_view_projection_matrix_state_++;
|
||||
model_view_projection_matrix_dirty_ = false;
|
||||
}
|
||||
}
|
||||
void UpdateModelWorldMatrix() {
|
||||
|
||||
void UpdateModelWorldMatrix_() {
|
||||
if (model_world_matrix_dirty_) {
|
||||
model_world_matrix_ = model_view_matrix_ * view_world_matrix_;
|
||||
model_world_matrix_state_++;
|
||||
model_world_matrix_dirty_ = false;
|
||||
}
|
||||
}
|
||||
void SetScreen(bool fullscreen, int width, int height,
|
||||
TextureQualityRequest texture_quality_request,
|
||||
GraphicsQualityRequest graphics_quality_request,
|
||||
const std::string& android_res);
|
||||
|
||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD
|
||||
void FullscreenCheck();
|
||||
#endif
|
||||
#if BA_ENABLE_OPENGL
|
||||
std::unique_ptr<GLContext> gl_context_;
|
||||
#endif
|
||||
EventLoop* event_loop_{};
|
||||
float res_x_{};
|
||||
float res_y_{};
|
||||
float res_x_virtual_{};
|
||||
float res_y_virtual_{};
|
||||
bool tv_border_{};
|
||||
bool renderer_context_lost_{};
|
||||
uint32_t texture_compression_types_{};
|
||||
bool texture_compression_types_set_{};
|
||||
TextureQualityRequest texture_quality_requested_{
|
||||
TextureQualityRequest::kUnset};
|
||||
TextureQuality texture_quality_{TextureQuality::kLow};
|
||||
GraphicsQualityRequest graphics_quality_requested_{
|
||||
GraphicsQualityRequest::kUnset};
|
||||
GraphicsQuality graphics_quality_{GraphicsQuality::kUnset};
|
||||
bool graphics_quality_set_{};
|
||||
bool texture_quality_set_{};
|
||||
bool fullscreen_enabled_{};
|
||||
float target_res_x_{800.0f};
|
||||
float target_res_y_{600.0f};
|
||||
// bool fullscreen_enabled_{};
|
||||
// float target_res_x_{800.0f};
|
||||
// float target_res_y_{600.0f};
|
||||
Matrix44f model_view_matrix_{kMatrix44fIdentity};
|
||||
Matrix44f view_world_matrix_{kMatrix44fIdentity};
|
||||
Matrix44f projection_matrix_{kMatrix44fIdentity};
|
||||
@ -325,8 +358,6 @@ class GraphicsServer {
|
||||
uint32_t projection_matrix_state_{1};
|
||||
uint32_t model_view_projection_matrix_state_{1};
|
||||
uint32_t model_world_matrix_state_{1};
|
||||
bool model_view_projection_matrix_dirty_{true};
|
||||
bool model_world_matrix_dirty_{true};
|
||||
Matrix44f light_shadow_projection_matrix_{kMatrix44fIdentity};
|
||||
uint32_t light_shadow_projection_matrix_state_{1};
|
||||
Vector3f cam_pos_{0.0f, 0.0f, 0.0f};
|
||||
@ -334,14 +365,22 @@ class GraphicsServer {
|
||||
uint32_t cam_pos_state_{1};
|
||||
Matrix44f cam_orient_matrix_ = kMatrix44fIdentity;
|
||||
uint32_t cam_orient_matrix_state_{1};
|
||||
bool cam_orient_matrix_dirty_{true};
|
||||
std::list<MeshData*> mesh_datas_;
|
||||
bool v_sync_{};
|
||||
bool auto_vsync_{};
|
||||
Timer* render_timer_{};
|
||||
Renderer* renderer_{};
|
||||
FrameDef* frame_def_{};
|
||||
bool initial_screen_created_{};
|
||||
// bool initial_screen_created_{};
|
||||
bool renderer_loaded_{};
|
||||
bool v_sync_{};
|
||||
bool auto_vsync_{};
|
||||
bool model_view_projection_matrix_dirty_{true};
|
||||
bool model_world_matrix_dirty_{true};
|
||||
bool graphics_quality_set_{};
|
||||
bool texture_quality_set_{};
|
||||
bool tv_border_{};
|
||||
bool renderer_context_lost_{};
|
||||
bool texture_compression_types_set_{};
|
||||
bool cam_orient_matrix_dirty_{true};
|
||||
int render_hold_{};
|
||||
std::mutex frame_def_mutex_{};
|
||||
};
|
||||
|
||||
@ -63,20 +63,21 @@ void GraphicsVR::DoDrawFade(FrameDef* frame_def, float amt) {
|
||||
Vector3f side = Vector3f::Cross(diff, Vector3f(0.0f, 1.0f, 0.0f));
|
||||
Vector3f up = Vector3f::Cross(diff, side);
|
||||
c.SetColor(0, 0, 0);
|
||||
c.PushTransform();
|
||||
// We start in vr-overlay screen space; get back to world.
|
||||
c.Translate(cam_pt.x, cam_pt.y, cam_pt.z);
|
||||
c.MultMatrix(Matrix44fOrient(diff, up).m);
|
||||
// At the very end we stay turned around so we get 100% black.
|
||||
if (amt < 0.98f) {
|
||||
c.Translate(0, 0, 40.0f * amt);
|
||||
c.Rotate(180, 1, 0, 0);
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
// We start in vr-overlay screen space; get back to world.
|
||||
c.Translate(cam_pt.x, cam_pt.y, cam_pt.z);
|
||||
c.MultMatrix(Matrix44fOrient(diff, up).m);
|
||||
// At the very end we stay turned around so we get 100% black.
|
||||
if (amt < 0.98f) {
|
||||
c.Translate(0, 0, 40.0f * amt);
|
||||
c.Rotate(180, 1, 0, 0);
|
||||
}
|
||||
float inv_a = 1.0f - amt;
|
||||
float s = 100.0f * inv_a + 5.0f * amt;
|
||||
c.Scale(s, s, s);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kVRFade));
|
||||
}
|
||||
float inv_a = 1.0f - amt;
|
||||
float s = 100.0f * inv_a + 5.0f * amt;
|
||||
c.Scale(s, s, s);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kVRFade));
|
||||
c.PopTransform();
|
||||
c.Submit();
|
||||
}
|
||||
|
||||
@ -281,13 +282,14 @@ void GraphicsVR::DrawVROverlay(FrameDef* frame_def) {
|
||||
// Draw our overlay-flat stuff into our overlay pass.
|
||||
SpecialComponent c(frame_def->overlay_pass(),
|
||||
SpecialComponent::Source::kVROverlayBuffer);
|
||||
c.PushTransform();
|
||||
c.Translate(0.5f * kBaseVirtualResX, 0.5f * kBaseVirtualResY, 0.0f);
|
||||
c.Scale(kBaseVirtualResX * (1.0f + kVRBorder),
|
||||
kBaseVirtualResY * (1.0f + kVRBorder),
|
||||
kBaseVirtualResX * (1.0f + kVRBorder));
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kVROverlay));
|
||||
c.PopTransform();
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.Translate(0.5f * kBaseVirtualResX, 0.5f * kBaseVirtualResY, 0.0f);
|
||||
c.Scale(kBaseVirtualResX * (1.0f + kVRBorder),
|
||||
kBaseVirtualResY * (1.0f + kVRBorder),
|
||||
kBaseVirtualResX * (1.0f + kVRBorder));
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kVROverlay));
|
||||
}
|
||||
c.Submit();
|
||||
}
|
||||
}
|
||||
@ -297,15 +299,16 @@ void GraphicsVR::DrawOverlayBounds(RenderPass* pass) {
|
||||
if (draw_overlay_bounds_) {
|
||||
SimpleComponent c(pass);
|
||||
c.SetColor(1, 0, 0);
|
||||
c.PushTransform();
|
||||
float width = screen_virtual_width();
|
||||
float height = screen_virtual_height();
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
float width = screen_virtual_width();
|
||||
float height = screen_virtual_height();
|
||||
|
||||
// Slight offset in z to reduce z fighting.
|
||||
c.Translate(0.5f * width, 0.5f * height, 1.0f);
|
||||
c.Scale(width, height, 100.0f);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kOverlayGuide));
|
||||
c.PopTransform();
|
||||
// Slight offset in z to reduce z fighting.
|
||||
c.Translate(0.5f * width, 0.5f * height, 1.0f);
|
||||
c.Scale(width, height, 100.0f);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kOverlayGuide));
|
||||
}
|
||||
c.Submit();
|
||||
}
|
||||
}
|
||||
@ -326,12 +329,13 @@ void GraphicsVR::DrawVRControllers(FrameDef* frame_def) {
|
||||
c.SetTexture(g_base->assets->SysTexture(SysTextureID::kBoxingGlove));
|
||||
c.SetReflection(ReflectionType::kSoft);
|
||||
c.SetReflectionScale(0.4f, 0.4f, 0.4f);
|
||||
c.PushTransform();
|
||||
c.VRTransformToHead();
|
||||
c.Translate(0, 0, 5);
|
||||
c.Scale(2, 2, 2);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBoxingGlove));
|
||||
c.PopTransform();
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.VRTransformToHead();
|
||||
c.Translate(0, 0, 5);
|
||||
c.Scale(2, 2, 2);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBoxingGlove));
|
||||
}
|
||||
c.Submit();
|
||||
}
|
||||
|
||||
@ -346,11 +350,12 @@ void GraphicsVR::DrawVRControllers(FrameDef* frame_def) {
|
||||
c.SetTexture(g_base->assets->SysTexture(SysTextureID::kBoxingGlove));
|
||||
c.SetReflection(ReflectionType::kSoft);
|
||||
c.SetReflectionScale(0.4f, 0.4f, 0.4f);
|
||||
c.PushTransform();
|
||||
c.VRTransformToRightHand();
|
||||
c.Scale(10, 10, 10);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBoxingGlove));
|
||||
c.PopTransform();
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.VRTransformToRightHand();
|
||||
c.Scale(10, 10, 10);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBoxingGlove));
|
||||
}
|
||||
c.Submit();
|
||||
break;
|
||||
}
|
||||
@ -365,11 +370,12 @@ void GraphicsVR::DrawVRControllers(FrameDef* frame_def) {
|
||||
c.SetTexture(g_base->assets->SysTexture(SysTextureID::kBoxingGlove));
|
||||
c.SetReflection(ReflectionType::kSoft);
|
||||
c.SetReflectionScale(0.4f, 0.4f, 0.4f);
|
||||
c.PushTransform();
|
||||
c.VRTransformToLeftHand();
|
||||
c.Scale(10, 10, 10);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBoxingGlove));
|
||||
c.PopTransform();
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.VRTransformToLeftHand();
|
||||
c.Scale(10, 10, 10);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kBoxingGlove));
|
||||
}
|
||||
c.Submit();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3,12 +3,13 @@
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SIMPLE_FULL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SIMPLE_FULL_H_
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/base/graphics/mesh/mesh_buffer.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// just make this a vanilla child class of our template
|
||||
// (simply so we could predeclare this)
|
||||
// Just make this a vanilla child class of our template (simply so we could
|
||||
// predeclare this).
|
||||
class MeshBufferVertexSimpleFull : public MeshBuffer<VertexSimpleFull> {
|
||||
using MeshBuffer::MeshBuffer;
|
||||
};
|
||||
|
||||
@ -3,12 +3,13 @@
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SMOKE_FULL_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SMOKE_FULL_H_
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/base/graphics/mesh/mesh_buffer.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// just make this a vanilla child class of our template
|
||||
// (simply so we could predeclare this)
|
||||
// Just make this a vanilla child class of our template (simply so we could
|
||||
// predeclare this).
|
||||
class MeshBufferVertexSmokeFull : public MeshBuffer<VertexSmokeFull> {
|
||||
using MeshBuffer::MeshBuffer;
|
||||
};
|
||||
|
||||
@ -3,12 +3,13 @@
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SPRITE_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SPRITE_H_
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/base/graphics/mesh/mesh_buffer.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// just make this a vanilla child class of our template
|
||||
// (simply so we could predeclare this)
|
||||
// Just make this a vanilla child class of our template (simply so we could
|
||||
// predeclare this).
|
||||
class MeshBufferVertexSprite : public MeshBuffer<VertexSprite> {
|
||||
using MeshBuffer::MeshBuffer;
|
||||
};
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// standard buffer for indices
|
||||
// Standard buffer for indices.
|
||||
class MeshIndexBuffer16 : public MeshBuffer<uint16_t> {
|
||||
using MeshBuffer::MeshBuffer;
|
||||
};
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// standard buffer for indices
|
||||
// Standard buffer for indices.
|
||||
class MeshIndexBuffer32 : public MeshBuffer<uint32_t> {
|
||||
using MeshBuffer::MeshBuffer;
|
||||
};
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// a simple mesh with all data provided together (either static or dynamic)
|
||||
// A simple mesh with all data provided together (either static or dynamic).
|
||||
class MeshIndexedSimpleFull
|
||||
: public MeshIndexed<VertexSimpleFull, MeshDataType::kIndexedSimpleFull> {
|
||||
using MeshIndexed::MeshIndexed; // wheee c++11 magic
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// a mesh with static indices and UVs and dynamic positions
|
||||
// A mesh with static indices and UVs and dynamic positions.
|
||||
class MeshIndexedSimpleSplit
|
||||
: public MeshIndexedStaticDynamic<VertexSimpleSplitStatic,
|
||||
VertexSimpleSplitDynamic,
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// a mesh with all data provided together (either static or dynamic)
|
||||
// A mesh with all data provided together (either static or dynamic).
|
||||
class MeshIndexedSmokeFull
|
||||
: public MeshIndexed<VertexSmokeFull, MeshDataType::kIndexedSmokeFull> {
|
||||
using MeshIndexed::MeshIndexed; // wheee c++11 magic
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#define BALLISTICA_BASE_GRAPHICS_MESH_MESH_NON_INDEXED_H_
|
||||
|
||||
#include "ballistica/base/graphics/mesh/mesh.h"
|
||||
#include "ballistica/base/graphics/mesh/mesh_buffer.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// an indexed sprite-mesh
|
||||
// An indexed sprite-mesh.
|
||||
class SpriteMesh : public MeshIndexed<VertexSprite, MeshDataType::kSprite> {
|
||||
using MeshIndexed::MeshIndexed; // wheeee c++11 magic
|
||||
};
|
||||
|
||||
@ -9,10 +9,9 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// a mesh set up to draw text
|
||||
// in general you should not use this directly; use TextGroup below, which will
|
||||
// automatically handle switching meshes/textures in order to support the full
|
||||
// unicode range
|
||||
// A mesh set up to draw text. In general you should not use this directly;
|
||||
// use TextGroup, which will automatically handle switching meshes/textures
|
||||
// in order to support the full unicode range.
|
||||
class TextMesh : public MeshIndexedDualTextureFull {
|
||||
public:
|
||||
enum class HAlign { kLeft, kCenter, kRight };
|
||||
|
||||
@ -432,8 +432,8 @@ void RenderPass::Reset() {
|
||||
throw Exception();
|
||||
}
|
||||
|
||||
// By default, logical width matches physical width, but for overlay passes
|
||||
// it can be independent.
|
||||
// By default, logical width matches physical width, but for overlay
|
||||
// passes it can be independent.
|
||||
switch (type()) {
|
||||
case Type::kOverlayPass:
|
||||
case Type::kOverlayFrontPass:
|
||||
|
||||
@ -12,7 +12,7 @@ RenderTarget::RenderTarget(Type type) : type_(type) {
|
||||
|
||||
RenderTarget::~RenderTarget() = default;
|
||||
|
||||
void RenderTarget::ScreenSizeChanged() {
|
||||
void RenderTarget::OnScreenSizeChange() {
|
||||
assert(type_ == Type::kScreen);
|
||||
physical_width_ = g_base->graphics_server->screen_pixel_width();
|
||||
physical_height_ = g_base->graphics_server->screen_pixel_height();
|
||||
|
||||
@ -27,7 +27,7 @@ class RenderTarget : public Object {
|
||||
clear_color.w);
|
||||
}
|
||||
|
||||
void ScreenSizeChanged();
|
||||
void OnScreenSizeChange();
|
||||
auto physical_width() const -> float { return physical_width_; }
|
||||
auto physical_height() const -> float { return physical_height_; }
|
||||
auto GetScissorScaleX() const -> float;
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
#include "ballistica/core/core.h"
|
||||
|
||||
// FIXME: Clear out conditional stuff.
|
||||
#if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
#include "ballistica/core/platform/support/min_sdl.h"
|
||||
#endif
|
||||
// #if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
// #include "ballistica/core/platform/support/min_sdl.h"
|
||||
// #endif
|
||||
|
||||
#if BA_VR_BUILD
|
||||
#include "ballistica/base/graphics/graphics_vr.h"
|
||||
@ -58,9 +58,9 @@ void Renderer::PreprocessFrameDef(FrameDef* frame_def) {
|
||||
UpdateSizesQualitiesAndColors(frame_def);
|
||||
|
||||
// Handle a weird gamma reset issue on our legacy mac build (SDL 1.2).
|
||||
#if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
HandleFunkyMacGammaIssue(frame_def);
|
||||
#endif
|
||||
// #if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
// HandleFunkyMacGammaIssue(frame_def);
|
||||
// #endif
|
||||
|
||||
// In some cases we draw to a lower-res backing buffer instead of native
|
||||
// screen res.
|
||||
@ -425,7 +425,7 @@ void Renderer::UpdateSizesQualitiesAndColors(FrameDef* frame_def) {
|
||||
// If screen-size has changed, handle that.
|
||||
if (screen_size_dirty_) {
|
||||
msaa_enabled_dirty_ = true;
|
||||
screen_render_target()->ScreenSizeChanged();
|
||||
screen_render_target()->OnScreenSizeChange();
|
||||
|
||||
// These render targets are dependent on screen size so they need to be
|
||||
// remade.
|
||||
@ -459,7 +459,7 @@ void Renderer::UpdateSizesQualitiesAndColors(FrameDef* frame_def) {
|
||||
} else {
|
||||
set_vignette_outer(frame_def->vignette_outer());
|
||||
}
|
||||
UpdateVignetteTex(false);
|
||||
UpdateVignetteTex_(false);
|
||||
}
|
||||
|
||||
void Renderer::UpdateLightAndShadowBuffers(FrameDef* frame_def) {
|
||||
@ -581,7 +581,7 @@ void Renderer::UpdateCameraRenderTargets(FrameDef* frame_def) {
|
||||
// If screen size just changed or whatnot,
|
||||
// update whether we should do msaa.
|
||||
if (msaa_enabled_dirty_) {
|
||||
UpdateMSAAEnabled();
|
||||
UpdateMSAAEnabled_();
|
||||
msaa_enabled_dirty_ = false;
|
||||
}
|
||||
|
||||
@ -612,7 +612,7 @@ void Renderer::UpdatePixelScaleAndBackingBuffer(FrameDef* frame_def) {
|
||||
// If our pixel-scale is changing its essentially the same as a resolution
|
||||
// change, so we wanna rebuild our light/shadow buffers and all that.
|
||||
if (pixel_scale_requested_ != pixel_scale_) {
|
||||
ScreenSizeChanged();
|
||||
OnScreenSizeChange();
|
||||
}
|
||||
|
||||
// Create or destroy our backing render-target as necessary.
|
||||
@ -658,21 +658,22 @@ void Renderer::LoadMedia(FrameDef* frame_def) {
|
||||
}
|
||||
}
|
||||
|
||||
#if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
void Renderer::HandleFunkyMacGammaIssue(FrameDef* frame_def) {
|
||||
// FIXME - for some reason, on mac, gamma is getting switched back to
|
||||
// default about 1 second after a res change, etc...
|
||||
// so if we're using a non-1.0 gamma, lets keep setting it periodically
|
||||
// to force the issue
|
||||
millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
if (screen_gamma_requested_ != screen_gamma_
|
||||
|| (t - last_screen_gamma_update_time_ > 300 && screen_gamma_ != 1.0f)) {
|
||||
screen_gamma_ = screen_gamma_requested_;
|
||||
SDL_SetGamma(screen_gamma_, screen_gamma_, screen_gamma_);
|
||||
last_screen_gamma_update_time_ = t;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// #if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
// void Renderer::HandleFunkyMacGammaIssue(FrameDef* frame_def) {
|
||||
// // FIXME - for some reason, on mac, gamma is getting switched back to
|
||||
// // default about 1 second after a res change, etc...
|
||||
// // so if we're using a non-1.0 gamma, lets keep setting it periodically
|
||||
// // to force the issue
|
||||
// millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
// if (screen_gamma_requested_ != screen_gamma_
|
||||
// || (t - last_screen_gamma_update_time_ > 300 && screen_gamma_ != 1.0f))
|
||||
// {
|
||||
// screen_gamma_ = screen_gamma_requested_;
|
||||
// SDL_SetGamma(screen_gamma_, screen_gamma_, screen_gamma_);
|
||||
// last_screen_gamma_update_time_ = t;
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
|
||||
void Renderer::DrawWorldToCameraBuffer(FrameDef* frame_def) {
|
||||
#if BA_CARDBOARD_BUILD
|
||||
@ -754,7 +755,7 @@ void Renderer::UpdateDOFParams(FrameDef* frame_def) {
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::ScreenSizeChanged() {
|
||||
void Renderer::OnScreenSizeChange() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
// We can actually get these events at times when we don't have a valid
|
||||
@ -763,8 +764,6 @@ void Renderer::ScreenSizeChanged() {
|
||||
screen_size_dirty_ = true;
|
||||
}
|
||||
|
||||
void Renderer::CheckCapabilities() {}
|
||||
|
||||
void Renderer::Unload() {
|
||||
light_render_target_.Clear();
|
||||
light_shadow_render_target_.Clear();
|
||||
@ -777,13 +776,13 @@ void Renderer::Load() {
|
||||
screen_render_target_ = Object::CompleteDeferred(NewScreenRenderTarget());
|
||||
|
||||
// Restore current gamma value.
|
||||
if (screen_gamma_ != 1.0f) {
|
||||
#if BA_SDL2_BUILD
|
||||
// Not supporting gamma in SDL2 currently.
|
||||
#elif BA_SDL_BUILD
|
||||
SDL_SetGamma(screen_gamma_, screen_gamma_, screen_gamma_);
|
||||
#endif
|
||||
}
|
||||
// if (screen_gamma_ != 1.0f) {
|
||||
// #if BA_SDL2_BUILD
|
||||
// // Not supporting gamma in SDL2 currently.
|
||||
// #elif BA_SDL_BUILD
|
||||
// SDL_SetGamma(screen_gamma_, screen_gamma_, screen_gamma_);
|
||||
// #endif
|
||||
// }
|
||||
}
|
||||
|
||||
void Renderer::PostLoad() {
|
||||
|
||||
@ -82,7 +82,7 @@ class Renderer {
|
||||
auto light_pitch() const -> float { return light_pitch_; }
|
||||
auto light_heading() const -> float { return light_heading_; }
|
||||
void set_pixel_scale(float s) { pixel_scale_requested_ = s; }
|
||||
void set_screen_gamma(float val) { screen_gamma_requested_ = val; }
|
||||
// void set_screen_gamma(float val) { screen_gamma_requested_ = val; }
|
||||
void set_debug_draw_mode(bool debugModeIn) { debug_draw_mode_ = debugModeIn; }
|
||||
auto debug_draw_mode() -> bool { return debug_draw_mode_; }
|
||||
|
||||
@ -90,13 +90,12 @@ class Renderer {
|
||||
virtual void Unload();
|
||||
virtual void Load();
|
||||
virtual void PostLoad();
|
||||
virtual void CheckCapabilities();
|
||||
virtual auto GetAutoGraphicsQuality() -> GraphicsQuality = 0;
|
||||
virtual auto GetAutoTextureQuality() -> TextureQuality = 0;
|
||||
|
||||
virtual auto GetAutoAndroidRes() -> std::string;
|
||||
|
||||
void ScreenSizeChanged();
|
||||
void OnScreenSizeChange();
|
||||
auto has_camera_render_target() const -> bool {
|
||||
return camera_render_target_.Exists();
|
||||
}
|
||||
@ -148,7 +147,7 @@ class Renderer {
|
||||
float eyeZ, int viewport_x, int viewport_y);
|
||||
int VRGetViewportX() const { return vr_viewport_x_; }
|
||||
int VRGetViewportY() const { return vr_viewport_y_; }
|
||||
#endif // BA_VR_BUILD
|
||||
#endif
|
||||
|
||||
virtual auto NewMeshAssetData(const MeshAsset& mesh)
|
||||
-> Object::Ref<MeshAssetRendererData> = 0;
|
||||
@ -166,7 +165,7 @@ class Renderer {
|
||||
protected:
|
||||
virtual void DrawDebug() = 0;
|
||||
virtual void CheckForErrors() = 0;
|
||||
virtual void UpdateVignetteTex(bool force) = 0;
|
||||
virtual void UpdateVignetteTex_(bool force) = 0;
|
||||
virtual void GenerateCameraBufferBlurPasses() = 0;
|
||||
virtual void UpdateMeshes(
|
||||
const std::vector<Object::Ref<MeshDataClientHandle>>& meshes,
|
||||
@ -190,7 +189,7 @@ class Renderer {
|
||||
bool linear_interpolation, bool force_shader_blit,
|
||||
bool invalidate_source) = 0;
|
||||
virtual auto IsMSAAEnabled() const -> bool = 0;
|
||||
virtual void UpdateMSAAEnabled() = 0;
|
||||
virtual void UpdateMSAAEnabled_() = 0;
|
||||
virtual void VREyeRenderBegin() = 0;
|
||||
virtual void RenderFrameDefEnd() = 0;
|
||||
virtual void CardboardDisableScissor() = 0;
|
||||
@ -209,46 +208,47 @@ class Renderer {
|
||||
void DrawWorldToCameraBuffer(FrameDef* frame_def);
|
||||
void UpdatePixelScaleAndBackingBuffer(FrameDef* frame_def);
|
||||
void UpdateCameraRenderTargets(FrameDef* frame_def);
|
||||
#if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
void HandleFunkyMacGammaIssue(FrameDef* frame_def);
|
||||
#endif
|
||||
// #if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD
|
||||
// void HandleFunkyMacGammaIssue(FrameDef* frame_def);
|
||||
// #endif
|
||||
void LoadMedia(FrameDef* frame_def);
|
||||
void UpdateDOFParams(FrameDef* frame_def);
|
||||
#if BA_VR_BUILD
|
||||
void VRPreprocess(FrameDef* frame_def);
|
||||
void VRUpdateForEyeRender(FrameDef* frame_def);
|
||||
void VRDrawOverlayFlatPass(FrameDef* frame_def);
|
||||
// raw values from vr system
|
||||
VRHandsState vr_raw_hands_state_;
|
||||
float vr_raw_head_tx_ = 0.0f;
|
||||
float vr_raw_head_ty_ = 0.0f;
|
||||
float vr_raw_head_tz_ = 0.0f;
|
||||
float vr_raw_head_yaw_ = 0.0f;
|
||||
float vr_raw_head_pitch_ = 0.0f;
|
||||
float vr_raw_head_roll_ = 0.0f;
|
||||
// final game-space transforms
|
||||
Matrix44f vr_base_transform_ = kMatrix44fIdentity;
|
||||
Matrix44f vr_transform_right_hand_ = kMatrix44fIdentity;
|
||||
Matrix44f vr_transform_left_hand_ = kMatrix44fIdentity;
|
||||
Matrix44f vr_transform_head_ = kMatrix44fIdentity;
|
||||
// values for current eye render
|
||||
bool vr_use_fov_tangents_ = false;
|
||||
float vr_fov_l_tan_ = 1.0f;
|
||||
float vr_fov_r_tan_ = 1.0f;
|
||||
float vr_fov_b_tan_ = 1.0f;
|
||||
float vr_fov_t_tan_ = 1.0f;
|
||||
float vr_fov_degrees_x_ = 30.0f;
|
||||
float vr_fov_degrees_y_ = 30.0f;
|
||||
float vr_eye_x_ = 0.0f;
|
||||
float vr_eye_y_ = 0.0f;
|
||||
float vr_eye_z_ = 0.0f;
|
||||
int vr_eye_ = 0;
|
||||
float vr_eye_yaw_ = 0.0f;
|
||||
float vr_eye_pitch_ = 0.0f;
|
||||
float vr_eye_roll_ = 0.0f;
|
||||
int vr_viewport_x_ = 0;
|
||||
int vr_viewport_y_ = 0;
|
||||
// Raw values from vr system.
|
||||
VRHandsState vr_raw_hands_state_{};
|
||||
float vr_raw_head_tx_{};
|
||||
float vr_raw_head_ty_{};
|
||||
float vr_raw_head_tz_{};
|
||||
float vr_raw_head_yaw_{};
|
||||
float vr_raw_head_pitch_{};
|
||||
float vr_raw_head_roll_{};
|
||||
// Final game-space transforms.
|
||||
Matrix44f vr_base_transform_{kMatrix44fIdentity};
|
||||
Matrix44f vr_transform_right_hand_{kMatrix44fIdentity};
|
||||
Matrix44f vr_transform_left_hand_{kMatrix44fIdentity};
|
||||
Matrix44f vr_transform_head_{kMatrix44fIdentity};
|
||||
// Values for current eye render.
|
||||
bool vr_use_fov_tangents_{};
|
||||
float vr_fov_l_tan_{1.0f};
|
||||
float vr_fov_r_tan_{1.0f};
|
||||
float vr_fov_b_tan_{1.0f};
|
||||
float vr_fov_t_tan_{1.0f};
|
||||
float vr_fov_degrees_x_{30.0f};
|
||||
float vr_fov_degrees_y_{30.0f};
|
||||
float vr_eye_x_{};
|
||||
float vr_eye_y_{};
|
||||
float vr_eye_z_{};
|
||||
int vr_eye_{};
|
||||
float vr_eye_yaw_{};
|
||||
float vr_eye_pitch_{};
|
||||
float vr_eye_roll_{};
|
||||
int vr_viewport_x_{};
|
||||
int vr_viewport_y_{};
|
||||
#endif // BA_VR_BUILD
|
||||
|
||||
bool screen_size_dirty_{};
|
||||
bool msaa_enabled_dirty_{};
|
||||
millisecs_t dof_update_time_{};
|
||||
@ -269,7 +269,7 @@ class Renderer {
|
||||
Vector3f vignette_outer_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f vignette_inner_{1.0f, 1.0f, 1.0f};
|
||||
int shadow_res_{-1};
|
||||
float screen_gamma_requested_{1.0f};
|
||||
// float screen_gamma_requested_{1.0f};
|
||||
float screen_gamma_{1.0f};
|
||||
float pixel_scale_requested_{1.0f};
|
||||
float pixel_scale_{1.0f};
|
||||
|
||||
@ -163,8 +163,12 @@ class FrameDef {
|
||||
auto shake_original() const -> const Vector3f& { return shake_original_; }
|
||||
|
||||
#if BA_DEBUG_BUILD
|
||||
auto defining_component() const -> bool { return defining_component_; }
|
||||
void set_defining_component(bool val) { defining_component_ = val; }
|
||||
// For debugging; there should ever only be a single RenderComponent writing
|
||||
// commands to us at once.
|
||||
auto active_render_component() const { return active_render_component_; }
|
||||
void set_active_render_component(RenderComponent* c) {
|
||||
active_render_component_ = c;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
@ -191,6 +195,7 @@ class FrameDef {
|
||||
// Sanity checking: make sure components are completely submitted
|
||||
// before new ones are started (so we dont get scrambled command buffers).
|
||||
bool defining_component_{};
|
||||
RenderComponent* active_render_component_{};
|
||||
#endif
|
||||
|
||||
std::unique_ptr<RenderPass> light_pass_;
|
||||
|
||||
@ -158,17 +158,18 @@ void NetGraph::Draw(RenderPass* pass, double time, double x, double y, double w,
|
||||
SimpleComponent c2(pass);
|
||||
c2.SetTransparent(true);
|
||||
c2.SetColor(1, 0, 0, 1);
|
||||
c2.PushTransform();
|
||||
c2.Translate(static_cast<float>(x), static_cast<float>(y + h));
|
||||
float scale = static_cast<float>(h) * 0.006f;
|
||||
c2.Scale(scale, scale);
|
||||
int text_elem_count = impl_->max_vel_text.GetElementCount();
|
||||
for (int e = 0; e < text_elem_count; e++) {
|
||||
c2.SetTexture(impl_->max_vel_text.GetElementTexture(e));
|
||||
c2.SetFlatness(1.0f);
|
||||
c2.DrawMesh(impl_->max_vel_text.GetElementMesh(e));
|
||||
{
|
||||
auto xf = c2.ScopedTransform();
|
||||
c2.Translate(static_cast<float>(x), static_cast<float>(y + h));
|
||||
float scale = static_cast<float>(h) * 0.006f;
|
||||
c2.Scale(scale, scale);
|
||||
int text_elem_count = impl_->max_vel_text.GetElementCount();
|
||||
for (int e = 0; e < text_elem_count; e++) {
|
||||
c2.SetTexture(impl_->max_vel_text.GetElementTexture(e));
|
||||
c2.SetFlatness(1.0f);
|
||||
c2.DrawMesh(impl_->max_vel_text.GetElementMesh(e));
|
||||
}
|
||||
}
|
||||
c2.PopTransform();
|
||||
c2.Submit();
|
||||
}
|
||||
|
||||
|
||||
@ -19,16 +19,19 @@ namespace ballistica::base {
|
||||
// this class provides to you, drawing each in the same manner.
|
||||
class TextGroup : public Object {
|
||||
public:
|
||||
// the number of meshes needing to be drawn for this text
|
||||
// The number of meshes needing to be drawn for this text.
|
||||
auto GetElementCount() -> int { return static_cast<int>(entries_.size()); }
|
||||
|
||||
auto GetElementMesh(int index) const -> TextMesh* {
|
||||
assert(index < static_cast<int>(entries_.size()));
|
||||
return &(entries_[index]->mesh);
|
||||
}
|
||||
|
||||
auto GetElementTexture(int index) const -> TextureAsset* {
|
||||
assert(index < static_cast<int>(entries_.size()));
|
||||
return entries_[index]->tex.Get();
|
||||
}
|
||||
|
||||
// if you are doing any shader effects in UV-space (such as drop-shadows),
|
||||
// scale them by this ..this will account for different character sheets
|
||||
// with different sized characters
|
||||
@ -36,18 +39,22 @@ class TextGroup : public Object {
|
||||
assert(index < static_cast<int>(entries_.size()));
|
||||
return entries_[index]->u_scale;
|
||||
}
|
||||
|
||||
auto GetElementVScale(int index) -> float {
|
||||
assert(index < static_cast<int>(entries_.size()));
|
||||
return entries_[index]->v_scale;
|
||||
}
|
||||
|
||||
auto GetElementMaxFlatness(int index) const -> float {
|
||||
assert(index < static_cast<int>(entries_.size()));
|
||||
return entries_[index]->max_flatness;
|
||||
}
|
||||
|
||||
auto GetElementCanColor(int index) const -> bool {
|
||||
assert(index < static_cast<int>(entries_.size()));
|
||||
return entries_[index]->can_color;
|
||||
}
|
||||
|
||||
auto GetElementMaskUV2Texture(int index) const -> TextureAsset* {
|
||||
assert(index < static_cast<int>(entries_.size()));
|
||||
return g_base->assets->SysTexture(entries_[index]->type
|
||||
@ -55,11 +62,14 @@ class TextGroup : public Object {
|
||||
? SysTextureID::kSoftRect2
|
||||
: SysTextureID::kSoftRect);
|
||||
}
|
||||
|
||||
void SetText(const std::string& text,
|
||||
TextMesh::HAlign alignment_h = TextMesh::HAlign::kLeft,
|
||||
TextMesh::VAlign alignment_v = TextMesh::VAlign::kNone,
|
||||
bool big = false, float resolution_scale = 1.0f);
|
||||
|
||||
auto text() const -> const std::string& { return text_; }
|
||||
|
||||
void GetCaratPts(const std::string& text_in, TextMesh::HAlign alignment_h,
|
||||
TextMesh::VAlign alignment_v, int carat_pos, float* carat_x,
|
||||
float* carat_y);
|
||||
|
||||
@ -5,8 +5,6 @@
|
||||
#include "ballistica/core/core.h"
|
||||
#include "ballistica/core/platform/core_platform.h"
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
/* DDS loader written by Jon Watte 2002 */
|
||||
/* Permission granted to use freely, as long as Jon Watte */
|
||||
/* is held harmless for all possible damages resulting from */
|
||||
@ -16,10 +14,6 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// Should tidy this up to use unsigned vals but don't want to touch for now.
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "hicpp-signed-bitwise"
|
||||
|
||||
struct DdsLoadInfo {
|
||||
bool compressed;
|
||||
bool swap;
|
||||
@ -139,8 +133,4 @@ void LoadDDS(const std::string& file_name, unsigned char** buffers, int* widths,
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
@ -3,9 +3,6 @@
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_TEXTURE_DDS_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_TEXTURE_DDS_H_
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "OCUnusedMacroInspection"
|
||||
|
||||
/* DDS loader written by Jon Watte 2002 */
|
||||
/* Permission granted to use freely, as long as Jon Watte */
|
||||
/* is held harmless for all possible damages resulting from */
|
||||
@ -17,8 +14,6 @@
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
// little-endian, of course
|
||||
#define DDS_MAGIC 0x20534444
|
||||
|
||||
@ -98,8 +93,6 @@
|
||||
#define PF_IS_INDEX8(pf) \
|
||||
(((pf).dwFlags & DDPF_INDEXED) && ((pf).dwRGBBitCount == 8))
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
union DDS_header {
|
||||
@ -152,6 +145,4 @@ void LoadDDS(const std::string& file_name, unsigned char** buffers, int* widths,
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_TEXTURE_DDS_H_
|
||||
|
||||
@ -5,23 +5,8 @@
|
||||
#include "ballistica/core/core.h"
|
||||
#include "ballistica/core/platform/core_platform.h"
|
||||
|
||||
#if !BA_HEADLESS_BUILD
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
// Inspection is not terribly happy about this file but it works so not
|
||||
// gonna touch it for now.
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "hicpp-signed-bitwise"
|
||||
#pragma ide diagnostic ignored "bugprone-narrowing-conversions"
|
||||
#pragma ide diagnostic ignored "bugprone-macro-parentheses"
|
||||
#pragma ide diagnostic ignored "UnusedValue"
|
||||
|
||||
#pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions"
|
||||
#pragma ide diagnostic ignored "OCUnusedMacroInspection"
|
||||
#pragma ide diagnostic ignored "clang-analyzer-deadcode.DeadStores"
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
// We don't want this to be dependent on GL so
|
||||
// lets just define the few bits we need here
|
||||
#ifndef GL_COMPRESSED_RGB8_ETC2
|
||||
@ -2291,8 +2276,4 @@ void KTXUnpackETC(const GLubyte* srcETC, const GLenum srcFormat,
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // !BA_HEADLESS_BUILD
|
||||
|
||||
@ -7,9 +7,6 @@
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
|
||||
// currently need gl for this stuff.. probably not necessary.
|
||||
#if BA_ENABLE_OPENGL
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
void LoadKTX(const std::string& file_name, unsigned char** buffers, int* widths,
|
||||
@ -24,6 +21,4 @@ void KTXUnpackETC(const uint8_t* src_etc, unsigned int src_format,
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_ENABLE_OPENGL
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_TEXTURE_KTX_H_
|
||||
|
||||
@ -66,7 +66,7 @@ JoystickInput::JoystickInput(int sdl_joystick_id,
|
||||
// In SDL2 we're passed a device-id but that's only used to open the
|
||||
// joystick; events and most everything else use an instance ID, so we store
|
||||
// that instead.
|
||||
#if BA_SDL2_BUILD
|
||||
// #if BA_SDL2_BUILD
|
||||
sdl_joystick_id_ = SDL_JoystickInstanceID(sdl_joystick_);
|
||||
raw_sdl_joystick_name_ = SDL_JoystickName(sdl_joystick_);
|
||||
|
||||
@ -78,14 +78,15 @@ JoystickInput::JoystickInput(int sdl_joystick_id,
|
||||
&& raw_sdl_joystick_name_.size() <= 22) {
|
||||
raw_sdl_joystick_name_ = "XInput Controller";
|
||||
}
|
||||
#else
|
||||
raw_sdl_joystick_name_ = SDL_JoystickName(sdl_joystick_id_);
|
||||
#endif // BA_SDL2_BUILD
|
||||
// #else
|
||||
// raw_sdl_joystick_name_ = SDL_JoystickName(sdl_joystick_id_);
|
||||
// #endif // BA_SDL2_BUILD
|
||||
|
||||
// If its an SDL joystick and we're using our custom sdl 1.2 build, ask it.
|
||||
#if BA_XCODE_BUILD && BA_OSTYPE_MACOS && !BA_SDL2_BUILD
|
||||
raw_sdl_joystick_identifier_ = SDL_JoystickIdentifier(sdl_joystick_id_);
|
||||
#endif
|
||||
// #if BA_XCODE_BUILD && BA_OSTYPE_MACOS && !BA_SDL2_BUILD
|
||||
// raw_sdl_joystick_identifier_ =
|
||||
// SDL_JoystickIdentifier(sdl_joystick_id_);
|
||||
// #endif
|
||||
|
||||
// Some special-cases on mac.
|
||||
if (strstr(raw_sdl_joystick_name_.c_str(), "PLAYSTATION") != nullptr) {
|
||||
@ -307,7 +308,7 @@ JoystickInput::~JoystickInput() {
|
||||
#if BA_ENABLE_SDL_JOYSTICKS
|
||||
assert(g_base->app_adapter);
|
||||
auto joystick = sdl_joystick_;
|
||||
g_core->main_event_loop()->PushCall(
|
||||
g_base->app_adapter->PushMainThreadCall(
|
||||
[joystick] { SDL_JoystickClose(joystick); });
|
||||
sdl_joystick_ = nullptr;
|
||||
#else
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user