nativeEngine.js 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039
  1. import { Engine } from "../Engines/engine.js";
  2. import { InternalTexture, InternalTextureSource } from "../Materials/Textures/internalTexture.js";
  3. import { Texture } from "../Materials/Textures/texture.js";
  4. import { DataBuffer } from "../Buffers/dataBuffer.js";
  5. import { Tools } from "../Misc/tools.js";
  6. import { Observable } from "../Misc/observable.js";
  7. import { CreateImageDataArrayBufferViews, GetEnvInfo, UploadEnvSpherical } from "../Misc/environmentTextureTools.js";
  8. import { Logger } from "../Misc/logger.js";
  9. import { ThinEngine } from "./thinEngine.js";
  10. import { EngineStore } from "./engineStore.js";
  11. import { ShaderCodeInliner } from "./Processors/shaderCodeInliner.js";
  12. import { WebGL2ShaderProcessor } from "../Engines/WebGL/webGL2ShaderProcessors.js";
  13. import { NativeDataStream } from "./Native/nativeDataStream.js";
  14. import { NativePipelineContext } from "./Native/nativePipelineContext.js";
  15. import { NativeRenderTargetWrapper } from "./Native/nativeRenderTargetWrapper.js";
  16. import { NativeHardwareTexture } from "./Native/nativeHardwareTexture.js";
  17. import { getNativeAlphaMode, getNativeAttribType, getNativeSamplingMode, getNativeTextureFormat, getNativeStencilDepthFail, getNativeStencilDepthPass, getNativeStencilFunc, getNativeStencilOpFail, getNativeAddressMode, } from "./Native/nativeHelpers.js";
  18. import { AbstractEngine } from "./abstractEngine.js";
  19. const onNativeObjectInitialized = new Observable();
  20. if (typeof self !== "undefined" && !Object.prototype.hasOwnProperty.call(self, "_native")) {
  21. let __native;
  22. Object.defineProperty(self, "_native", {
  23. get: () => __native,
  24. set: (value) => {
  25. __native = value;
  26. if (__native) {
  27. onNativeObjectInitialized.notifyObservers(__native);
  28. }
  29. },
  30. });
  31. }
  32. /**
  33. * Returns _native only after it has been defined by BabylonNative.
  34. * @internal
  35. */
  36. export function AcquireNativeObjectAsync() {
  37. return new Promise((resolve) => {
  38. if (typeof _native === "undefined") {
  39. onNativeObjectInitialized.addOnce((nativeObject) => resolve(nativeObject));
  40. }
  41. else {
  42. resolve(_native);
  43. }
  44. });
  45. }
  46. /**
  47. * Registers a constructor on the _native object. See NativeXRFrame for an example.
  48. * @internal
  49. */
  50. export async function RegisterNativeTypeAsync(typeName, constructor) {
  51. (await AcquireNativeObjectAsync())[typeName] = constructor;
  52. }
  53. /**
  54. * Container for accessors for natively-stored mesh data buffers.
  55. */
  56. class NativeDataBuffer extends DataBuffer {
  57. }
  58. /** @internal */
  59. class CommandBufferEncoder {
  60. constructor(_engine) {
  61. this._engine = _engine;
  62. this._pending = new Array();
  63. this._isCommandBufferScopeActive = false;
  64. this._commandStream = NativeEngine._createNativeDataStream();
  65. this._engine.setCommandDataStream(this._commandStream);
  66. }
  67. beginCommandScope() {
  68. if (this._isCommandBufferScopeActive) {
  69. throw new Error("Command scope already active.");
  70. }
  71. this._isCommandBufferScopeActive = true;
  72. }
  73. endCommandScope() {
  74. if (!this._isCommandBufferScopeActive) {
  75. throw new Error("Command scope is not active.");
  76. }
  77. this._isCommandBufferScopeActive = false;
  78. this._submit();
  79. }
  80. startEncodingCommand(command) {
  81. this._commandStream.writeNativeData(command);
  82. }
  83. encodeCommandArgAsUInt32(commandArg) {
  84. this._commandStream.writeUint32(commandArg);
  85. }
  86. encodeCommandArgAsUInt32s(commandArg) {
  87. this._commandStream.writeUint32Array(commandArg);
  88. }
  89. encodeCommandArgAsInt32(commandArg) {
  90. this._commandStream.writeInt32(commandArg);
  91. }
  92. encodeCommandArgAsInt32s(commandArg) {
  93. this._commandStream.writeInt32Array(commandArg);
  94. }
  95. encodeCommandArgAsFloat32(commandArg) {
  96. this._commandStream.writeFloat32(commandArg);
  97. }
  98. encodeCommandArgAsFloat32s(commandArg) {
  99. this._commandStream.writeFloat32Array(commandArg);
  100. }
  101. encodeCommandArgAsNativeData(commandArg) {
  102. this._commandStream.writeNativeData(commandArg);
  103. this._pending.push(commandArg);
  104. }
  105. finishEncodingCommand() {
  106. if (!this._isCommandBufferScopeActive) {
  107. this._submit();
  108. }
  109. }
  110. _submit() {
  111. this._engine.submitCommands();
  112. this._pending.length = 0;
  113. }
  114. }
  115. /** @internal */
  116. export class NativeEngine extends Engine {
  117. setHardwareScalingLevel(level) {
  118. super.setHardwareScalingLevel(level);
  119. this._engine.setHardwareScalingLevel(level);
  120. }
  121. constructor(options = {}) {
  122. super(null, false, undefined, options.adaptToDeviceRatio);
  123. this._engine = new _native.Engine();
  124. this._camera = _native.Camera ? new _native.Camera() : null;
  125. this._commandBufferEncoder = new CommandBufferEncoder(this._engine);
  126. this._boundBuffersVertexArray = null;
  127. this._currentDepthTest = _native.Engine.DEPTH_TEST_LEQUAL;
  128. this._stencilTest = false;
  129. this._stencilMask = 255;
  130. this._stencilFunc = 519;
  131. this._stencilFuncRef = 0;
  132. this._stencilFuncMask = 255;
  133. this._stencilOpStencilFail = 7680;
  134. this._stencilOpDepthFail = 7680;
  135. this._stencilOpStencilDepthPass = 7681;
  136. this._zOffset = 0;
  137. this._zOffsetUnits = 0;
  138. this._depthWrite = true;
  139. if (_native.Engine.PROTOCOL_VERSION !== NativeEngine.PROTOCOL_VERSION) {
  140. throw new Error(`Protocol version mismatch: ${_native.Engine.PROTOCOL_VERSION} (Native) !== ${NativeEngine.PROTOCOL_VERSION} (JS)`);
  141. }
  142. if (this._engine.setDeviceLostCallback) {
  143. this._engine.setDeviceLostCallback(() => {
  144. this.onContextLostObservable.notifyObservers(this);
  145. this._contextWasLost = true;
  146. this._restoreEngineAfterContextLost();
  147. });
  148. }
  149. this._webGLVersion = 2;
  150. this.disableUniformBuffers = true;
  151. this._shaderPlatformName = "NATIVE";
  152. // TODO: Initialize this more correctly based on the hardware capabilities.
  153. // Init caps
  154. this._caps = {
  155. maxTexturesImageUnits: 16,
  156. maxVertexTextureImageUnits: 16,
  157. maxCombinedTexturesImageUnits: 32,
  158. maxTextureSize: _native.Engine.CAPS_LIMITS_MAX_TEXTURE_SIZE,
  159. maxCubemapTextureSize: 512,
  160. maxRenderTextureSize: 512,
  161. maxVertexAttribs: 16,
  162. maxVaryingVectors: 16,
  163. maxFragmentUniformVectors: 16,
  164. maxVertexUniformVectors: 16,
  165. standardDerivatives: true,
  166. astc: null,
  167. pvrtc: null,
  168. etc1: null,
  169. etc2: null,
  170. bptc: null,
  171. maxAnisotropy: 16,
  172. uintIndices: true,
  173. fragmentDepthSupported: false,
  174. highPrecisionShaderSupported: true,
  175. colorBufferFloat: false,
  176. supportFloatTexturesResolve: false,
  177. rg11b10ufColorRenderable: false,
  178. textureFloat: true,
  179. textureFloatLinearFiltering: false,
  180. textureFloatRender: true,
  181. textureHalfFloat: true,
  182. textureHalfFloatLinearFiltering: false,
  183. textureHalfFloatRender: true,
  184. textureLOD: true,
  185. texelFetch: false,
  186. drawBuffersExtension: false,
  187. depthTextureExtension: false,
  188. vertexArrayObject: true,
  189. instancedArrays: true,
  190. supportOcclusionQuery: false,
  191. canUseTimestampForTimerQuery: false,
  192. blendMinMax: false,
  193. maxMSAASamples: 16,
  194. canUseGLInstanceID: true,
  195. canUseGLVertexID: true,
  196. supportComputeShaders: false,
  197. supportSRGBBuffers: true,
  198. supportTransformFeedbacks: false,
  199. textureMaxLevel: false,
  200. texture2DArrayMaxLayerCount: _native.Engine.CAPS_LIMITS_MAX_TEXTURE_LAYERS,
  201. disableMorphTargetTexture: false,
  202. parallelShaderCompile: { COMPLETION_STATUS_KHR: 0 },
  203. };
  204. this._features = {
  205. forceBitmapOverHTMLImageElement: true,
  206. supportRenderAndCopyToLodForFloatTextures: false,
  207. supportDepthStencilTexture: false,
  208. supportShadowSamplers: false,
  209. uniformBufferHardCheckMatrix: false,
  210. allowTexturePrefiltering: false,
  211. trackUbosInFrame: false,
  212. checkUbosContentBeforeUpload: false,
  213. supportCSM: false,
  214. basisNeedsPOT: false,
  215. support3DTextures: false,
  216. needTypeSuffixInShaderConstants: false,
  217. supportMSAA: true,
  218. supportSSAO2: false,
  219. supportExtendedTextureFormats: false,
  220. supportSwitchCaseInShader: false,
  221. supportSyncTextureRead: false,
  222. needsInvertingBitmap: true,
  223. useUBOBindingCache: true,
  224. needShaderCodeInlining: true,
  225. needToAlwaysBindUniformBuffers: false,
  226. supportRenderPasses: true,
  227. supportSpriteInstancing: false,
  228. forceVertexBufferStrideAndOffsetMultiple4Bytes: false,
  229. _collectUbosUpdatedInFrame: false,
  230. };
  231. Tools.Log("Babylon Native (v" + Engine.Version + ") launched");
  232. Tools.LoadScript = function (scriptUrl, onSuccess, onError, scriptId) {
  233. Tools.LoadFile(scriptUrl, (data) => {
  234. Function(data).apply(null);
  235. if (onSuccess) {
  236. onSuccess();
  237. }
  238. }, undefined, undefined, false, (request, exception) => {
  239. if (onError) {
  240. onError("LoadScript Error", exception);
  241. }
  242. });
  243. };
  244. // Wrappers
  245. if (typeof URL === "undefined") {
  246. window.URL = {
  247. createObjectURL: function () { },
  248. revokeObjectURL: function () { },
  249. };
  250. }
  251. if (typeof Blob === "undefined") {
  252. window.Blob = function (v) {
  253. return v;
  254. };
  255. }
  256. // polyfill for Chakra
  257. if (!Array.prototype.flat) {
  258. Object.defineProperty(Array.prototype, "flat", {
  259. configurable: true,
  260. value: function flat() {
  261. const depth = isNaN(arguments[0]) ? 1 : Number(arguments[0]);
  262. return depth
  263. ? Array.prototype.reduce.call(this, function (acc, cur) {
  264. if (Array.isArray(cur)) {
  265. acc.push.apply(acc, flat.call(cur, depth - 1));
  266. }
  267. else {
  268. acc.push(cur);
  269. }
  270. return acc;
  271. }, [])
  272. : Array.prototype.slice.call(this);
  273. },
  274. writable: true,
  275. });
  276. }
  277. // Currently we do not fully configure the ThinEngine on construction of NativeEngine.
  278. // Setup resolution scaling based on display settings.
  279. const devicePixelRatio = window ? window.devicePixelRatio || 1.0 : 1.0;
  280. this._hardwareScalingLevel = options.adaptToDeviceRatio ? 1.0 / devicePixelRatio : 1.0;
  281. this._engine.setHardwareScalingLevel(this._hardwareScalingLevel);
  282. this._lastDevicePixelRatio = devicePixelRatio;
  283. this.resize();
  284. const currentDepthFunction = this.getDepthFunction();
  285. if (currentDepthFunction) {
  286. this.setDepthFunction(currentDepthFunction);
  287. }
  288. // Shader processor
  289. this._shaderProcessor = new WebGL2ShaderProcessor();
  290. this.onNewSceneAddedObservable.add((scene) => {
  291. const originalRender = scene.render;
  292. scene.render = (...args) => {
  293. this._commandBufferEncoder.beginCommandScope();
  294. originalRender.apply(scene, args);
  295. this._commandBufferEncoder.endCommandScope();
  296. };
  297. });
  298. }
  299. dispose() {
  300. super.dispose();
  301. if (this._boundBuffersVertexArray) {
  302. this._deleteVertexArray(this._boundBuffersVertexArray);
  303. }
  304. this._engine.dispose();
  305. }
  306. /** @internal */
  307. static _createNativeDataStream() {
  308. return new NativeDataStream();
  309. }
  310. /**
  311. * Can be used to override the current requestAnimationFrame requester.
  312. * @internal
  313. */
  314. _queueNewFrame(bindedRenderFunction, requester) {
  315. // Use the provided requestAnimationFrame, unless the requester is the window. In that case, we will default to the Babylon Native version of requestAnimationFrame.
  316. if (requester.requestAnimationFrame && requester !== window) {
  317. requester.requestAnimationFrame(bindedRenderFunction);
  318. }
  319. else {
  320. this._engine.requestAnimationFrame(bindedRenderFunction);
  321. }
  322. return 0;
  323. }
  324. _restoreEngineAfterContextLost() {
  325. this._clearEmptyResources();
  326. const depthTest = this._depthCullingState.depthTest; // backup those values because the call to initEngine / wipeCaches will reset them
  327. const depthFunc = this._depthCullingState.depthFunc;
  328. const depthMask = this._depthCullingState.depthMask;
  329. const stencilTest = this._stencilState.stencilTest;
  330. this._rebuildGraphicsResources();
  331. this._depthCullingState.depthTest = depthTest;
  332. this._depthCullingState.depthFunc = depthFunc;
  333. this._depthCullingState.depthMask = depthMask;
  334. this._stencilState.stencilTest = stencilTest;
  335. this._flagContextRestored();
  336. }
  337. /**
  338. * Override default engine behavior.
  339. * @param framebuffer
  340. */
  341. _bindUnboundFramebuffer(framebuffer) {
  342. if (this._currentFramebuffer !== framebuffer) {
  343. if (this._currentFramebuffer) {
  344. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_UNBINDFRAMEBUFFER);
  345. this._commandBufferEncoder.encodeCommandArgAsNativeData(this._currentFramebuffer);
  346. this._commandBufferEncoder.finishEncodingCommand();
  347. }
  348. if (framebuffer) {
  349. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_BINDFRAMEBUFFER);
  350. this._commandBufferEncoder.encodeCommandArgAsNativeData(framebuffer);
  351. this._commandBufferEncoder.finishEncodingCommand();
  352. }
  353. this._currentFramebuffer = framebuffer;
  354. }
  355. }
  356. /**
  357. * Gets host document
  358. * @returns the host document object
  359. */
  360. getHostDocument() {
  361. return null;
  362. }
  363. clear(color, backBuffer, depth, stencil = false) {
  364. if (this.useReverseDepthBuffer) {
  365. throw new Error("reverse depth buffer is not currently implemented");
  366. }
  367. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_CLEAR);
  368. this._commandBufferEncoder.encodeCommandArgAsUInt32(backBuffer && color ? 1 : 0);
  369. this._commandBufferEncoder.encodeCommandArgAsFloat32(color ? color.r : 0);
  370. this._commandBufferEncoder.encodeCommandArgAsFloat32(color ? color.g : 0);
  371. this._commandBufferEncoder.encodeCommandArgAsFloat32(color ? color.b : 0);
  372. this._commandBufferEncoder.encodeCommandArgAsFloat32(color ? color.a : 1);
  373. this._commandBufferEncoder.encodeCommandArgAsUInt32(depth ? 1 : 0);
  374. this._commandBufferEncoder.encodeCommandArgAsFloat32(1);
  375. this._commandBufferEncoder.encodeCommandArgAsUInt32(stencil ? 1 : 0);
  376. this._commandBufferEncoder.encodeCommandArgAsUInt32(0);
  377. this._commandBufferEncoder.finishEncodingCommand();
  378. }
  379. createIndexBuffer(indices, updateable, _label) {
  380. const data = this._normalizeIndexData(indices);
  381. const buffer = new NativeDataBuffer();
  382. buffer.references = 1;
  383. buffer.is32Bits = data.BYTES_PER_ELEMENT === 4;
  384. if (data.byteLength) {
  385. buffer.nativeIndexBuffer = this._engine.createIndexBuffer(data.buffer, data.byteOffset, data.byteLength, buffer.is32Bits, updateable ?? false);
  386. }
  387. return buffer;
  388. }
  389. createVertexBuffer(vertices, updateable, _label) {
  390. const data = ArrayBuffer.isView(vertices) ? vertices : new Float32Array(vertices);
  391. const buffer = new NativeDataBuffer();
  392. buffer.references = 1;
  393. if (data.byteLength) {
  394. buffer.nativeVertexBuffer = this._engine.createVertexBuffer(data.buffer, data.byteOffset, data.byteLength, updateable ?? false);
  395. }
  396. return buffer;
  397. }
  398. _recordVertexArrayObject(vertexArray, vertexBuffers, indexBuffer, effect, overrideVertexBuffers) {
  399. if (indexBuffer) {
  400. this._engine.recordIndexBuffer(vertexArray, indexBuffer.nativeIndexBuffer);
  401. }
  402. const attributes = effect.getAttributesNames();
  403. for (let index = 0; index < attributes.length; index++) {
  404. const location = effect.getAttributeLocation(index);
  405. if (location >= 0) {
  406. const kind = attributes[index];
  407. let vertexBuffer = null;
  408. if (overrideVertexBuffers) {
  409. vertexBuffer = overrideVertexBuffers[kind];
  410. }
  411. if (!vertexBuffer) {
  412. vertexBuffer = vertexBuffers[kind];
  413. }
  414. if (vertexBuffer) {
  415. const buffer = vertexBuffer.getBuffer();
  416. if (buffer && buffer.nativeVertexBuffer) {
  417. this._engine.recordVertexBuffer(vertexArray, buffer.nativeVertexBuffer, location, vertexBuffer.byteOffset, vertexBuffer.byteStride, vertexBuffer.getSize(), getNativeAttribType(vertexBuffer.type), vertexBuffer.normalized, vertexBuffer.getInstanceDivisor());
  418. }
  419. }
  420. }
  421. }
  422. }
  423. bindBuffers(vertexBuffers, indexBuffer, effect) {
  424. if (this._boundBuffersVertexArray) {
  425. this._deleteVertexArray(this._boundBuffersVertexArray);
  426. }
  427. this._boundBuffersVertexArray = this._engine.createVertexArray();
  428. this._recordVertexArrayObject(this._boundBuffersVertexArray, vertexBuffers, indexBuffer, effect);
  429. this.bindVertexArrayObject(this._boundBuffersVertexArray);
  430. }
  431. recordVertexArrayObject(vertexBuffers, indexBuffer, effect, overrideVertexBuffers) {
  432. const vertexArray = this._engine.createVertexArray();
  433. this._recordVertexArrayObject(vertexArray, vertexBuffers, indexBuffer, effect, overrideVertexBuffers);
  434. return vertexArray;
  435. }
  436. _deleteVertexArray(vertexArray) {
  437. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DELETEVERTEXARRAY);
  438. this._commandBufferEncoder.encodeCommandArgAsNativeData(vertexArray);
  439. this._commandBufferEncoder.finishEncodingCommand();
  440. }
  441. bindVertexArrayObject(vertexArray) {
  442. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_BINDVERTEXARRAY);
  443. this._commandBufferEncoder.encodeCommandArgAsNativeData(vertexArray);
  444. this._commandBufferEncoder.finishEncodingCommand();
  445. }
  446. releaseVertexArrayObject(vertexArray) {
  447. this._deleteVertexArray(vertexArray);
  448. }
  449. getAttributes(pipelineContext, attributesNames) {
  450. const nativePipelineContext = pipelineContext;
  451. return this._engine.getAttributes(nativePipelineContext.program, attributesNames);
  452. }
  453. /**
  454. * Draw a list of indexed primitives
  455. * @param fillMode defines the primitive to use
  456. * @param indexStart defines the starting index
  457. * @param indexCount defines the number of index to draw
  458. * @param instancesCount defines the number of instances to draw (if instantiation is enabled)
  459. */
  460. drawElementsType(fillMode, indexStart, indexCount, instancesCount) {
  461. // Apply states
  462. this._drawCalls.addCount(1, false);
  463. if (instancesCount && _native.Engine.COMMAND_DRAWINDEXEDINSTANCED) {
  464. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DRAWINDEXEDINSTANCED);
  465. this._commandBufferEncoder.encodeCommandArgAsUInt32(fillMode);
  466. this._commandBufferEncoder.encodeCommandArgAsUInt32(indexStart);
  467. this._commandBufferEncoder.encodeCommandArgAsUInt32(indexCount);
  468. this._commandBufferEncoder.encodeCommandArgAsUInt32(instancesCount);
  469. }
  470. else {
  471. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DRAWINDEXED);
  472. this._commandBufferEncoder.encodeCommandArgAsUInt32(fillMode);
  473. this._commandBufferEncoder.encodeCommandArgAsUInt32(indexStart);
  474. this._commandBufferEncoder.encodeCommandArgAsUInt32(indexCount);
  475. }
  476. this._commandBufferEncoder.finishEncodingCommand();
  477. // }
  478. }
  479. /**
  480. * Draw a list of unindexed primitives
  481. * @param fillMode defines the primitive to use
  482. * @param verticesStart defines the index of first vertex to draw
  483. * @param verticesCount defines the count of vertices to draw
  484. * @param instancesCount defines the number of instances to draw (if instantiation is enabled)
  485. */
  486. drawArraysType(fillMode, verticesStart, verticesCount, instancesCount) {
  487. // Apply states
  488. this._drawCalls.addCount(1, false);
  489. if (instancesCount && _native.Engine.COMMAND_DRAWINSTANCED) {
  490. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DRAWINSTANCED);
  491. this._commandBufferEncoder.encodeCommandArgAsUInt32(fillMode);
  492. this._commandBufferEncoder.encodeCommandArgAsUInt32(verticesStart);
  493. this._commandBufferEncoder.encodeCommandArgAsUInt32(verticesCount);
  494. this._commandBufferEncoder.encodeCommandArgAsUInt32(instancesCount);
  495. }
  496. else {
  497. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DRAW);
  498. this._commandBufferEncoder.encodeCommandArgAsUInt32(fillMode);
  499. this._commandBufferEncoder.encodeCommandArgAsUInt32(verticesStart);
  500. this._commandBufferEncoder.encodeCommandArgAsUInt32(verticesCount);
  501. }
  502. this._commandBufferEncoder.finishEncodingCommand();
  503. // }
  504. }
  505. createPipelineContext() {
  506. const isAsync = !!(this._caps.parallelShaderCompile && this._engine.createProgramAsync);
  507. return new NativePipelineContext(this, isAsync);
  508. }
  509. createMaterialContext() {
  510. return undefined;
  511. }
  512. createDrawContext() {
  513. return undefined;
  514. }
  515. /**
  516. * @internal
  517. */
  518. _preparePipelineContext(pipelineContext, vertexSourceCode, fragmentSourceCode, createAsRaw, _rawVertexSourceCode, _rawFragmentSourceCode, _rebuildRebind, defines) {
  519. if (createAsRaw) {
  520. this.createRawShaderProgram();
  521. }
  522. else {
  523. this.createShaderProgram(pipelineContext, vertexSourceCode, fragmentSourceCode, defines);
  524. }
  525. }
  526. /**
  527. * @internal
  528. */
  529. _executeWhenRenderingStateIsCompiled(pipelineContext, action) {
  530. const nativePipelineContext = pipelineContext;
  531. if (nativePipelineContext.isAsync) {
  532. if (nativePipelineContext.onCompiled) {
  533. const oldHandler = nativePipelineContext.onCompiled;
  534. nativePipelineContext.onCompiled = () => {
  535. oldHandler();
  536. action();
  537. };
  538. }
  539. else {
  540. nativePipelineContext.onCompiled = action;
  541. }
  542. }
  543. else {
  544. action();
  545. }
  546. }
  547. createRawShaderProgram() {
  548. throw new Error("Not Supported");
  549. }
  550. createShaderProgram(pipelineContext, vertexCode, fragmentCode, defines) {
  551. const nativePipelineContext = pipelineContext;
  552. this.onBeforeShaderCompilationObservable.notifyObservers(this);
  553. const vertexInliner = new ShaderCodeInliner(vertexCode);
  554. vertexInliner.processCode();
  555. vertexCode = vertexInliner.code;
  556. const fragmentInliner = new ShaderCodeInliner(fragmentCode);
  557. fragmentInliner.processCode();
  558. fragmentCode = fragmentInliner.code;
  559. vertexCode = ThinEngine._ConcatenateShader(vertexCode, defines);
  560. fragmentCode = ThinEngine._ConcatenateShader(fragmentCode, defines);
  561. const onSuccess = () => {
  562. nativePipelineContext.isCompiled = true;
  563. nativePipelineContext.onCompiled?.();
  564. this.onAfterShaderCompilationObservable.notifyObservers(this);
  565. };
  566. if (pipelineContext.isAsync) {
  567. nativePipelineContext.program = this._engine.createProgramAsync(vertexCode, fragmentCode, onSuccess, (error) => {
  568. nativePipelineContext.compilationError = error;
  569. });
  570. }
  571. else {
  572. try {
  573. nativePipelineContext.program = this._engine.createProgram(vertexCode, fragmentCode);
  574. onSuccess();
  575. }
  576. catch (e) {
  577. const message = e?.message;
  578. throw new Error("SHADER ERROR" + (typeof message === "string" ? "\n" + message : ""));
  579. }
  580. }
  581. return nativePipelineContext.program;
  582. }
  583. /**
  584. * Inline functions in shader code that are marked to be inlined
  585. * @param code code to inline
  586. * @returns inlined code
  587. */
  588. inlineShaderCode(code) {
  589. const sci = new ShaderCodeInliner(code);
  590. sci.debug = false;
  591. sci.processCode();
  592. return sci.code;
  593. }
  594. _setProgram(program) {
  595. if (this._currentProgram !== program) {
  596. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETPROGRAM);
  597. this._commandBufferEncoder.encodeCommandArgAsNativeData(program);
  598. this._commandBufferEncoder.finishEncodingCommand();
  599. this._currentProgram = program;
  600. }
  601. }
  602. _deletePipelineContext(pipelineContext) {
  603. const nativePipelineContext = pipelineContext;
  604. if (nativePipelineContext && nativePipelineContext.program) {
  605. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DELETEPROGRAM);
  606. this._commandBufferEncoder.encodeCommandArgAsNativeData(nativePipelineContext.program);
  607. this._commandBufferEncoder.finishEncodingCommand();
  608. }
  609. }
  610. getUniforms(pipelineContext, uniformsNames) {
  611. const nativePipelineContext = pipelineContext;
  612. return this._engine.getUniforms(nativePipelineContext.program, uniformsNames);
  613. }
  614. bindUniformBlock(pipelineContext, blockName, index) {
  615. // TODO
  616. throw new Error("Not Implemented");
  617. }
  618. bindSamplers(effect) {
  619. const nativePipelineContext = effect.getPipelineContext();
  620. this._setProgram(nativePipelineContext.program);
  621. // TODO: share this with engine?
  622. const samplers = effect.getSamplers();
  623. for (let index = 0; index < samplers.length; index++) {
  624. const uniform = effect.getUniform(samplers[index]);
  625. if (uniform) {
  626. this._boundUniforms[index] = uniform;
  627. }
  628. }
  629. this._currentEffect = null;
  630. }
  631. getRenderWidth(useScreen = false) {
  632. if (!useScreen && this._currentRenderTarget) {
  633. return this._currentRenderTarget.width;
  634. }
  635. return this._engine.getRenderWidth();
  636. }
  637. getRenderHeight(useScreen = false) {
  638. if (!useScreen && this._currentRenderTarget) {
  639. return this._currentRenderTarget.height;
  640. }
  641. return this._engine.getRenderHeight();
  642. }
  643. setViewport(viewport, requiredWidth, requiredHeight) {
  644. this._cachedViewport = viewport;
  645. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETVIEWPORT);
  646. this._commandBufferEncoder.encodeCommandArgAsFloat32(viewport.x);
  647. this._commandBufferEncoder.encodeCommandArgAsFloat32(viewport.y);
  648. this._commandBufferEncoder.encodeCommandArgAsFloat32(viewport.width);
  649. this._commandBufferEncoder.encodeCommandArgAsFloat32(viewport.height);
  650. this._commandBufferEncoder.finishEncodingCommand();
  651. }
  652. enableScissor(x, y, width, height) {
  653. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETSCISSOR);
  654. this._commandBufferEncoder.encodeCommandArgAsFloat32(x);
  655. this._commandBufferEncoder.encodeCommandArgAsFloat32(y);
  656. this._commandBufferEncoder.encodeCommandArgAsFloat32(width);
  657. this._commandBufferEncoder.encodeCommandArgAsFloat32(height);
  658. this._commandBufferEncoder.finishEncodingCommand();
  659. }
  660. disableScissor() {
  661. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETSCISSOR);
  662. this._commandBufferEncoder.encodeCommandArgAsFloat32(0);
  663. this._commandBufferEncoder.encodeCommandArgAsFloat32(0);
  664. this._commandBufferEncoder.encodeCommandArgAsFloat32(0);
  665. this._commandBufferEncoder.encodeCommandArgAsFloat32(0);
  666. this._commandBufferEncoder.finishEncodingCommand();
  667. }
  668. setState(culling, zOffset = 0, force, reverseSide = false, cullBackFaces, stencil, zOffsetUnits = 0) {
  669. this._zOffset = zOffset;
  670. this._zOffsetUnits = zOffsetUnits;
  671. if (this._zOffset !== 0) {
  672. Tools.Warn("zOffset is not supported in Native engine.");
  673. }
  674. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETSTATE);
  675. this._commandBufferEncoder.encodeCommandArgAsUInt32(culling ? 1 : 0);
  676. this._commandBufferEncoder.encodeCommandArgAsFloat32(zOffset);
  677. this._commandBufferEncoder.encodeCommandArgAsFloat32(zOffsetUnits);
  678. this._commandBufferEncoder.encodeCommandArgAsUInt32(this.cullBackFaces ?? cullBackFaces ?? true ? 1 : 0);
  679. this._commandBufferEncoder.encodeCommandArgAsUInt32(reverseSide ? 1 : 0);
  680. this._commandBufferEncoder.finishEncodingCommand();
  681. }
  682. /**
  683. * Gets the client rect of native canvas. Needed for InputManager.
  684. * @returns a client rectangle
  685. */
  686. getInputElementClientRect() {
  687. const rect = {
  688. bottom: this.getRenderHeight(),
  689. height: this.getRenderHeight(),
  690. left: 0,
  691. right: this.getRenderWidth(),
  692. top: 0,
  693. width: this.getRenderWidth(),
  694. x: 0,
  695. y: 0,
  696. toJSON: () => { },
  697. };
  698. return rect;
  699. }
  700. /**
  701. * Set the z offset Factor to apply to current rendering
  702. * @param value defines the offset to apply
  703. */
  704. setZOffset(value) {
  705. if (value !== this._zOffset) {
  706. this._zOffset = value;
  707. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETZOFFSET);
  708. this._commandBufferEncoder.encodeCommandArgAsFloat32(this.useReverseDepthBuffer ? -value : value);
  709. this._commandBufferEncoder.finishEncodingCommand();
  710. }
  711. }
  712. /**
  713. * Gets the current value of the zOffset Factor
  714. * @returns the current zOffset Factor state
  715. */
  716. getZOffset() {
  717. return this._zOffset;
  718. }
  719. /**
  720. * Set the z offset Units to apply to current rendering
  721. * @param value defines the offset to apply
  722. */
  723. setZOffsetUnits(value) {
  724. if (value !== this._zOffsetUnits) {
  725. this._zOffsetUnits = value;
  726. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETZOFFSETUNITS);
  727. this._commandBufferEncoder.encodeCommandArgAsFloat32(this.useReverseDepthBuffer ? -value : value);
  728. this._commandBufferEncoder.finishEncodingCommand();
  729. }
  730. }
  731. /**
  732. * Gets the current value of the zOffset Units
  733. * @returns the current zOffset Units state
  734. */
  735. getZOffsetUnits() {
  736. return this._zOffsetUnits;
  737. }
  738. /**
  739. * Enable or disable depth buffering
  740. * @param enable defines the state to set
  741. */
  742. setDepthBuffer(enable) {
  743. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETDEPTHTEST);
  744. this._commandBufferEncoder.encodeCommandArgAsUInt32(enable ? this._currentDepthTest : _native.Engine.DEPTH_TEST_ALWAYS);
  745. this._commandBufferEncoder.finishEncodingCommand();
  746. }
  747. /**
  748. * Gets a boolean indicating if depth writing is enabled
  749. * @returns the current depth writing state
  750. */
  751. getDepthWrite() {
  752. return this._depthWrite;
  753. }
  754. getDepthFunction() {
  755. switch (this._currentDepthTest) {
  756. case _native.Engine.DEPTH_TEST_NEVER:
  757. return 512;
  758. case _native.Engine.DEPTH_TEST_ALWAYS:
  759. return 519;
  760. case _native.Engine.DEPTH_TEST_GREATER:
  761. return 516;
  762. case _native.Engine.DEPTH_TEST_GEQUAL:
  763. return 518;
  764. case _native.Engine.DEPTH_TEST_NOTEQUAL:
  765. return 517;
  766. case _native.Engine.DEPTH_TEST_EQUAL:
  767. return 514;
  768. case _native.Engine.DEPTH_TEST_LESS:
  769. return 513;
  770. case _native.Engine.DEPTH_TEST_LEQUAL:
  771. return 515;
  772. }
  773. return null;
  774. }
  775. setDepthFunction(depthFunc) {
  776. let nativeDepthFunc = 0;
  777. switch (depthFunc) {
  778. case 512:
  779. nativeDepthFunc = _native.Engine.DEPTH_TEST_NEVER;
  780. break;
  781. case 519:
  782. nativeDepthFunc = _native.Engine.DEPTH_TEST_ALWAYS;
  783. break;
  784. case 516:
  785. nativeDepthFunc = _native.Engine.DEPTH_TEST_GREATER;
  786. break;
  787. case 518:
  788. nativeDepthFunc = _native.Engine.DEPTH_TEST_GEQUAL;
  789. break;
  790. case 517:
  791. nativeDepthFunc = _native.Engine.DEPTH_TEST_NOTEQUAL;
  792. break;
  793. case 514:
  794. nativeDepthFunc = _native.Engine.DEPTH_TEST_EQUAL;
  795. break;
  796. case 513:
  797. nativeDepthFunc = _native.Engine.DEPTH_TEST_LESS;
  798. break;
  799. case 515:
  800. nativeDepthFunc = _native.Engine.DEPTH_TEST_LEQUAL;
  801. break;
  802. }
  803. this._currentDepthTest = nativeDepthFunc;
  804. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETDEPTHTEST);
  805. this._commandBufferEncoder.encodeCommandArgAsUInt32(this._currentDepthTest);
  806. this._commandBufferEncoder.finishEncodingCommand();
  807. }
  808. /**
  809. * Enable or disable depth writing
  810. * @param enable defines the state to set
  811. */
  812. setDepthWrite(enable) {
  813. this._depthWrite = enable;
  814. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETDEPTHWRITE);
  815. this._commandBufferEncoder.encodeCommandArgAsUInt32(Number(enable));
  816. this._commandBufferEncoder.finishEncodingCommand();
  817. }
  818. /**
  819. * Enable or disable color writing
  820. * @param enable defines the state to set
  821. */
  822. setColorWrite(enable) {
  823. this._colorWrite = enable;
  824. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETCOLORWRITE);
  825. this._commandBufferEncoder.encodeCommandArgAsUInt32(Number(enable));
  826. this._commandBufferEncoder.finishEncodingCommand();
  827. }
  828. /**
  829. * Gets a boolean indicating if color writing is enabled
  830. * @returns the current color writing state
  831. */
  832. getColorWrite() {
  833. return this._colorWrite;
  834. }
  835. applyStencil() {
  836. this._setStencil(this._stencilMask, getNativeStencilOpFail(this._stencilOpStencilFail), getNativeStencilDepthFail(this._stencilOpDepthFail), getNativeStencilDepthPass(this._stencilOpStencilDepthPass), getNativeStencilFunc(this._stencilFunc), this._stencilFuncRef);
  837. }
  838. _setStencil(mask, stencilOpFail, depthOpFail, depthOpPass, func, ref) {
  839. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETSTENCIL);
  840. this._commandBufferEncoder.encodeCommandArgAsUInt32(mask);
  841. this._commandBufferEncoder.encodeCommandArgAsUInt32(stencilOpFail);
  842. this._commandBufferEncoder.encodeCommandArgAsUInt32(depthOpFail);
  843. this._commandBufferEncoder.encodeCommandArgAsUInt32(depthOpPass);
  844. this._commandBufferEncoder.encodeCommandArgAsUInt32(func);
  845. this._commandBufferEncoder.encodeCommandArgAsUInt32(ref);
  846. this._commandBufferEncoder.finishEncodingCommand();
  847. }
  848. /**
  849. * Enable or disable the stencil buffer
  850. * @param enable defines if the stencil buffer must be enabled or disabled
  851. */
  852. setStencilBuffer(enable) {
  853. this._stencilTest = enable;
  854. if (enable) {
  855. this.applyStencil();
  856. }
  857. else {
  858. this._setStencil(255, _native.Engine.STENCIL_OP_FAIL_S_KEEP, _native.Engine.STENCIL_OP_FAIL_Z_KEEP, _native.Engine.STENCIL_OP_PASS_Z_KEEP, _native.Engine.STENCIL_TEST_ALWAYS, 0);
  859. }
  860. }
  861. /**
  862. * Gets a boolean indicating if stencil buffer is enabled
  863. * @returns the current stencil buffer state
  864. */
  865. getStencilBuffer() {
  866. return this._stencilTest;
  867. }
  868. /**
  869. * Gets the current stencil operation when stencil passes
  870. * @returns a number defining stencil operation to use when stencil passes
  871. */
  872. getStencilOperationPass() {
  873. return this._stencilOpStencilDepthPass;
  874. }
  875. /**
  876. * Sets the stencil operation to use when stencil passes
  877. * @param operation defines the stencil operation to use when stencil passes
  878. */
  879. setStencilOperationPass(operation) {
  880. this._stencilOpStencilDepthPass = operation;
  881. this.applyStencil();
  882. }
  883. /**
  884. * Sets the current stencil mask
  885. * @param mask defines the new stencil mask to use
  886. */
  887. setStencilMask(mask) {
  888. this._stencilMask = mask;
  889. this.applyStencil();
  890. }
  891. /**
  892. * Sets the current stencil function
  893. * @param stencilFunc defines the new stencil function to use
  894. */
  895. setStencilFunction(stencilFunc) {
  896. this._stencilFunc = stencilFunc;
  897. this.applyStencil();
  898. }
  899. /**
  900. * Sets the current stencil reference
  901. * @param reference defines the new stencil reference to use
  902. */
  903. setStencilFunctionReference(reference) {
  904. this._stencilFuncRef = reference;
  905. this.applyStencil();
  906. }
  907. /**
  908. * Sets the current stencil mask
  909. * @param mask defines the new stencil mask to use
  910. */
  911. setStencilFunctionMask(mask) {
  912. this._stencilFuncMask = mask;
  913. }
  914. /**
  915. * Sets the stencil operation to use when stencil fails
  916. * @param operation defines the stencil operation to use when stencil fails
  917. */
  918. setStencilOperationFail(operation) {
  919. this._stencilOpStencilFail = operation;
  920. this.applyStencil();
  921. }
  922. /**
  923. * Sets the stencil operation to use when depth fails
  924. * @param operation defines the stencil operation to use when depth fails
  925. */
  926. setStencilOperationDepthFail(operation) {
  927. this._stencilOpDepthFail = operation;
  928. this.applyStencil();
  929. }
  930. /**
  931. * Gets the current stencil mask
  932. * @returns a number defining the new stencil mask to use
  933. */
  934. getStencilMask() {
  935. return this._stencilMask;
  936. }
  937. /**
  938. * Gets the current stencil function
  939. * @returns a number defining the stencil function to use
  940. */
  941. getStencilFunction() {
  942. return this._stencilFunc;
  943. }
  944. /**
  945. * Gets the current stencil reference value
  946. * @returns a number defining the stencil reference value to use
  947. */
  948. getStencilFunctionReference() {
  949. return this._stencilFuncRef;
  950. }
  951. /**
  952. * Gets the current stencil mask
  953. * @returns a number defining the stencil mask to use
  954. */
  955. getStencilFunctionMask() {
  956. return this._stencilFuncMask;
  957. }
  958. /**
  959. * Gets the current stencil operation when stencil fails
  960. * @returns a number defining stencil operation to use when stencil fails
  961. */
  962. getStencilOperationFail() {
  963. return this._stencilOpStencilFail;
  964. }
  965. /**
  966. * Gets the current stencil operation when depth fails
  967. * @returns a number defining stencil operation to use when depth fails
  968. */
  969. getStencilOperationDepthFail() {
  970. return this._stencilOpDepthFail;
  971. }
  972. /**
  973. * Sets alpha constants used by some alpha blending modes
  974. * @param r defines the red component
  975. * @param g defines the green component
  976. * @param b defines the blue component
  977. * @param a defines the alpha component
  978. */
  979. setAlphaConstants(r, g, b, a) {
  980. throw new Error("Setting alpha blend constant color not yet implemented.");
  981. }
  982. /**
  983. * Sets the current alpha mode
  984. * @param mode defines the mode to use (one of the BABYLON.undefined)
  985. * @param noDepthWriteChange defines if depth writing state should remains unchanged (false by default)
  986. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/advanced/transparent_rendering
  987. */
  988. setAlphaMode(mode, noDepthWriteChange = false) {
  989. if (this._alphaMode === mode) {
  990. return;
  991. }
  992. const nativeMode = getNativeAlphaMode(mode);
  993. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETBLENDMODE);
  994. this._commandBufferEncoder.encodeCommandArgAsUInt32(nativeMode);
  995. this._commandBufferEncoder.finishEncodingCommand();
  996. if (!noDepthWriteChange) {
  997. this.setDepthWrite(mode === 0);
  998. }
  999. this._alphaMode = mode;
  1000. }
  1001. /**
  1002. * Gets the current alpha mode
  1003. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/advanced/transparent_rendering
  1004. * @returns the current alpha mode
  1005. */
  1006. getAlphaMode() {
  1007. return this._alphaMode;
  1008. }
  1009. setInt(uniform, int) {
  1010. if (!uniform) {
  1011. return false;
  1012. }
  1013. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETINT);
  1014. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1015. this._commandBufferEncoder.encodeCommandArgAsInt32(int);
  1016. this._commandBufferEncoder.finishEncodingCommand();
  1017. return true;
  1018. }
  1019. setIntArray(uniform, array) {
  1020. if (!uniform) {
  1021. return false;
  1022. }
  1023. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETINTARRAY);
  1024. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1025. this._commandBufferEncoder.encodeCommandArgAsInt32s(array);
  1026. this._commandBufferEncoder.finishEncodingCommand();
  1027. return true;
  1028. }
  1029. setIntArray2(uniform, array) {
  1030. if (!uniform) {
  1031. return false;
  1032. }
  1033. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETINTARRAY2);
  1034. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1035. this._commandBufferEncoder.encodeCommandArgAsInt32s(array);
  1036. this._commandBufferEncoder.finishEncodingCommand();
  1037. return true;
  1038. }
  1039. setIntArray3(uniform, array) {
  1040. if (!uniform) {
  1041. return false;
  1042. }
  1043. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETINTARRAY3);
  1044. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1045. this._commandBufferEncoder.encodeCommandArgAsInt32s(array);
  1046. this._commandBufferEncoder.finishEncodingCommand();
  1047. return true;
  1048. }
  1049. setIntArray4(uniform, array) {
  1050. if (!uniform) {
  1051. return false;
  1052. }
  1053. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETINTARRAY4);
  1054. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1055. this._commandBufferEncoder.encodeCommandArgAsInt32s(array);
  1056. this._commandBufferEncoder.finishEncodingCommand();
  1057. return true;
  1058. }
  1059. setFloatArray(uniform, array) {
  1060. if (!uniform) {
  1061. return false;
  1062. }
  1063. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETFLOATARRAY);
  1064. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1065. this._commandBufferEncoder.encodeCommandArgAsFloat32s(array);
  1066. this._commandBufferEncoder.finishEncodingCommand();
  1067. return true;
  1068. }
  1069. setFloatArray2(uniform, array) {
  1070. if (!uniform) {
  1071. return false;
  1072. }
  1073. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETFLOATARRAY2);
  1074. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1075. this._commandBufferEncoder.encodeCommandArgAsFloat32s(array);
  1076. this._commandBufferEncoder.finishEncodingCommand();
  1077. return true;
  1078. }
  1079. setFloatArray3(uniform, array) {
  1080. if (!uniform) {
  1081. return false;
  1082. }
  1083. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETFLOATARRAY3);
  1084. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1085. this._commandBufferEncoder.encodeCommandArgAsFloat32s(array);
  1086. this._commandBufferEncoder.finishEncodingCommand();
  1087. return true;
  1088. }
  1089. setFloatArray4(uniform, array) {
  1090. if (!uniform) {
  1091. return false;
  1092. }
  1093. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETFLOATARRAY4);
  1094. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1095. this._commandBufferEncoder.encodeCommandArgAsFloat32s(array);
  1096. this._commandBufferEncoder.finishEncodingCommand();
  1097. return true;
  1098. }
  1099. setArray(uniform, array) {
  1100. if (!uniform) {
  1101. return false;
  1102. }
  1103. return this.setFloatArray(uniform, new Float32Array(array));
  1104. }
  1105. setArray2(uniform, array) {
  1106. if (!uniform) {
  1107. return false;
  1108. }
  1109. return this.setFloatArray2(uniform, new Float32Array(array));
  1110. }
  1111. setArray3(uniform, array) {
  1112. if (!uniform) {
  1113. return false;
  1114. }
  1115. return this.setFloatArray3(uniform, new Float32Array(array));
  1116. }
  1117. setArray4(uniform, array) {
  1118. if (!uniform) {
  1119. return false;
  1120. }
  1121. return this.setFloatArray4(uniform, new Float32Array(array));
  1122. }
  1123. setMatrices(uniform, matrices) {
  1124. if (!uniform) {
  1125. return false;
  1126. }
  1127. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETMATRICES);
  1128. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1129. this._commandBufferEncoder.encodeCommandArgAsFloat32s(matrices);
  1130. this._commandBufferEncoder.finishEncodingCommand();
  1131. return true;
  1132. }
  1133. setMatrix3x3(uniform, matrix) {
  1134. if (!uniform) {
  1135. return false;
  1136. }
  1137. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETMATRIX3X3);
  1138. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1139. this._commandBufferEncoder.encodeCommandArgAsFloat32s(matrix);
  1140. this._commandBufferEncoder.finishEncodingCommand();
  1141. return true;
  1142. }
  1143. setMatrix2x2(uniform, matrix) {
  1144. if (!uniform) {
  1145. return false;
  1146. }
  1147. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETMATRIX2X2);
  1148. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1149. this._commandBufferEncoder.encodeCommandArgAsFloat32s(matrix);
  1150. this._commandBufferEncoder.finishEncodingCommand();
  1151. return true;
  1152. }
  1153. setFloat(uniform, value) {
  1154. if (!uniform) {
  1155. return false;
  1156. }
  1157. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETFLOAT);
  1158. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1159. this._commandBufferEncoder.encodeCommandArgAsFloat32(value);
  1160. this._commandBufferEncoder.finishEncodingCommand();
  1161. return true;
  1162. }
  1163. setFloat2(uniform, x, y) {
  1164. if (!uniform) {
  1165. return false;
  1166. }
  1167. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETFLOAT2);
  1168. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1169. this._commandBufferEncoder.encodeCommandArgAsFloat32(x);
  1170. this._commandBufferEncoder.encodeCommandArgAsFloat32(y);
  1171. this._commandBufferEncoder.finishEncodingCommand();
  1172. return true;
  1173. }
  1174. setFloat3(uniform, x, y, z) {
  1175. if (!uniform) {
  1176. return false;
  1177. }
  1178. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETFLOAT3);
  1179. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1180. this._commandBufferEncoder.encodeCommandArgAsFloat32(x);
  1181. this._commandBufferEncoder.encodeCommandArgAsFloat32(y);
  1182. this._commandBufferEncoder.encodeCommandArgAsFloat32(z);
  1183. this._commandBufferEncoder.finishEncodingCommand();
  1184. return true;
  1185. }
  1186. setFloat4(uniform, x, y, z, w) {
  1187. if (!uniform) {
  1188. return false;
  1189. }
  1190. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETFLOAT4);
  1191. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1192. this._commandBufferEncoder.encodeCommandArgAsFloat32(x);
  1193. this._commandBufferEncoder.encodeCommandArgAsFloat32(y);
  1194. this._commandBufferEncoder.encodeCommandArgAsFloat32(z);
  1195. this._commandBufferEncoder.encodeCommandArgAsFloat32(w);
  1196. this._commandBufferEncoder.finishEncodingCommand();
  1197. return true;
  1198. }
  1199. setColor3(uniform, color3) {
  1200. if (!uniform) {
  1201. return false;
  1202. }
  1203. this.setFloat3(uniform, color3.r, color3.g, color3.b);
  1204. return true;
  1205. }
  1206. setColor4(uniform, color3, alpha) {
  1207. if (!uniform) {
  1208. return false;
  1209. }
  1210. this.setFloat4(uniform, color3.r, color3.g, color3.b, alpha);
  1211. return true;
  1212. }
  1213. wipeCaches(bruteForce) {
  1214. if (this.preventCacheWipeBetweenFrames) {
  1215. return;
  1216. }
  1217. this.resetTextureCache();
  1218. this._currentEffect = null;
  1219. if (bruteForce) {
  1220. this._currentProgram = null;
  1221. this._stencilStateComposer.reset();
  1222. this._depthCullingState.reset();
  1223. this._alphaState.reset();
  1224. }
  1225. this._cachedVertexBuffers = null;
  1226. this._cachedIndexBuffer = null;
  1227. this._cachedEffectForVertexBuffers = null;
  1228. }
  1229. _createTexture() {
  1230. return this._engine.createTexture();
  1231. }
  1232. _deleteTexture(texture) {
  1233. if (texture) {
  1234. this._engine.deleteTexture(texture);
  1235. }
  1236. }
  1237. /**
  1238. * Update the content of a dynamic texture
  1239. * @param texture defines the texture to update
  1240. * @param canvas defines the canvas containing the source
  1241. * @param invertY defines if data must be stored with Y axis inverted
  1242. * @param premulAlpha defines if alpha is stored as premultiplied
  1243. * @param format defines the format of the data
  1244. */
  1245. updateDynamicTexture(texture, canvas, invertY, premulAlpha = false, format) {
  1246. if (premulAlpha === void 0) {
  1247. premulAlpha = false;
  1248. }
  1249. if (!!texture && !!texture._hardwareTexture) {
  1250. const source = canvas.getCanvasTexture();
  1251. const destination = texture._hardwareTexture.underlyingResource;
  1252. this._engine.copyTexture(destination, source);
  1253. texture.isReady = true;
  1254. }
  1255. }
  1256. createDynamicTexture(width, height, generateMipMaps, samplingMode) {
  1257. // it's not possible to create 0x0 texture sized. Many bgfx methods assume texture size is at least 1x1(best case).
  1258. // Worst case is getting a crash/assert.
  1259. width = Math.max(width, 1);
  1260. height = Math.max(height, 1);
  1261. return this.createRawTexture(new Uint8Array(width * height * 4), width, height, 5, false, false, samplingMode);
  1262. }
  1263. createVideoElement(constraints) {
  1264. // create native object depending on stream. Only NativeCamera is supported for now.
  1265. if (this._camera) {
  1266. return this._camera.createVideo(constraints);
  1267. }
  1268. return null;
  1269. }
  1270. updateVideoTexture(texture, video, invertY) {
  1271. if (texture && texture._hardwareTexture && this._camera) {
  1272. const webGLTexture = texture._hardwareTexture.underlyingResource;
  1273. this._camera.updateVideoTexture(webGLTexture, video, invertY);
  1274. }
  1275. }
  1276. createRawTexture(data, width, height, format, generateMipMaps, invertY, samplingMode, compression = null, type = 0, creationFlags = 0, useSRGBBuffer = false) {
  1277. const texture = new InternalTexture(this, InternalTextureSource.Raw);
  1278. texture.format = format;
  1279. texture.generateMipMaps = generateMipMaps;
  1280. texture.samplingMode = samplingMode;
  1281. texture.invertY = invertY;
  1282. texture.baseWidth = width;
  1283. texture.baseHeight = height;
  1284. texture.width = texture.baseWidth;
  1285. texture.height = texture.baseHeight;
  1286. texture._compression = compression;
  1287. texture.type = type;
  1288. texture._useSRGBBuffer = this._getUseSRGBBuffer(useSRGBBuffer, !generateMipMaps);
  1289. this.updateRawTexture(texture, data, format, invertY, compression, type, texture._useSRGBBuffer);
  1290. if (texture._hardwareTexture) {
  1291. const webGLTexture = texture._hardwareTexture.underlyingResource;
  1292. const filter = getNativeSamplingMode(samplingMode);
  1293. this._setTextureSampling(webGLTexture, filter);
  1294. }
  1295. this._internalTexturesCache.push(texture);
  1296. return texture;
  1297. }
  1298. createRawTexture2DArray(data, width, height, depth, format, generateMipMaps, invertY, samplingMode, compression = null, textureType = 0) {
  1299. const texture = new InternalTexture(this, InternalTextureSource.Raw2DArray);
  1300. texture.baseWidth = width;
  1301. texture.baseHeight = height;
  1302. texture.baseDepth = depth;
  1303. texture.width = width;
  1304. texture.height = height;
  1305. texture.depth = depth;
  1306. texture.format = format;
  1307. texture.type = textureType;
  1308. texture.generateMipMaps = generateMipMaps;
  1309. texture.samplingMode = samplingMode;
  1310. texture.is2DArray = true;
  1311. if (texture._hardwareTexture) {
  1312. const nativeTexture = texture._hardwareTexture.underlyingResource;
  1313. this._engine.loadRawTexture2DArray(nativeTexture, data, width, height, depth, getNativeTextureFormat(format, textureType), generateMipMaps, invertY);
  1314. const filter = getNativeSamplingMode(samplingMode);
  1315. this._setTextureSampling(nativeTexture, filter);
  1316. }
  1317. texture.isReady = true;
  1318. this._internalTexturesCache.push(texture);
  1319. return texture;
  1320. }
  1321. updateRawTexture(texture, bufferView, format, invertY, compression = null, type = 0, useSRGBBuffer = false) {
  1322. if (!texture) {
  1323. return;
  1324. }
  1325. if (bufferView && texture._hardwareTexture) {
  1326. const underlyingResource = texture._hardwareTexture.underlyingResource;
  1327. this._engine.loadRawTexture(underlyingResource, bufferView, texture.width, texture.height, getNativeTextureFormat(format, type), texture.generateMipMaps, texture.invertY);
  1328. }
  1329. texture.isReady = true;
  1330. }
  1331. // TODO: Refactor to share more logic with babylon.engine.ts version.
  1332. /**
  1333. * Usually called from Texture.ts.
  1334. * Passed information to create a NativeTexture
  1335. * @param url defines a value which contains one of the following:
  1336. * * A conventional http URL, e.g. 'http://...' or 'file://...'
  1337. * * A base64 string of in-line texture data, e.g. 'data:image/jpg;base64,/...'
  1338. * * An indicator that data being passed using the buffer parameter, e.g. 'data:mytexture.jpg'
  1339. * @param noMipmap defines a boolean indicating that no mipmaps shall be generated. Ignored for compressed textures. They must be in the file
  1340. * @param invertY when true, image is flipped when loaded. You probably want true. Certain compressed textures may invert this if their default is inverted (eg. ktx)
  1341. * @param scene needed for loading to the correct scene
  1342. * @param samplingMode mode with should be used sample / access the texture (Default: Texture.TRILINEAR_SAMPLINGMODE)
  1343. * @param onLoad optional callback to be called upon successful completion
  1344. * @param onError optional callback to be called upon failure
  1345. * @param buffer a source of a file previously fetched as either a base64 string, an ArrayBuffer (compressed or image format), HTMLImageElement (image format), or a Blob
  1346. * @param fallback an internal argument in case the function must be called again, due to etc1 not having alpha capabilities
  1347. * @param format internal format. Default: RGB when extension is '.jpg' else RGBA. Ignored for compressed textures
  1348. * @param forcedExtension defines the extension to use to pick the right loader
  1349. * @param mimeType defines an optional mime type
  1350. * @param loaderOptions options to be passed to the loader
  1351. * @param creationFlags specific flags to use when creating the texture (1 for storage textures, for eg)
  1352. * @param useSRGBBuffer defines if the texture must be loaded in a sRGB GPU buffer (if supported by the GPU).
  1353. * @returns a InternalTexture for assignment back into BABYLON.Texture
  1354. */
  1355. createTexture(url, noMipmap, invertY, scene, samplingMode = 3, onLoad = null, onError = null, buffer = null, fallback = null, format = null, forcedExtension = null, mimeType, loaderOptions, creationFlags, useSRGBBuffer = false) {
  1356. url = url || "";
  1357. const fromData = url.substr(0, 5) === "data:";
  1358. //const fromBlob = url.substr(0, 5) === "blob:";
  1359. const isBase64 = fromData && url.indexOf(";base64,") !== -1;
  1360. const texture = fallback ? fallback : new InternalTexture(this, InternalTextureSource.Url);
  1361. const originalUrl = url;
  1362. if (this._transformTextureUrl && !isBase64 && !fallback && !buffer) {
  1363. url = this._transformTextureUrl(url);
  1364. }
  1365. // establish the file extension, if possible
  1366. const lastDot = url.lastIndexOf(".");
  1367. const extension = forcedExtension ? forcedExtension : lastDot > -1 ? url.substring(lastDot).toLowerCase() : "";
  1368. let loader = null;
  1369. for (const availableLoader of AbstractEngine._TextureLoaders) {
  1370. if (availableLoader.canLoad(extension)) {
  1371. loader = availableLoader;
  1372. break;
  1373. }
  1374. }
  1375. if (scene) {
  1376. scene.addPendingData(texture);
  1377. }
  1378. texture.url = url;
  1379. texture.generateMipMaps = !noMipmap;
  1380. texture.samplingMode = samplingMode;
  1381. texture.invertY = invertY;
  1382. texture._useSRGBBuffer = this._getUseSRGBBuffer(useSRGBBuffer, noMipmap);
  1383. if (!this.doNotHandleContextLost) {
  1384. // Keep a link to the buffer only if we plan to handle context lost
  1385. texture._buffer = buffer;
  1386. }
  1387. let onLoadObserver = null;
  1388. if (onLoad && !fallback) {
  1389. onLoadObserver = texture.onLoadedObservable.add(onLoad);
  1390. }
  1391. if (!fallback) {
  1392. this._internalTexturesCache.push(texture);
  1393. }
  1394. const onInternalError = (message, exception) => {
  1395. if (scene) {
  1396. scene.removePendingData(texture);
  1397. }
  1398. if (url === originalUrl) {
  1399. if (onLoadObserver) {
  1400. texture.onLoadedObservable.remove(onLoadObserver);
  1401. }
  1402. if (EngineStore.UseFallbackTexture) {
  1403. this.createTexture(EngineStore.FallbackTexture, noMipmap, texture.invertY, scene, samplingMode, null, onError, buffer, texture);
  1404. }
  1405. if (onError) {
  1406. onError((message || "Unknown error") + (EngineStore.UseFallbackTexture ? " - Fallback texture was used" : ""), exception);
  1407. }
  1408. }
  1409. else {
  1410. // fall back to the original url if the transformed url fails to load
  1411. Logger.Warn(`Failed to load ${url}, falling back to ${originalUrl}`);
  1412. this.createTexture(originalUrl, noMipmap, texture.invertY, scene, samplingMode, onLoad, onError, buffer, texture, format, forcedExtension, mimeType, loaderOptions);
  1413. }
  1414. };
  1415. // processing for non-image formats
  1416. if (loader) {
  1417. throw new Error("Loading textures from IInternalTextureLoader not yet implemented.");
  1418. }
  1419. else {
  1420. const onload = (data) => {
  1421. if (!texture._hardwareTexture) {
  1422. if (scene) {
  1423. scene.removePendingData(texture);
  1424. }
  1425. return;
  1426. }
  1427. const underlyingResource = texture._hardwareTexture.underlyingResource;
  1428. this._engine.loadTexture(underlyingResource, data, !noMipmap, invertY, texture._useSRGBBuffer, () => {
  1429. texture.baseWidth = this._engine.getTextureWidth(underlyingResource);
  1430. texture.baseHeight = this._engine.getTextureHeight(underlyingResource);
  1431. texture.width = texture.baseWidth;
  1432. texture.height = texture.baseHeight;
  1433. texture.isReady = true;
  1434. const filter = getNativeSamplingMode(samplingMode);
  1435. this._setTextureSampling(underlyingResource, filter);
  1436. if (scene) {
  1437. scene.removePendingData(texture);
  1438. }
  1439. texture.onLoadedObservable.notifyObservers(texture);
  1440. texture.onLoadedObservable.clear();
  1441. }, () => {
  1442. throw new Error("Could not load a native texture.");
  1443. });
  1444. };
  1445. if (fromData && buffer) {
  1446. if (buffer instanceof ArrayBuffer) {
  1447. onload(new Uint8Array(buffer));
  1448. }
  1449. else if (ArrayBuffer.isView(buffer)) {
  1450. onload(buffer);
  1451. }
  1452. else if (typeof buffer === "string") {
  1453. onload(new Uint8Array(Tools.DecodeBase64(buffer)));
  1454. }
  1455. else {
  1456. throw new Error("Unsupported buffer type");
  1457. }
  1458. }
  1459. else {
  1460. if (isBase64) {
  1461. onload(new Uint8Array(Tools.DecodeBase64(url)));
  1462. }
  1463. else {
  1464. this._loadFile(url, (data) => onload(new Uint8Array(data)), undefined, undefined, true, (request, exception) => {
  1465. onInternalError("Unable to load " + (request ? request.responseURL : url, exception));
  1466. });
  1467. }
  1468. }
  1469. }
  1470. return texture;
  1471. }
  1472. /**
  1473. * Wraps an external native texture in a Babylon texture.
  1474. * @param texture defines the external texture
  1475. * @param hasMipMaps defines whether the external texture has mip maps
  1476. * @param samplingMode defines the sampling mode for the external texture (default: 3)
  1477. * @returns the babylon internal texture
  1478. */
  1479. wrapNativeTexture(texture, hasMipMaps = false, samplingMode = 3) {
  1480. const hardwareTexture = new NativeHardwareTexture(texture, this._engine);
  1481. const internalTexture = new InternalTexture(this, InternalTextureSource.Unknown, true);
  1482. internalTexture._hardwareTexture = hardwareTexture;
  1483. internalTexture.baseWidth = this._engine.getTextureWidth(texture);
  1484. internalTexture.baseHeight = this._engine.getTextureHeight(texture);
  1485. internalTexture.width = internalTexture.baseWidth;
  1486. internalTexture.height = internalTexture.baseHeight;
  1487. internalTexture.isReady = true;
  1488. internalTexture.useMipMaps = hasMipMaps;
  1489. this.updateTextureSamplingMode(samplingMode, internalTexture);
  1490. return internalTexture;
  1491. }
  1492. // eslint-disable-next-line jsdoc/require-returns-check
  1493. /**
  1494. * Wraps an external web gl texture in a Babylon texture.
  1495. * @returns the babylon internal texture
  1496. */
  1497. wrapWebGLTexture() {
  1498. throw new Error("wrapWebGLTexture is not supported, use wrapNativeTexture instead.");
  1499. }
  1500. _createDepthStencilTexture(size, options, rtWrapper) {
  1501. // TODO: handle other options?
  1502. const generateStencil = options.generateStencil || false;
  1503. const samples = options.samples || 1;
  1504. const nativeRTWrapper = rtWrapper;
  1505. const texture = new InternalTexture(this, InternalTextureSource.DepthStencil);
  1506. const width = size.width ?? size;
  1507. const height = size.height ?? size;
  1508. const framebuffer = this._engine.createFrameBuffer(texture._hardwareTexture.underlyingResource, width, height, generateStencil, true, samples);
  1509. nativeRTWrapper._framebufferDepthStencil = framebuffer;
  1510. return texture;
  1511. }
  1512. /**
  1513. * @internal
  1514. */
  1515. _releaseFramebufferObjects(framebuffer) {
  1516. if (framebuffer) {
  1517. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DELETEFRAMEBUFFER);
  1518. this._commandBufferEncoder.encodeCommandArgAsNativeData(framebuffer);
  1519. this._commandBufferEncoder.finishEncodingCommand();
  1520. }
  1521. }
  1522. /**
  1523. * @internal Engine abstraction for loading and creating an image bitmap from a given source string.
  1524. * @param imageSource source to load the image from.
  1525. * @param options An object that sets options for the image's extraction.
  1526. * @returns ImageBitmap
  1527. */
  1528. _createImageBitmapFromSource(imageSource, options) {
  1529. const promise = new Promise((resolve, reject) => {
  1530. const image = this.createCanvasImage();
  1531. image.onload = () => {
  1532. try {
  1533. const imageBitmap = this._engine.createImageBitmap(image);
  1534. resolve(imageBitmap);
  1535. }
  1536. catch (error) {
  1537. reject(`Error loading image ${image.src} with exception: ${error}`);
  1538. }
  1539. };
  1540. image.onerror = (error) => {
  1541. reject(`Error loading image ${image.src} with exception: ${error}`);
  1542. };
  1543. image.src = imageSource;
  1544. });
  1545. return promise;
  1546. }
  1547. /**
  1548. * Engine abstraction for createImageBitmap
  1549. * @param image source for image
  1550. * @param options An object that sets options for the image's extraction.
  1551. * @returns ImageBitmap
  1552. */
  1553. createImageBitmap(image, options) {
  1554. return new Promise((resolve, reject) => {
  1555. if (Array.isArray(image)) {
  1556. const arr = image;
  1557. if (arr.length) {
  1558. const image = this._engine.createImageBitmap(arr[0]);
  1559. if (image) {
  1560. resolve(image);
  1561. return;
  1562. }
  1563. }
  1564. }
  1565. reject(`Unsupported data for createImageBitmap.`);
  1566. });
  1567. }
  1568. /**
  1569. * Resize an image and returns the image data as an uint8array
  1570. * @param image image to resize
  1571. * @param bufferWidth destination buffer width
  1572. * @param bufferHeight destination buffer height
  1573. * @returns an uint8array containing RGBA values of bufferWidth * bufferHeight size
  1574. */
  1575. resizeImageBitmap(image, bufferWidth, bufferHeight) {
  1576. return this._engine.resizeImageBitmap(image, bufferWidth, bufferHeight);
  1577. }
  1578. /**
  1579. * Creates a cube texture
  1580. * @param rootUrl defines the url where the files to load is located
  1581. * @param scene defines the current scene
  1582. * @param files defines the list of files to load (1 per face)
  1583. * @param noMipmap defines a boolean indicating that no mipmaps shall be generated (false by default)
  1584. * @param onLoad defines an optional callback raised when the texture is loaded
  1585. * @param onError defines an optional callback raised if there is an issue to load the texture
  1586. * @param format defines the format of the data
  1587. * @param forcedExtension defines the extension to use to pick the right loader
  1588. * @param createPolynomials if a polynomial sphere should be created for the cube texture
  1589. * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
  1590. * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
  1591. * @param fallback defines texture to use while falling back when (compressed) texture file not found.
  1592. * @param loaderOptions options to be passed to the loader
  1593. * @param useSRGBBuffer defines if the texture must be loaded in a sRGB GPU buffer (if supported by the GPU).
  1594. * @returns the cube texture as an InternalTexture
  1595. */
  1596. createCubeTexture(rootUrl, scene, files, noMipmap, onLoad = null, onError = null, format, forcedExtension = null, createPolynomials = false, lodScale = 0, lodOffset = 0, fallback = null, loaderOptions, useSRGBBuffer = false) {
  1597. const texture = fallback ? fallback : new InternalTexture(this, InternalTextureSource.Cube);
  1598. texture.isCube = true;
  1599. texture.url = rootUrl;
  1600. texture.generateMipMaps = !noMipmap;
  1601. texture._lodGenerationScale = lodScale;
  1602. texture._lodGenerationOffset = lodOffset;
  1603. texture._useSRGBBuffer = this._getUseSRGBBuffer(useSRGBBuffer, !!noMipmap);
  1604. if (!this._doNotHandleContextLost) {
  1605. texture._extension = forcedExtension;
  1606. texture._files = files;
  1607. }
  1608. const lastDot = rootUrl.lastIndexOf(".");
  1609. const extension = forcedExtension ? forcedExtension : lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "";
  1610. // TODO: use texture loader to load env files?
  1611. if (extension === ".env") {
  1612. const onloaddata = (data) => {
  1613. const info = GetEnvInfo(data);
  1614. texture.width = info.width;
  1615. texture.height = info.width;
  1616. UploadEnvSpherical(texture, info);
  1617. const specularInfo = info.specular;
  1618. if (!specularInfo) {
  1619. throw new Error(`Nothing else parsed so far`);
  1620. }
  1621. texture._lodGenerationScale = specularInfo.lodGenerationScale;
  1622. const imageData = CreateImageDataArrayBufferViews(data, info);
  1623. texture.format = 5;
  1624. texture.type = 0;
  1625. texture.generateMipMaps = true;
  1626. texture.getEngine().updateTextureSamplingMode(Texture.TRILINEAR_SAMPLINGMODE, texture);
  1627. texture._isRGBD = true;
  1628. texture.invertY = true;
  1629. this._engine.loadCubeTextureWithMips(texture._hardwareTexture.underlyingResource, imageData, false, texture._useSRGBBuffer, () => {
  1630. texture.isReady = true;
  1631. if (onLoad) {
  1632. onLoad();
  1633. }
  1634. }, () => {
  1635. throw new Error("Could not load a native cube texture.");
  1636. });
  1637. };
  1638. if (files && files.length === 6) {
  1639. throw new Error(`Multi-file loading not allowed on env files.`);
  1640. }
  1641. else {
  1642. const onInternalError = (request, exception) => {
  1643. if (onError && request) {
  1644. onError(request.status + " " + request.statusText, exception);
  1645. }
  1646. };
  1647. this._loadFile(rootUrl, (data) => {
  1648. onloaddata(new Uint8Array(data, 0, data.byteLength));
  1649. }, undefined, undefined, true, onInternalError);
  1650. }
  1651. }
  1652. else {
  1653. if (!files || files.length !== 6) {
  1654. throw new Error("Cannot load cubemap because 6 files were not defined");
  1655. }
  1656. // Reorder from [+X, +Y, +Z, -X, -Y, -Z] to [+X, -X, +Y, -Y, +Z, -Z].
  1657. const reorderedFiles = [files[0], files[3], files[1], files[4], files[2], files[5]];
  1658. Promise.all(reorderedFiles.map((file) => this._loadFileAsync(file, undefined, true).then((data) => new Uint8Array(data, 0, data.byteLength))))
  1659. .then((data) => {
  1660. return new Promise((resolve, reject) => {
  1661. this._engine.loadCubeTexture(texture._hardwareTexture.underlyingResource, data, !noMipmap, true, texture._useSRGBBuffer, resolve, reject);
  1662. });
  1663. })
  1664. .then(() => {
  1665. texture.isReady = true;
  1666. if (onLoad) {
  1667. onLoad();
  1668. }
  1669. }, (error) => {
  1670. if (onError) {
  1671. onError(`Failed to load cubemap: ${error.message}`, error);
  1672. }
  1673. });
  1674. }
  1675. this._internalTexturesCache.push(texture);
  1676. return texture;
  1677. }
  1678. /** @internal */
  1679. _createHardwareTexture() {
  1680. return new NativeHardwareTexture(this._createTexture(), this._engine);
  1681. }
  1682. /** @internal */
  1683. _createHardwareRenderTargetWrapper(isMulti, isCube, size) {
  1684. const rtWrapper = new NativeRenderTargetWrapper(isMulti, isCube, size, this);
  1685. this._renderTargetWrapperCache.push(rtWrapper);
  1686. return rtWrapper;
  1687. }
  1688. /** @internal */
  1689. _createInternalTexture(size, options, _delayGPUTextureCreation = true, source = InternalTextureSource.Unknown) {
  1690. let generateMipMaps = false;
  1691. let type = 0;
  1692. let samplingMode = 3;
  1693. let format = 5;
  1694. let useSRGBBuffer = false;
  1695. let samples = 1;
  1696. let label;
  1697. if (options !== undefined && typeof options === "object") {
  1698. generateMipMaps = !!options.generateMipMaps;
  1699. type = options.type === undefined ? 0 : options.type;
  1700. samplingMode = options.samplingMode === undefined ? 3 : options.samplingMode;
  1701. format = options.format === undefined ? 5 : options.format;
  1702. useSRGBBuffer = options.useSRGBBuffer === undefined ? false : options.useSRGBBuffer;
  1703. samples = options.samples ?? 1;
  1704. label = options.label;
  1705. }
  1706. else {
  1707. generateMipMaps = !!options;
  1708. }
  1709. useSRGBBuffer = this._getUseSRGBBuffer(useSRGBBuffer, !generateMipMaps);
  1710. if (type === 1 && !this._caps.textureFloatLinearFiltering) {
  1711. // if floating point linear (gl.FLOAT) then force to NEAREST_SAMPLINGMODE
  1712. samplingMode = 1;
  1713. }
  1714. else if (type === 2 && !this._caps.textureHalfFloatLinearFiltering) {
  1715. // if floating point linear (HALF_FLOAT) then force to NEAREST_SAMPLINGMODE
  1716. samplingMode = 1;
  1717. }
  1718. if (type === 1 && !this._caps.textureFloat) {
  1719. type = 0;
  1720. Logger.Warn("Float textures are not supported. Type forced to TEXTURETYPE_UNSIGNED_BYTE");
  1721. }
  1722. const texture = new InternalTexture(this, source);
  1723. const width = size.width ?? size;
  1724. const height = size.height ?? size;
  1725. const layers = size.layers || 0;
  1726. if (layers !== 0) {
  1727. throw new Error("Texture layers are not supported in Babylon Native");
  1728. }
  1729. const nativeTexture = texture._hardwareTexture.underlyingResource;
  1730. const nativeTextureFormat = getNativeTextureFormat(format, type);
  1731. // REVIEW: We are always setting the renderTarget flag as we don't know whether the texture will be used as a render target.
  1732. this._engine.initializeTexture(nativeTexture, width, height, generateMipMaps, nativeTextureFormat, true, useSRGBBuffer, samples);
  1733. this._setTextureSampling(nativeTexture, getNativeSamplingMode(samplingMode));
  1734. texture._useSRGBBuffer = useSRGBBuffer;
  1735. texture.baseWidth = width;
  1736. texture.baseHeight = height;
  1737. texture.width = width;
  1738. texture.height = height;
  1739. texture.depth = layers;
  1740. texture.isReady = true;
  1741. texture.samples = samples;
  1742. texture.generateMipMaps = generateMipMaps;
  1743. texture.samplingMode = samplingMode;
  1744. texture.type = type;
  1745. texture.format = format;
  1746. texture.label = label;
  1747. this._internalTexturesCache.push(texture);
  1748. return texture;
  1749. }
  1750. createRenderTargetTexture(size, options) {
  1751. const rtWrapper = this._createHardwareRenderTargetWrapper(false, false, size);
  1752. let generateDepthBuffer = true;
  1753. let generateStencilBuffer = false;
  1754. let noColorAttachment = false;
  1755. let colorAttachment = undefined;
  1756. let samples = 1;
  1757. if (options !== undefined && typeof options === "object") {
  1758. generateDepthBuffer = options.generateDepthBuffer ?? true;
  1759. generateStencilBuffer = !!options.generateStencilBuffer;
  1760. noColorAttachment = !!options.noColorAttachment;
  1761. colorAttachment = options.colorAttachment;
  1762. samples = options.samples ?? 1;
  1763. }
  1764. const texture = colorAttachment || (noColorAttachment ? null : this._createInternalTexture(size, options, true, InternalTextureSource.RenderTarget));
  1765. const width = size.width ?? size;
  1766. const height = size.height ?? size;
  1767. const framebuffer = this._engine.createFrameBuffer(texture ? texture._hardwareTexture.underlyingResource : null, width, height, generateStencilBuffer, generateDepthBuffer, samples);
  1768. rtWrapper._framebuffer = framebuffer;
  1769. rtWrapper._generateDepthBuffer = generateDepthBuffer;
  1770. rtWrapper._generateStencilBuffer = generateStencilBuffer;
  1771. rtWrapper._samples = samples;
  1772. rtWrapper.setTextures(texture);
  1773. return rtWrapper;
  1774. }
  1775. updateRenderTargetTextureSampleCount(rtWrapper, samples) {
  1776. Logger.Warn("Updating render target sample count is not currently supported");
  1777. return rtWrapper.samples;
  1778. }
  1779. updateTextureSamplingMode(samplingMode, texture) {
  1780. if (texture._hardwareTexture) {
  1781. const filter = getNativeSamplingMode(samplingMode);
  1782. this._setTextureSampling(texture._hardwareTexture.underlyingResource, filter);
  1783. }
  1784. texture.samplingMode = samplingMode;
  1785. }
  1786. bindFramebuffer(texture, faceIndex, requiredWidth, requiredHeight, forceFullscreenViewport) {
  1787. const nativeRTWrapper = texture;
  1788. if (this._currentRenderTarget) {
  1789. this.unBindFramebuffer(this._currentRenderTarget);
  1790. }
  1791. this._currentRenderTarget = texture;
  1792. if (faceIndex) {
  1793. throw new Error("Cuboid frame buffers are not yet supported in NativeEngine.");
  1794. }
  1795. if (requiredWidth || requiredHeight) {
  1796. throw new Error("Required width/height for frame buffers not yet supported in NativeEngine.");
  1797. }
  1798. if (forceFullscreenViewport) {
  1799. //Not supported yet but don't stop rendering
  1800. }
  1801. if (nativeRTWrapper._framebufferDepthStencil) {
  1802. this._bindUnboundFramebuffer(nativeRTWrapper._framebufferDepthStencil);
  1803. }
  1804. else {
  1805. this._bindUnboundFramebuffer(nativeRTWrapper._framebuffer);
  1806. }
  1807. }
  1808. unBindFramebuffer(texture, disableGenerateMipMaps = false, onBeforeUnbind) {
  1809. // NOTE: Disabling mipmap generation is not yet supported in NativeEngine.
  1810. this._currentRenderTarget = null;
  1811. if (onBeforeUnbind) {
  1812. onBeforeUnbind();
  1813. }
  1814. this._bindUnboundFramebuffer(null);
  1815. }
  1816. createDynamicVertexBuffer(data) {
  1817. return this.createVertexBuffer(data, true);
  1818. }
  1819. updateDynamicIndexBuffer(indexBuffer, indices, offset = 0) {
  1820. const buffer = indexBuffer;
  1821. const data = this._normalizeIndexData(indices);
  1822. buffer.is32Bits = data.BYTES_PER_ELEMENT === 4;
  1823. this._engine.updateDynamicIndexBuffer(buffer.nativeIndexBuffer, data.buffer, data.byteOffset, data.byteLength, offset);
  1824. }
  1825. updateDynamicVertexBuffer(vertexBuffer, data, byteOffset = 0, byteLength) {
  1826. const buffer = vertexBuffer;
  1827. const dataView = data instanceof Array ? new Float32Array(data) : data instanceof ArrayBuffer ? new Uint8Array(data) : data;
  1828. const byteView = new Uint8Array(dataView.buffer, dataView.byteOffset, byteLength ?? dataView.byteLength);
  1829. this._engine.updateDynamicVertexBuffer(buffer.nativeVertexBuffer, byteView.buffer, byteView.byteOffset, byteView.byteLength, byteOffset);
  1830. }
  1831. // TODO: Refactor to share more logic with base Engine implementation.
  1832. _setTexture(channel, texture, isPartOfTextureArray = false, depthStencilTexture = false) {
  1833. const uniform = this._boundUniforms[channel];
  1834. if (!uniform) {
  1835. return false;
  1836. }
  1837. // Not ready?
  1838. if (!texture) {
  1839. if (this._boundTexturesCache[channel] != null) {
  1840. this._activeChannel = channel;
  1841. this._boundTexturesCache[channel] = null;
  1842. }
  1843. return false;
  1844. }
  1845. // Video
  1846. if (texture.video) {
  1847. this._activeChannel = channel;
  1848. texture.update();
  1849. }
  1850. else if (texture.delayLoadState === 4) {
  1851. // Delay loading
  1852. texture.delayLoad();
  1853. return false;
  1854. }
  1855. let internalTexture;
  1856. if (depthStencilTexture) {
  1857. internalTexture = texture.depthStencilTexture;
  1858. }
  1859. else if (texture.isReady()) {
  1860. internalTexture = texture.getInternalTexture();
  1861. }
  1862. else if (texture.isCube) {
  1863. internalTexture = this.emptyCubeTexture;
  1864. }
  1865. else if (texture.is3D) {
  1866. internalTexture = this.emptyTexture3D;
  1867. }
  1868. else if (texture.is2DArray) {
  1869. internalTexture = this.emptyTexture2DArray;
  1870. }
  1871. else {
  1872. internalTexture = this.emptyTexture;
  1873. }
  1874. this._activeChannel = channel;
  1875. if (!internalTexture || !internalTexture._hardwareTexture) {
  1876. return false;
  1877. }
  1878. this._setTextureWrapMode(internalTexture._hardwareTexture.underlyingResource, getNativeAddressMode(texture.wrapU), getNativeAddressMode(texture.wrapV), getNativeAddressMode(texture.wrapR));
  1879. this._updateAnisotropicLevel(texture);
  1880. this._setTextureCore(uniform, internalTexture._hardwareTexture.underlyingResource);
  1881. return true;
  1882. }
  1883. // filter is a NativeFilter.XXXX value.
  1884. _setTextureSampling(texture, filter) {
  1885. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETTEXTURESAMPLING);
  1886. this._commandBufferEncoder.encodeCommandArgAsNativeData(texture);
  1887. this._commandBufferEncoder.encodeCommandArgAsUInt32(filter);
  1888. this._commandBufferEncoder.finishEncodingCommand();
  1889. }
  1890. // addressModes are NativeAddressMode.XXXX values.
  1891. _setTextureWrapMode(texture, addressModeU, addressModeV, addressModeW) {
  1892. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETTEXTUREWRAPMODE);
  1893. this._commandBufferEncoder.encodeCommandArgAsNativeData(texture);
  1894. this._commandBufferEncoder.encodeCommandArgAsUInt32(addressModeU);
  1895. this._commandBufferEncoder.encodeCommandArgAsUInt32(addressModeV);
  1896. this._commandBufferEncoder.encodeCommandArgAsUInt32(addressModeW);
  1897. this._commandBufferEncoder.finishEncodingCommand();
  1898. }
  1899. _setTextureCore(uniform, texture) {
  1900. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETTEXTURE);
  1901. this._commandBufferEncoder.encodeCommandArgAsNativeData(uniform);
  1902. this._commandBufferEncoder.encodeCommandArgAsNativeData(texture);
  1903. this._commandBufferEncoder.finishEncodingCommand();
  1904. }
  1905. // TODO: Share more of this logic with the base implementation.
  1906. // TODO: Rename to match naming in base implementation once refactoring allows different parameters.
  1907. _updateAnisotropicLevel(texture) {
  1908. const internalTexture = texture.getInternalTexture();
  1909. const value = texture.anisotropicFilteringLevel;
  1910. if (!internalTexture || !internalTexture._hardwareTexture) {
  1911. return;
  1912. }
  1913. if (internalTexture._cachedAnisotropicFilteringLevel !== value) {
  1914. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_SETTEXTUREANISOTROPICLEVEL);
  1915. this._commandBufferEncoder.encodeCommandArgAsNativeData(internalTexture._hardwareTexture.underlyingResource);
  1916. this._commandBufferEncoder.encodeCommandArgAsUInt32(value);
  1917. this._commandBufferEncoder.finishEncodingCommand();
  1918. internalTexture._cachedAnisotropicFilteringLevel = value;
  1919. }
  1920. }
  1921. /**
  1922. * @internal
  1923. */
  1924. _bindTexture(channel, texture) {
  1925. const uniform = this._boundUniforms[channel];
  1926. if (!uniform) {
  1927. return;
  1928. }
  1929. if (texture && texture._hardwareTexture) {
  1930. const underlyingResource = texture._hardwareTexture.underlyingResource;
  1931. this._setTextureCore(uniform, underlyingResource);
  1932. }
  1933. }
  1934. _deleteBuffer(buffer) {
  1935. if (buffer.nativeIndexBuffer) {
  1936. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DELETEINDEXBUFFER);
  1937. this._commandBufferEncoder.encodeCommandArgAsNativeData(buffer.nativeIndexBuffer);
  1938. this._commandBufferEncoder.finishEncodingCommand();
  1939. delete buffer.nativeIndexBuffer;
  1940. }
  1941. if (buffer.nativeVertexBuffer) {
  1942. this._commandBufferEncoder.startEncodingCommand(_native.Engine.COMMAND_DELETEVERTEXBUFFER);
  1943. this._commandBufferEncoder.encodeCommandArgAsNativeData(buffer.nativeVertexBuffer);
  1944. this._commandBufferEncoder.finishEncodingCommand();
  1945. delete buffer.nativeVertexBuffer;
  1946. }
  1947. }
  1948. /**
  1949. * Create a canvas
  1950. * @param width width
  1951. * @param height height
  1952. * @returns ICanvas interface
  1953. */
  1954. createCanvas(width, height) {
  1955. if (!_native.Canvas) {
  1956. throw new Error("Native Canvas plugin not available.");
  1957. }
  1958. const canvas = new _native.Canvas();
  1959. canvas.width = width;
  1960. canvas.height = height;
  1961. return canvas;
  1962. }
  1963. /**
  1964. * Create an image to use with canvas
  1965. * @returns IImage interface
  1966. */
  1967. createCanvasImage() {
  1968. if (!_native.Canvas) {
  1969. throw new Error("Native Canvas plugin not available.");
  1970. }
  1971. const image = new _native.Image();
  1972. return image;
  1973. }
  1974. /**
  1975. * Update a portion of an internal texture
  1976. * @param texture defines the texture to update
  1977. * @param imageData defines the data to store into the texture
  1978. * @param xOffset defines the x coordinates of the update rectangle
  1979. * @param yOffset defines the y coordinates of the update rectangle
  1980. * @param width defines the width of the update rectangle
  1981. * @param height defines the height of the update rectangle
  1982. * @param faceIndex defines the face index if texture is a cube (0 by default)
  1983. * @param lod defines the lod level to update (0 by default)
  1984. * @param generateMipMaps defines whether to generate mipmaps or not
  1985. */
  1986. updateTextureData(texture, imageData, xOffset, yOffset, width, height, faceIndex = 0, lod = 0, generateMipMaps = false) {
  1987. throw new Error("updateTextureData not implemented.");
  1988. }
  1989. /**
  1990. * @internal
  1991. */
  1992. _uploadCompressedDataToTextureDirectly(texture, internalFormat, width, height, data, faceIndex = 0, lod = 0) {
  1993. throw new Error("_uploadCompressedDataToTextureDirectly not implemented.");
  1994. }
  1995. /**
  1996. * @internal
  1997. */
  1998. _uploadDataToTextureDirectly(texture, imageData, faceIndex = 0, lod = 0) {
  1999. throw new Error("_uploadDataToTextureDirectly not implemented.");
  2000. }
  2001. /**
  2002. * @internal
  2003. */
  2004. _uploadArrayBufferViewToTexture(texture, imageData, faceIndex = 0, lod = 0) {
  2005. throw new Error("_uploadArrayBufferViewToTexture not implemented.");
  2006. }
  2007. /**
  2008. * @internal
  2009. */
  2010. _uploadImageToTexture(texture, image, faceIndex = 0, lod = 0) {
  2011. throw new Error("_uploadArrayBufferViewToTexture not implemented.");
  2012. }
  2013. getFontOffset(font) {
  2014. // TODO
  2015. const result = { ascent: 0, height: 0, descent: 0 };
  2016. return result;
  2017. }
  2018. /**
  2019. * No equivalent for native. Do nothing.
  2020. */
  2021. flushFramebuffer() { }
  2022. _readTexturePixels(texture, width, height, faceIndex, level, buffer, _flushRenderer, _noDataConversion, x, y) {
  2023. if (faceIndex !== undefined && faceIndex !== -1) {
  2024. throw new Error(`Reading cubemap faces is not supported, but faceIndex is ${faceIndex}.`);
  2025. }
  2026. return this._engine
  2027. .readTexture(texture._hardwareTexture?.underlyingResource, level ?? 0, x ?? 0, y ?? 0, width, height, buffer?.buffer ?? null, buffer?.byteOffset ?? 0, buffer?.byteLength ?? 0)
  2028. .then((rawBuffer) => {
  2029. if (!buffer) {
  2030. buffer = new Uint8Array(rawBuffer);
  2031. }
  2032. return buffer;
  2033. });
  2034. }
  2035. }
  2036. // This must match the protocol version in NativeEngine.cpp
  2037. NativeEngine.PROTOCOL_VERSION = 8;
  2038. //# sourceMappingURL=nativeEngine.js.map