nativeEngine.ts 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  1. import { Nullable, IndicesArray, DataArray } from "../types";
  2. import { Engine, EngineCapabilities } from "../Engines/engine";
  3. import { VertexBuffer } from "../Meshes/buffer";
  4. import { InternalTexture } from "../Materials/Textures/internalTexture";
  5. import { IInternalTextureLoader } from "../Materials/Textures/internalTextureLoader";
  6. import { Texture } from "../Materials/Textures/texture";
  7. import { BaseTexture } from "../Materials/Textures/baseTexture";
  8. import { VideoTexture } from "../Materials/Textures/videoTexture";
  9. import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
  10. import { Effect } from "../Materials/effect";
  11. import { Tools } from "../Misc/tools";
  12. import { Observer } from "../Misc/observable";
  13. import { EnvironmentTextureTools, EnvironmentTextureSpecularInfoV1 } from "../Misc/environmentTextureTools";
  14. import { Color4, Matrix, Viewport, Color3 } from "../Maths/math";
  15. import { Scene } from "../scene";
  16. import { RenderTargetCreationOptions } from "../Materials/Textures/renderTargetCreationOptions";
  17. interface INativeEngine {
  18. requestAnimationFrame(callback: () => void): void;
  19. createVertexArray(): any;
  20. deleteVertexArray(vertexArray: any): void;
  21. bindVertexArray(vertexArray: any): void;
  22. createIndexBuffer(data: ArrayBufferView): any;
  23. deleteIndexBuffer(buffer: any): void;
  24. recordIndexBuffer(vertexArray: any, buffer: any): void;
  25. createVertexBuffer(data: DataArray, byteStride: number, infos: Array<{ location: number, numElements: number, byteOffset: number, normalized: boolean }>): any;
  26. deleteVertexBuffer(buffer: any): void;
  27. recordVertexBuffer(vertexArray: any, buffer: any): void;
  28. createProgram(vertexShader: string, fragmentShader: string): any;
  29. getUniforms(shaderProgram: any, uniformsNames: string[]): WebGLUniformLocation[];
  30. getAttributes(shaderProgram: any, attributeNames: string[]): number[];
  31. setProgram(program: any): void;
  32. setState(culling: boolean, zOffset: number, reverseSide: boolean): void;
  33. setZOffset(zOffset: number): void;
  34. getZOffset(): number;
  35. setDepthTest(enable: boolean): void;
  36. getDepthWrite(): boolean;
  37. setDepthWrite(enable: boolean): void;
  38. setColorWrite(enable: boolean): void;
  39. setBlendMode(blendMode: number): void;
  40. setMatrix(uniform: WebGLUniformLocation, matrix: Float32Array): void;
  41. setIntArray(uniform: WebGLUniformLocation, array: Int32Array): void;
  42. setIntArray2(uniform: WebGLUniformLocation, array: Int32Array): void;
  43. setIntArray3(uniform: WebGLUniformLocation, array: Int32Array): void;
  44. setIntArray4(uniform: WebGLUniformLocation, array: Int32Array): void;
  45. setFloatArray(uniform: WebGLUniformLocation, array: Float32Array | number[]): void;
  46. setFloatArray2(uniform: WebGLUniformLocation, array: Float32Array | number[]): void;
  47. setFloatArray3(uniform: WebGLUniformLocation, array: Float32Array | number[]): void;
  48. setFloatArray4(uniform: WebGLUniformLocation, array: Float32Array | number[]): void;
  49. setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): void;
  50. setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): void;
  51. setMatrix2x2(uniform: WebGLUniformLocation, matrix: Float32Array): void;
  52. setFloat(uniform: WebGLUniformLocation, value: number): void;
  53. setFloat2(uniform: WebGLUniformLocation, x: number, y: number): void;
  54. setFloat3(uniform: WebGLUniformLocation, x: number, y: number, z: number): void;
  55. setBool(uniform: WebGLUniformLocation, bool: number): void;
  56. setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void;
  57. createTexture(): WebGLTexture;
  58. loadTexture(texture: WebGLTexture, buffer: ArrayBuffer | Blob, mipMap: boolean): void;
  59. loadCubeTexture(texture: WebGLTexture, data: Array<Array<ArrayBufferView>>, flipY : boolean): void;
  60. getTextureWidth(texture: WebGLTexture): number;
  61. getTextureHeight(texture: WebGLTexture): number;
  62. setTextureSampling(texture: WebGLTexture, filter: number): void; // filter is a NativeFilter.XXXX value.
  63. setTextureWrapMode(texture: WebGLTexture, addressModeU: number, addressModeV: number, addressModeW: number): void; // addressModes are NativeAddressMode.XXXX values.
  64. setTextureAnisotropicLevel(texture: WebGLTexture, value: number): void;
  65. setTexture(uniform: WebGLUniformLocation, texture: Nullable<WebGLTexture>): void;
  66. deleteTexture(texture: Nullable<WebGLTexture>): void;
  67. drawIndexed(fillMode: number, indexStart: number, indexCount: number): void;
  68. draw(fillMode: number, vertexStart: number, vertexCount: number): void;
  69. clear(r: number, g: number, b: number, a: number, backBuffer: boolean, depth: boolean, stencil: boolean): void;
  70. getRenderWidth(): number;
  71. getRenderHeight(): number;
  72. }
  73. interface WebGLProgramInfo extends WebGLProgram {
  74. nativeProgram?: any;
  75. }
  76. interface WebGLBufferInfo extends WebGLBuffer {
  77. id: number;
  78. data: DataArray;
  79. nativeIndexBuffer?: any;
  80. nativeVertexBuffer?: any;
  81. }
  82. // Must match Filter enum in SpectreEngine.h.
  83. class NativeFilter {
  84. public static readonly POINT = 0;
  85. public static readonly MINPOINT_MAGPOINT_MIPPOINT = NativeFilter.POINT;
  86. public static readonly BILINEAR = 1;
  87. public static readonly MINLINEAR_MAGLINEAR_MIPPOINT = NativeFilter.BILINEAR;
  88. public static readonly TRILINEAR = 2;
  89. public static readonly MINLINEAR_MAGLINEAR_MIPLINEAR = NativeFilter.TRILINEAR;
  90. public static readonly ANISOTROPIC = 3;
  91. public static readonly POINT_COMPARE = 4;
  92. public static readonly TRILINEAR_COMPARE = 5;
  93. public static readonly MINBILINEAR_MAGPOINT = 6;
  94. public static readonly MINLINEAR_MAGPOINT_MIPLINEAR = NativeFilter.MINBILINEAR_MAGPOINT;
  95. public static readonly MINPOINT_MAGPOINT_MIPLINEAR = 7;
  96. public static readonly MINPOINT_MAGLINEAR_MIPPOINT = 8;
  97. public static readonly MINPOINT_MAGLINEAR_MIPLINEAR = 9;
  98. public static readonly MINLINEAR_MAGPOINT_MIPPOINT = 10;
  99. }
  100. // Must match AddressMode enum in SpectreEngine.h.
  101. class NativeAddressMode {
  102. public static readonly WRAP = 0;
  103. public static readonly MIRROR = 1;
  104. public static readonly CLAMP = 2;
  105. public static readonly BORDER = 3;
  106. public static readonly MIRROR_ONCE = 4;
  107. }
  108. // Must match BlendMode in SpectreEngine.h.
  109. class NativeBlendMode {
  110. public static readonly REPLACE = 0;
  111. public static readonly OVER = 1;
  112. public static readonly UNDER = 2;
  113. public static readonly INSIDE = 3;
  114. public static readonly ERASE = 4;
  115. public static readonly NULL = 5;
  116. public static readonly CLEAR = 6;
  117. public static readonly STRAIGHT_REPLACE = 7;
  118. public static readonly STRAIGHT_OVER = 8;
  119. public static readonly STRAIGHT_ADD = 9;
  120. public static readonly ADD = 10;
  121. public static readonly SCREEN = 11;
  122. public static readonly MULTIPLY = 12;
  123. public static readonly MULTIPLY2X = 13;
  124. public static readonly INTERPOLATE = 14;
  125. public static readonly MINIMUM = 15;
  126. public static readonly MAXIMUM = 16;
  127. public static readonly MAXIMUM_ALPHA = 17;
  128. public static readonly ADD_ALPHA = 18;
  129. public static readonly BLACK_REPLACE = 19;
  130. public static readonly BLACK_OVER = 20;
  131. public static readonly BLACK_UNDER = 21;
  132. public static readonly BLACK_INSIDE = 22;
  133. public static readonly ALPHA_COVERAGE_MASK = 23;
  134. public static readonly DUAL_COLOR_MULTIPLY_ADD = 24;
  135. public static readonly COMBINE = 25;
  136. public static readonly BLEND_OPAQUE = NativeBlendMode.REPLACE;
  137. public static readonly BLEND_ALPHA_PREMULTIPLIED = NativeBlendMode.OVER;
  138. public static readonly BLEND_ALPHA_STRAIGHT = NativeBlendMode.STRAIGHT_OVER;
  139. }
  140. /** @hidden */
  141. declare var nativeEngine: INativeEngine;
  142. /** @hidden */
  143. export class NativeEngineOptions {
  144. public textureSize = 512;
  145. public deterministicLockstep = false;
  146. public lockstepMaxSteps = 4;
  147. }
  148. /** @hidden */
  149. export class NativeEngine extends Engine {
  150. private readonly _native: INativeEngine = nativeEngine;
  151. private readonly _options: NativeEngineOptions;
  152. private _nextBufferId = 0;
  153. public isDeterministicLockStep(): boolean {
  154. return this._options.deterministicLockstep;
  155. }
  156. public getLockstepMaxSteps(): number {
  157. return this._options.lockstepMaxSteps;
  158. }
  159. public getHardwareScalingLevel(): number {
  160. return 1.0;
  161. }
  162. public constructor(options: NativeEngineOptions = new NativeEngineOptions()) {
  163. super(null);
  164. if (options.deterministicLockstep === undefined) {
  165. options.deterministicLockstep = false;
  166. }
  167. if (options.lockstepMaxSteps === undefined) {
  168. options.lockstepMaxSteps = 4;
  169. }
  170. this._options = options;
  171. // TODO: Initialize this more correctly based on the hardware capabilities reported by Spectre.
  172. // Init caps
  173. // We consider we are on a webgl1 capable device
  174. this._caps = new EngineCapabilities();
  175. this._caps.maxTexturesImageUnits = 16;
  176. this._caps.maxVertexTextureImageUnits = 16;
  177. this._caps.maxTextureSize = 512;
  178. this._caps.maxCubemapTextureSize = 512;
  179. this._caps.maxRenderTextureSize = 512;
  180. this._caps.maxVertexAttribs = 16;
  181. this._caps.maxVaryingVectors = 16;
  182. this._caps.maxFragmentUniformVectors = 16;
  183. this._caps.maxVertexUniformVectors = 16;
  184. // Extensions
  185. this._caps.standardDerivatives = true;
  186. this._caps.astc = null;
  187. this._caps.s3tc = null;
  188. this._caps.pvrtc = null;
  189. this._caps.etc1 = null;
  190. this._caps.etc2 = null;
  191. this._caps.maxAnisotropy = 16; // TODO: Retrieve this smartly. Currently set to D3D11 maximum allowable value.
  192. this._caps.uintIndices = false;
  193. this._caps.fragmentDepthSupported = false;
  194. this._caps.highPrecisionShaderSupported = true;
  195. this._caps.colorBufferFloat = false;
  196. this._caps.textureFloat = false;
  197. this._caps.textureFloatLinearFiltering = false;
  198. this._caps.textureFloatRender = false;
  199. this._caps.textureHalfFloat = false;
  200. this._caps.textureHalfFloatLinearFiltering = false;
  201. this._caps.textureHalfFloatRender = false;
  202. this._caps.textureLOD = true;
  203. this._caps.drawBuffersExtension = false;
  204. this._caps.depthTextureExtension = false;
  205. this._caps.vertexArrayObject = true;
  206. this._caps.instancedArrays = false;
  207. Tools.Log("Babylon Native (v" + Engine.Version + ") launched");
  208. // Wrappers
  209. if (typeof URL === "undefined") {
  210. (window.URL as any) = {
  211. createObjectURL: function() { },
  212. revokeObjectURL: function() { }
  213. };
  214. }
  215. if (typeof Blob === "undefined") {
  216. (window.Blob as any) = function() { };
  217. }
  218. }
  219. /**
  220. * Can be used to override the current requestAnimationFrame requester.
  221. * @hidden
  222. */
  223. protected _queueNewFrame(bindedRenderFunction: any, requester: any): number {
  224. this._native.requestAnimationFrame(bindedRenderFunction);
  225. return 0;
  226. }
  227. public clear(color: Color4, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
  228. this._native.clear(color.r, color.g, color.b, color.a, backBuffer, depth, stencil);
  229. }
  230. public createIndexBuffer(indices: IndicesArray): WebGLBufferInfo {
  231. const data = this._normalizeIndexData(indices);
  232. return {
  233. references: 1,
  234. capacity: 0,
  235. is32Bits: (data.BYTES_PER_ELEMENT === 4),
  236. id: this._nextBufferId++,
  237. data: data
  238. };
  239. }
  240. public createVertexBuffer(data: DataArray): WebGLBufferInfo {
  241. return {
  242. references: 1,
  243. capacity: 0,
  244. is32Bits: false,
  245. id: this._nextBufferId++,
  246. data: data
  247. };
  248. }
  249. public recordVertexArrayObject(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: Nullable<WebGLBufferInfo>, effect: Effect): WebGLVertexArrayObject {
  250. const vertexArray = this._native.createVertexArray();
  251. // Index
  252. if (indexBuffer) {
  253. if (!indexBuffer.nativeIndexBuffer) {
  254. indexBuffer.nativeIndexBuffer = this._native.createIndexBuffer(indexBuffer.data as ArrayBufferView);
  255. }
  256. this._native.recordIndexBuffer(vertexArray, indexBuffer.nativeIndexBuffer);
  257. }
  258. // Vertex
  259. // TODO: handle vertex buffers that are not Float32Array
  260. // Map the vertex buffers that point to the same underlying buffer.
  261. const map: { [id: number]: { buffer: WebGLBufferInfo, byteStride: number, infos: Array<{ location: number, numElements: number, byteOffset: number, normalized: boolean }> } } = {};
  262. const attributes = effect.getAttributesNames();
  263. for (let index = 0; index < attributes.length; index++) {
  264. const location = effect.getAttributeLocation(index);
  265. if (location >= 0) {
  266. const kind = attributes[index];
  267. const vertexBuffer = vertexBuffers[kind];
  268. if (vertexBuffer) {
  269. const buffer = vertexBuffer.getBuffer() as WebGLBufferInfo;
  270. if (buffer) {
  271. let entry = map[buffer.id];
  272. if (!entry) {
  273. entry = { buffer: buffer, byteStride: vertexBuffer.byteStride, infos: [] };
  274. map[buffer.id] = entry;
  275. }
  276. // TODO: check if byteStride matches for all vertex buffers??
  277. entry.infos.push({location: location, numElements: vertexBuffer.getSize(), byteOffset: vertexBuffer.byteOffset, normalized: vertexBuffer.normalized });
  278. }
  279. }
  280. }
  281. }
  282. // Record vertex buffer for each unique buffer.
  283. for (const id in map) {
  284. const entry = map[id];
  285. const buffer = entry.buffer;
  286. if (!buffer.nativeVertexBuffer) {
  287. buffer.nativeVertexBuffer = this._native.createVertexBuffer(buffer.data, entry.byteStride, entry.infos);
  288. }
  289. this._native.recordVertexBuffer(vertexArray, buffer.nativeVertexBuffer);
  290. }
  291. return vertexArray;
  292. }
  293. public bindVertexArrayObject(vertexArray: WebGLVertexArrayObject): void {
  294. this._native.bindVertexArray(vertexArray);
  295. }
  296. public releaseVertexArrayObject(vertexArray: WebGLVertexArrayObject) {
  297. this._native.deleteVertexArray(vertexArray);
  298. }
  299. public getAttributes(shaderProgram: WebGLProgramInfo, attributesNames: string[]): number[] {
  300. return this._native.getAttributes(shaderProgram.nativeProgram, attributesNames);
  301. }
  302. /**
  303. * Draw a list of indexed primitives
  304. * @param fillMode defines the primitive to use
  305. * @param indexStart defines the starting index
  306. * @param indexCount defines the number of index to draw
  307. * @param instancesCount defines the number of instances to draw (if instanciation is enabled)
  308. */
  309. public drawElementsType(fillMode: number, indexStart: number, indexCount: number, instancesCount?: number): void {
  310. // Apply states
  311. this._drawCalls.addCount(1, false);
  312. // TODO: Make this implementation more robust like core Engine version.
  313. // Render
  314. //var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
  315. //var mult = this._uintIndicesCurrentlySet ? 4 : 2;
  316. // if (instancesCount) {
  317. // this._gl.drawElementsInstanced(drawMode, indexCount, indexFormat, indexStart * mult, instancesCount);
  318. // } else {
  319. this._native.drawIndexed(fillMode, indexStart, indexCount);
  320. // }
  321. }
  322. /**
  323. * Draw a list of unindexed primitives
  324. * @param fillMode defines the primitive to use
  325. * @param verticesStart defines the index of first vertex to draw
  326. * @param verticesCount defines the count of vertices to draw
  327. * @param instancesCount defines the number of instances to draw (if instanciation is enabled)
  328. */
  329. public drawArraysType(fillMode: number, verticesStart: number, verticesCount: number, instancesCount?: number): void {
  330. // Apply states
  331. this._drawCalls.addCount(1, false);
  332. // TODO: Make this implementation more robust like core Engine version.
  333. // if (instancesCount) {
  334. // this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
  335. // } else {
  336. this._native.draw(fillMode, verticesStart, verticesCount);
  337. // }
  338. }
  339. /**
  340. * Directly creates a webGL program
  341. * @param vertexCode defines the vertex shader code to use
  342. * @param fragmentCode defines the fragment shader code to use
  343. * @param context defines the webGL context to use (if not set, the current one will be used)
  344. * @param transformFeedbackVaryings defines the list of transform feedback varyings to use
  345. * @returns the new webGL program
  346. */
  347. public createRawShaderProgram(vertexCode: string, fragmentCode: string, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgramInfo {
  348. return {
  349. nativeProgram: this._native.createProgram(vertexCode, fragmentCode),
  350. isParallelCompiled: false
  351. };
  352. }
  353. /**
  354. * Creates a webGL program
  355. * @param vertexCode defines the vertex shader code to use
  356. * @param fragmentCode defines the fragment shader code to use
  357. * @param defines defines the string containing the defines to use to compile the shaders
  358. * @param context defines the webGL context to use (if not set, the current one will be used)
  359. * @param transformFeedbackVaryings defines the list of transform feedback varyings to use
  360. * @returns the new webGL program
  361. */
  362. public createShaderProgram(vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgramInfo {
  363. this.onBeforeShaderCompilationObservable.notifyObservers(this);
  364. // TODO: Share this shader version logic with base class.
  365. var shaderVersion = (this._webGLVersion > 1) ? "#version 300 es\n#define WEBGL2 \n" : "";
  366. var vertexCodeConcat = Engine._concatenateShader(vertexCode, defines, shaderVersion);
  367. var fragmentCodeConcat = Engine._concatenateShader(fragmentCode, defines, shaderVersion);
  368. var program = this.createRawShaderProgram(vertexCodeConcat, fragmentCodeConcat);
  369. program.transformFeedback = null;
  370. program.__SPECTOR_rebuildProgram = null;
  371. this.onAfterShaderCompilationObservable.notifyObservers(this);
  372. return program;
  373. }
  374. protected setProgram(program: WebGLProgramInfo): void {
  375. if (this._currentProgram !== program) {
  376. this._native.setProgram(program.nativeProgram);
  377. this._currentProgram = program;
  378. }
  379. }
  380. public getUniforms(shaderProgram: WebGLProgramInfo, uniformsNames: string[]): WebGLUniformLocation[] {
  381. return this._native.getUniforms(shaderProgram.nativeProgram, uniformsNames);
  382. }
  383. public setMatrix(uniform: WebGLUniformLocation, matrix: Matrix): void {
  384. if (!uniform) {
  385. return;
  386. }
  387. this._native.setMatrix(uniform, matrix.toArray() as Float32Array);
  388. }
  389. public getRenderWidth(useScreen = false): number {
  390. if (!useScreen && this._currentRenderTarget) {
  391. return this._currentRenderTarget.width;
  392. }
  393. return this._native.getRenderWidth();
  394. }
  395. public getRenderHeight(useScreen = false): number {
  396. if (!useScreen && this._currentRenderTarget) {
  397. return this._currentRenderTarget.height;
  398. }
  399. return this._native.getRenderHeight();
  400. }
  401. public setViewport(viewport: Viewport, requiredWidth?: number, requiredHeight?: number): void {
  402. // TODO: Implement.
  403. this._cachedViewport = viewport;
  404. }
  405. public setState(culling: boolean, zOffset: number = 0, force?: boolean, reverseSide = false): void {
  406. this._native.setState(culling, zOffset, reverseSide);
  407. }
  408. /**
  409. * Set the z offset to apply to current rendering
  410. * @param value defines the offset to apply
  411. */
  412. public setZOffset(value: number): void {
  413. this._native.setZOffset(value);
  414. }
  415. /**
  416. * Gets the current value of the zOffset
  417. * @returns the current zOffset state
  418. */
  419. public getZOffset(): number {
  420. return this._native.getZOffset();
  421. }
  422. /**
  423. * Enable or disable depth buffering
  424. * @param enable defines the state to set
  425. */
  426. public setDepthBuffer(enable: boolean): void {
  427. this._native.setDepthTest(enable);
  428. }
  429. /**
  430. * Gets a boolean indicating if depth writing is enabled
  431. * @returns the current depth writing state
  432. */
  433. public getDepthWrite(): boolean {
  434. return this._native.getDepthWrite();
  435. }
  436. /**
  437. * Enable or disable depth writing
  438. * @param enable defines the state to set
  439. */
  440. public setDepthWrite(enable: boolean): void {
  441. this._native.setDepthWrite(enable);
  442. }
  443. /**
  444. * Enable or disable color writing
  445. * @param enable defines the state to set
  446. */
  447. public setColorWrite(enable: boolean): void {
  448. this._native.setColorWrite(enable);
  449. this._colorWrite = enable;
  450. }
  451. /**
  452. * Gets a boolean indicating if color writing is enabled
  453. * @returns the current color writing state
  454. */
  455. public getColorWrite(): boolean {
  456. return this._colorWrite;
  457. }
  458. /**
  459. * Sets alpha constants used by some alpha blending modes
  460. * @param r defines the red component
  461. * @param g defines the green component
  462. * @param b defines the blue component
  463. * @param a defines the alpha component
  464. */
  465. public setAlphaConstants(r: number, g: number, b: number, a: number) {
  466. throw new Error("Setting alpha blend constant color not yet implemented.");
  467. }
  468. /**
  469. * Sets the current alpha mode
  470. * @param mode defines the mode to use (one of the BABYLON.Engine.ALPHA_XXX)
  471. * @param noDepthWriteChange defines if depth writing state should remains unchanged (false by default)
  472. * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
  473. */
  474. public setAlphaMode(mode: number, noDepthWriteChange: boolean = false): void {
  475. if (this._alphaMode === mode) {
  476. return;
  477. }
  478. this._native.setBlendMode(this._getBlendMode(mode));
  479. if (!noDepthWriteChange) {
  480. this.setDepthWrite(mode === Engine.ALPHA_DISABLE);
  481. }
  482. this._alphaMode = mode;
  483. }
  484. // Returns a NativeBlendMode.XXXX value.
  485. // Note: Many blend modes intentionally not implemented. If more are needed, they should be added.
  486. private _getBlendMode(mode: number): number {
  487. switch (mode) {
  488. case Engine.ALPHA_DISABLE:
  489. return NativeBlendMode.REPLACE;
  490. case Engine.ALPHA_PREMULTIPLIED_PORTERDUFF:
  491. return NativeBlendMode.OVER;
  492. case Engine.ALPHA_COMBINE:
  493. return NativeBlendMode.COMBINE;
  494. case Engine.ALPHA_SCREENMODE:
  495. return NativeBlendMode.SCREEN;
  496. default:
  497. throw new Error("Unexpected alpha mode: " + mode + ".");
  498. }
  499. }
  500. /**
  501. * Gets the current alpha mode
  502. * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
  503. * @returns the current alpha mode
  504. */
  505. public getAlphaMode(): number {
  506. return this._alphaMode;
  507. }
  508. public setIntArray(uniform: WebGLUniformLocation, array: Int32Array): void {
  509. if (!uniform) {
  510. return;
  511. }
  512. this._native.setIntArray(uniform, array);
  513. }
  514. public setIntArray2(uniform: WebGLUniformLocation, array: Int32Array): void {
  515. if (!uniform) {
  516. return;
  517. }
  518. this._native.setIntArray2(uniform, array);
  519. }
  520. public setIntArray3(uniform: WebGLUniformLocation, array: Int32Array): void {
  521. if (!uniform) {
  522. return;
  523. }
  524. this._native.setIntArray3(uniform, array);
  525. }
  526. public setIntArray4(uniform: WebGLUniformLocation, array: Int32Array): void {
  527. if (!uniform) {
  528. return;
  529. }
  530. this._native.setIntArray4(uniform, array);
  531. }
  532. public setFloatArray(uniform: WebGLUniformLocation, array: Float32Array): void {
  533. if (!uniform) {
  534. return;
  535. }
  536. this._native.setFloatArray(uniform, array);
  537. }
  538. public setFloatArray2(uniform: WebGLUniformLocation, array: Float32Array): void {
  539. if (!uniform) {
  540. return;
  541. }
  542. this._native.setFloatArray2(uniform, array);
  543. }
  544. public setFloatArray3(uniform: WebGLUniformLocation, array: Float32Array): void {
  545. if (!uniform) {
  546. return;
  547. }
  548. this._native.setFloatArray3(uniform, array);
  549. }
  550. public setFloatArray4(uniform: WebGLUniformLocation, array: Float32Array): void {
  551. if (!uniform) {
  552. return;
  553. }
  554. this._native.setFloatArray4(uniform, array);
  555. }
  556. public setArray(uniform: WebGLUniformLocation, array: number[]): void {
  557. if (!uniform) {
  558. return;
  559. }
  560. this._native.setFloatArray(uniform, array);
  561. }
  562. public setArray2(uniform: WebGLUniformLocation, array: number[]): void {
  563. if (!uniform) {
  564. return;
  565. }
  566. this._native.setFloatArray2(uniform, array);
  567. }
  568. public setArray3(uniform: WebGLUniformLocation, array: number[]): void {
  569. if (!uniform) {
  570. return;
  571. }
  572. this._native.setFloatArray3(uniform, array);
  573. }
  574. public setArray4(uniform: WebGLUniformLocation, array: number[]): void {
  575. if (!uniform) {
  576. return;
  577. }
  578. this._native.setFloatArray4(uniform, array);
  579. }
  580. public setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): void {
  581. if (!uniform) {
  582. return;
  583. }
  584. this._native.setMatrices(uniform, matrices);
  585. }
  586. public setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): void {
  587. if (!uniform) {
  588. return;
  589. }
  590. this._native.setMatrix3x3(uniform, matrix);
  591. }
  592. public setMatrix2x2(uniform: WebGLUniformLocation, matrix: Float32Array): void {
  593. if (!uniform) {
  594. return;
  595. }
  596. this._native.setMatrix2x2(uniform, matrix);
  597. }
  598. public setFloat(uniform: WebGLUniformLocation, value: number): void {
  599. if (!uniform) {
  600. return;
  601. }
  602. this._native.setFloat(uniform, value);
  603. }
  604. public setFloat2(uniform: WebGLUniformLocation, x: number, y: number): void {
  605. if (!uniform) {
  606. return;
  607. }
  608. this._native.setFloat2(uniform, x, y);
  609. }
  610. public setFloat3(uniform: WebGLUniformLocation, x: number, y: number, z: number): void {
  611. if (!uniform) {
  612. return;
  613. }
  614. this._native.setFloat3(uniform, x, y, z);
  615. }
  616. public setBool(uniform: WebGLUniformLocation, bool: number): void {
  617. if (!uniform) {
  618. return;
  619. }
  620. this._native.setBool(uniform, bool);
  621. }
  622. public setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void {
  623. if (!uniform) {
  624. return;
  625. }
  626. this._native.setFloat4(uniform, x, y, z, w);
  627. }
  628. public setColor3(uniform: WebGLUniformLocation, color3: Color3): void {
  629. if (!uniform) {
  630. return;
  631. }
  632. this._native.setFloat3(uniform, color3.r, color3.g, color3.b);
  633. }
  634. public setColor4(uniform: WebGLUniformLocation, color3: Color3, alpha: number): void {
  635. if (!uniform) {
  636. return;
  637. }
  638. this._native.setFloat4(uniform, color3.r, color3.g, color3.b, alpha);
  639. }
  640. public wipeCaches(bruteForce?: boolean): void {
  641. if (this.preventCacheWipeBetweenFrames) {
  642. return;
  643. }
  644. this.resetTextureCache();
  645. this._currentEffect = null;
  646. if (bruteForce) {
  647. this._currentProgram = null;
  648. this._stencilState.reset();
  649. this._depthCullingState.reset();
  650. this._alphaState.reset();
  651. }
  652. this._cachedVertexBuffers = null;
  653. this._cachedIndexBuffer = null;
  654. this._cachedEffectForVertexBuffers = null;
  655. }
  656. public _createTexture(): WebGLTexture {
  657. return this._native.createTexture();
  658. }
  659. protected _deleteTexture(texture: Nullable<WebGLTexture>): void {
  660. this._native.deleteTexture(texture);
  661. }
  662. // TODO: Refactor to share more logic with babylon.engine.ts version.
  663. /**
  664. * Usually called from BABYLON.Texture.ts.
  665. * Passed information to create a WebGLTexture
  666. * @param urlArg defines a value which contains one of the following:
  667. * * A conventional http URL, e.g. 'http://...' or 'file://...'
  668. * * A base64 string of in-line texture data, e.g. 'data:image/jpg;base64,/...'
  669. * * An indicator that data being passed using the buffer parameter, e.g. 'data:mytexture.jpg'
  670. * @param noMipmap defines a boolean indicating that no mipmaps shall be generated. Ignored for compressed textures. They must be in the file
  671. * @param invertY when true, image is flipped when loaded. You probably want true. Ignored for compressed textures. Must be flipped in the file
  672. * @param scene needed for loading to the correct scene
  673. * @param samplingMode mode with should be used sample / access the texture (Default: BABYLON.Texture.TRILINEAR_SAMPLINGMODE)
  674. * @param onLoad optional callback to be called upon successful completion
  675. * @param onError optional callback to be called upon failure
  676. * @param buffer a source of a file previously fetched as either a base64 string, an ArrayBuffer (compressed or image format), or a Blob
  677. * @param fallback an internal argument in case the function must be called again, due to etc1 not having alpha capabilities
  678. * @param format internal format. Default: RGB when extension is '.jpg' else RGBA. Ignored for compressed textures
  679. * @param forcedExtension defines the extension to use to pick the right loader
  680. * @returns a InternalTexture for assignment back into BABYLON.Texture
  681. */
  682. public createTexture(
  683. urlArg: Nullable<string>,
  684. noMipmap: boolean,
  685. invertY: boolean,
  686. scene: Nullable<Scene>,
  687. samplingMode: number = Engine.TEXTURE_TRILINEAR_SAMPLINGMODE,
  688. onLoad: Nullable<() => void> = null,
  689. onError: Nullable<(message: string, exception: any) => void> = null,
  690. buffer: Nullable<string | ArrayBuffer | Blob> = null,
  691. fallback: Nullable<InternalTexture> = null,
  692. format: Nullable<number> = null,
  693. forcedExtension: Nullable<string> = null): InternalTexture {
  694. var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
  695. var fromData = url.substr(0, 5) === "data:";
  696. var fromBlob = url.substr(0, 5) === "blob:";
  697. var isBase64 = fromData && url.indexOf("base64") !== -1;
  698. let texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_URL);
  699. // establish the file extension, if possible
  700. var lastDot = url.lastIndexOf('.');
  701. var extension = forcedExtension ? forcedExtension : (lastDot > -1 ? url.substring(lastDot).toLowerCase() : "");
  702. // TODO: Add support for compressed texture formats.
  703. var textureFormatInUse: Nullable<string> = null;
  704. let loader: Nullable<IInternalTextureLoader> = null;
  705. for (let availableLoader of Engine._TextureLoaders) {
  706. if (availableLoader.canLoad(extension, textureFormatInUse, fallback, isBase64, buffer ? true : false)) {
  707. loader = availableLoader;
  708. break;
  709. }
  710. }
  711. if (loader) {
  712. url = loader.transformUrl(url, textureFormatInUse);
  713. }
  714. if (scene) {
  715. scene._addPendingData(texture);
  716. }
  717. texture.url = url;
  718. texture.generateMipMaps = !noMipmap;
  719. texture.samplingMode = samplingMode;
  720. texture.invertY = invertY;
  721. if (!this.doNotHandleContextLost) {
  722. // Keep a link to the buffer only if we plan to handle context lost
  723. texture._buffer = buffer;
  724. }
  725. let onLoadObserver: Nullable<Observer<InternalTexture>> = null;
  726. if (onLoad && !fallback) {
  727. onLoadObserver = texture.onLoadedObservable.add(onLoad);
  728. }
  729. if (!fallback) { this._internalTexturesCache.push(texture); }
  730. let onInternalError = (message?: string, exception?: any) => {
  731. if (scene) {
  732. scene._removePendingData(texture);
  733. }
  734. let customFallback = false;
  735. if (loader) {
  736. const fallbackUrl = loader.getFallbackTextureUrl(url, textureFormatInUse);
  737. if (fallbackUrl) {
  738. // Add Back
  739. customFallback = true;
  740. this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
  741. }
  742. }
  743. if (!customFallback) {
  744. if (onLoadObserver) {
  745. texture.onLoadedObservable.remove(onLoadObserver);
  746. }
  747. if (Tools.UseFallbackTexture) {
  748. this.createTexture(Tools.fallbackTexture, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
  749. }
  750. }
  751. if (onError) {
  752. onError(message || "Unknown error", exception);
  753. }
  754. };
  755. // processing for non-image formats
  756. if (loader) {
  757. throw new Error("Loading textures from IInternalTextureLoader not yet implemented.");
  758. // var callback = (data: string | ArrayBuffer) => {
  759. // loader!.loadData(data as ArrayBuffer, texture, (width: number, height: number, loadMipmap: boolean, isCompressed: boolean, done: () => void) => {
  760. // this._prepareWebGLTexture(texture, scene, width, height, invertY, !loadMipmap, isCompressed, () => {
  761. // done();
  762. // return false;
  763. // },
  764. // samplingMode);
  765. // });
  766. // }
  767. // if (!buffer) {
  768. // this._loadFile(url, callback, undefined, scene ? scene.database : undefined, true, (request?: XMLHttpRequest, exception?: any) => {
  769. // onInternalError("Unable to load " + (request ? request.responseURL : url, exception));
  770. // });
  771. // } else {
  772. // callback(buffer as ArrayBuffer);
  773. // }
  774. } else {
  775. var onload = (data: string | ArrayBuffer | Blob, responseURL?: string) => {
  776. if (typeof (data) === "string") {
  777. throw new Error("Loading textures from string data not yet implemented.");
  778. }
  779. if (fromBlob && !this.doNotHandleContextLost) {
  780. // We need to store the image if we need to rebuild the texture
  781. // in case of a webgl context lost
  782. texture._buffer = data;
  783. }
  784. let webGLTexture = texture._webGLTexture;
  785. if (!webGLTexture) {
  786. // this.resetTextureCache();
  787. if (scene) {
  788. scene._removePendingData(texture);
  789. }
  790. return;
  791. }
  792. this._native.loadTexture(webGLTexture, data, !noMipmap);
  793. if (invertY) {
  794. throw new Error("Support for textures with inverted Y coordinates not yet implemented.");
  795. }
  796. //this._unpackFlipY(invertY === undefined ? true : (invertY ? true : false));
  797. texture.baseWidth = this._native.getTextureWidth(webGLTexture);
  798. texture.baseHeight = this._native.getTextureHeight(webGLTexture);
  799. texture.width = texture.baseWidth;
  800. texture.height = texture.baseHeight;
  801. texture.isReady = true;
  802. var filter = this._getSamplingFilter(samplingMode);
  803. this._native.setTextureSampling(webGLTexture, filter);
  804. // this.resetTextureCache();
  805. if (scene) {
  806. scene._removePendingData(texture);
  807. }
  808. texture.onLoadedObservable.notifyObservers(texture);
  809. texture.onLoadedObservable.clear();
  810. };
  811. if (buffer instanceof ArrayBuffer) {
  812. onload(buffer);
  813. } else if (buffer instanceof Blob) {
  814. throw new Error("Loading texture from Blob not yet implemented.");
  815. } else if (!fromData) {
  816. let onLoadFileError = (request?: XMLHttpRequest, exception?: any) => {
  817. onInternalError("Failed to retrieve " + url + ".", exception);
  818. };
  819. Tools.LoadFile(url, onload, undefined, undefined, /*useArrayBuffer*/true, onLoadFileError);
  820. } else {
  821. onload(Tools.DecodeBase64(buffer as string));
  822. }
  823. }
  824. return texture;
  825. }
  826. /**
  827. * Creates a cube texture
  828. * @param rootUrl defines the url where the files to load is located
  829. * @param scene defines the current scene
  830. * @param files defines the list of files to load (1 per face)
  831. * @param noMipmap defines a boolean indicating that no mipmaps shall be generated (false by default)
  832. * @param onLoad defines an optional callback raised when the texture is loaded
  833. * @param onError defines an optional callback raised if there is an issue to load the texture
  834. * @param format defines the format of the data
  835. * @param forcedExtension defines the extension to use to pick the right loader
  836. * @param createPolynomials if a polynomial sphere should be created for the cube texture
  837. * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
  838. * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
  839. * @param fallback defines texture to use while falling back when (compressed) texture file not found.
  840. * @returns the cube texture as an InternalTexture
  841. */
  842. public createCubeTexture(
  843. rootUrl: string,
  844. scene: Nullable<Scene>,
  845. files: Nullable<string[]>,
  846. noMipmap?: boolean,
  847. onLoad: Nullable<(data?: any) => void> = null,
  848. onError: Nullable<(message?: string, exception?: any) => void> = null,
  849. format?: number,
  850. forcedExtension: any = null,
  851. createPolynomials = false,
  852. lodScale: number = 0,
  853. lodOffset: number = 0,
  854. fallback: Nullable<InternalTexture> = null): InternalTexture
  855. {
  856. var texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
  857. texture.isCube = true;
  858. texture.url = rootUrl;
  859. texture.generateMipMaps = !noMipmap;
  860. texture._lodGenerationScale = lodScale;
  861. texture._lodGenerationOffset = lodOffset;
  862. if (!this._doNotHandleContextLost) {
  863. texture._extension = forcedExtension;
  864. texture._files = files;
  865. }
  866. var lastDot = rootUrl.lastIndexOf('.');
  867. var extension = forcedExtension ? forcedExtension : (lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "");
  868. if (extension === ".env") {
  869. const onloaddata = (data: any) => {
  870. data = data as ArrayBuffer;
  871. var info = EnvironmentTextureTools.GetEnvInfo(data)!;
  872. texture.width = info.width;
  873. texture.height = info.width;
  874. EnvironmentTextureTools.UploadEnvSpherical(texture, info);
  875. if (info.version !== 1) {
  876. throw new Error(`Unsupported babylon environment map version "${info.version}"`);
  877. }
  878. let specularInfo = info.specular as EnvironmentTextureSpecularInfoV1;
  879. if (!specularInfo) {
  880. throw new Error(`Nothing else parsed so far`);
  881. }
  882. texture._lodGenerationScale = specularInfo.lodGenerationScale;
  883. const imageData = EnvironmentTextureTools.CreateImageDataArrayBufferViews(data, info);
  884. texture.format = Engine.TEXTUREFORMAT_RGBA;
  885. texture.type = Engine.TEXTURETYPE_UNSIGNED_INT;
  886. texture.generateMipMaps = true;
  887. texture.getEngine().updateTextureSamplingMode(Texture.TRILINEAR_SAMPLINGMODE, texture);
  888. texture._isRGBD = true;
  889. texture.invertY = true;
  890. this._native.loadCubeTexture(texture._webGLTexture!, imageData, true);
  891. texture.isReady = true;
  892. if (onLoad) {
  893. onLoad();
  894. }
  895. };
  896. if (files && files.length === 6) {
  897. throw new Error(`Multi-file loading not yet supported.`);
  898. }
  899. else {
  900. let onInternalError = (request?: XMLHttpRequest, exception?: any) => {
  901. if (onError && request) {
  902. onError(request.status + " " + request.statusText, exception);
  903. }
  904. };
  905. this._loadFile(rootUrl, onloaddata, undefined, undefined, true, onInternalError);
  906. }
  907. }
  908. else {
  909. throw new Error("Cannot load cubemap: non-ENV format not supported.");
  910. }
  911. this._internalTexturesCache.push(texture);
  912. return texture;
  913. }
  914. // Returns a NativeFilter.XXXX value.
  915. private _getSamplingFilter(samplingMode: number): number {
  916. switch (samplingMode) {
  917. case Engine.TEXTURE_BILINEAR_SAMPLINGMODE:
  918. return NativeFilter.MINLINEAR_MAGLINEAR_MIPPOINT;
  919. case Engine.TEXTURE_TRILINEAR_SAMPLINGMODE:
  920. return NativeFilter.MINLINEAR_MAGLINEAR_MIPLINEAR;
  921. case Engine.TEXTURE_NEAREST_SAMPLINGMODE:
  922. return NativeFilter.MINPOINT_MAGPOINT_MIPLINEAR;
  923. case Engine.TEXTURE_NEAREST_NEAREST_MIPNEAREST:
  924. return NativeFilter.MINPOINT_MAGPOINT_MIPPOINT;
  925. case Engine.TEXTURE_NEAREST_LINEAR_MIPNEAREST:
  926. return NativeFilter.MINLINEAR_MAGPOINT_MIPPOINT;
  927. case Engine.TEXTURE_NEAREST_LINEAR_MIPLINEAR:
  928. return NativeFilter.MINLINEAR_MAGPOINT_MIPLINEAR;
  929. case Engine.TEXTURE_NEAREST_LINEAR:
  930. return NativeFilter.MINLINEAR_MAGPOINT_MIPLINEAR;
  931. case Engine.TEXTURE_NEAREST_NEAREST:
  932. return NativeFilter.MINPOINT_MAGPOINT_MIPPOINT;
  933. case Engine.TEXTURE_LINEAR_NEAREST_MIPNEAREST:
  934. return NativeFilter.MINPOINT_MAGLINEAR_MIPPOINT;
  935. case Engine.TEXTURE_LINEAR_NEAREST_MIPLINEAR:
  936. return NativeFilter.MINPOINT_MAGLINEAR_MIPLINEAR;
  937. case Engine.TEXTURE_LINEAR_LINEAR:
  938. return NativeFilter.MINLINEAR_MAGLINEAR_MIPLINEAR;
  939. case Engine.TEXTURE_LINEAR_NEAREST:
  940. return NativeFilter.MINPOINT_MAGLINEAR_MIPLINEAR;
  941. default:
  942. throw new Error("Unexpected sampling mode: " + samplingMode + ".");
  943. }
  944. }
  945. public createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture {
  946. let fullOptions = new RenderTargetCreationOptions();
  947. if (options !== undefined && typeof options === "object") {
  948. fullOptions.generateMipMaps = options.generateMipMaps;
  949. fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
  950. fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
  951. fullOptions.type = options.type === undefined ? Engine.TEXTURETYPE_UNSIGNED_INT : options.type;
  952. fullOptions.samplingMode = options.samplingMode === undefined ? Texture.TRILINEAR_SAMPLINGMODE : options.samplingMode;
  953. } else {
  954. fullOptions.generateMipMaps = <boolean>options;
  955. fullOptions.generateDepthBuffer = true;
  956. fullOptions.generateStencilBuffer = false;
  957. fullOptions.type = Engine.TEXTURETYPE_UNSIGNED_INT;
  958. fullOptions.samplingMode = Texture.TRILINEAR_SAMPLINGMODE;
  959. }
  960. var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
  961. var width = size.width || size;
  962. var height = size.height || size;
  963. texture._depthStencilBuffer = {};
  964. texture._framebuffer = {};
  965. texture.baseWidth = width;
  966. texture.baseHeight = height;
  967. texture.width = width;
  968. texture.height = height;
  969. texture.isReady = true;
  970. texture.samples = 1;
  971. texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
  972. texture.samplingMode = fullOptions.samplingMode;
  973. texture.type = fullOptions.type;
  974. texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
  975. texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
  976. this._internalTexturesCache.push(texture);
  977. return texture;
  978. }
  979. public updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void {
  980. if (texture._webGLTexture) {
  981. var filter = this._getSamplingFilter(samplingMode);
  982. this._native.setTextureSampling(texture._webGLTexture, filter);
  983. }
  984. texture.samplingMode = samplingMode;
  985. }
  986. public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void {
  987. throw new Error("bindFramebuffer not yet implemented.");
  988. }
  989. public unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps = false, onBeforeUnbind?: () => void): void {
  990. throw new Error("unBindFramebuffer not yet implemented.");
  991. }
  992. public createDynamicVertexBuffer(data: DataArray): WebGLBuffer {
  993. throw new Error("createDynamicVertexBuffer not yet implemented.");
  994. }
  995. public updateDynamicIndexBuffer(indexBuffer: WebGLBuffer, indices: IndicesArray, offset: number = 0): void {
  996. throw new Error("updateDynamicIndexBuffer not yet implemented.");
  997. }
  998. /**
  999. * Updates a dynamic vertex buffer.
  1000. * @param vertexBuffer the vertex buffer to update
  1001. * @param data the data used to update the vertex buffer
  1002. * @param byteOffset the byte offset of the data (optional)
  1003. * @param byteLength the byte length of the data (optional)
  1004. */
  1005. public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
  1006. throw new Error("updateDynamicVertexBuffer not yet implemented.");
  1007. }
  1008. // TODO: Refactor to share more logic with base Engine implementation.
  1009. protected _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false, depthStencilTexture = false): boolean {
  1010. let uniform = this._boundUniforms[channel];
  1011. if (!uniform) {
  1012. return false;
  1013. }
  1014. // Not ready?
  1015. if (!texture) {
  1016. if (this._boundTexturesCache[channel] != null) {
  1017. this._activeChannel = channel;
  1018. this._native.setTexture(uniform, null);
  1019. }
  1020. return false;
  1021. }
  1022. // Video
  1023. if ((<VideoTexture>texture).video) {
  1024. this._activeChannel = channel;
  1025. (<VideoTexture>texture).update();
  1026. } else if (texture.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) { // Delay loading
  1027. texture.delayLoad();
  1028. return false;
  1029. }
  1030. let internalTexture: InternalTexture;
  1031. if (depthStencilTexture) {
  1032. internalTexture = (<RenderTargetTexture>texture).depthStencilTexture!;
  1033. } else if (texture.isReady()) {
  1034. internalTexture = <InternalTexture>texture.getInternalTexture();
  1035. } else if (texture.isCube) {
  1036. internalTexture = this.emptyCubeTexture;
  1037. } else if (texture.is3D) {
  1038. internalTexture = this.emptyTexture3D;
  1039. } else {
  1040. internalTexture = this.emptyTexture;
  1041. }
  1042. this._activeChannel = channel;
  1043. if (!internalTexture ||
  1044. !internalTexture._webGLTexture) {
  1045. return false;
  1046. }
  1047. this._native.setTextureWrapMode(
  1048. internalTexture._webGLTexture,
  1049. this._getAddressMode(texture.wrapU),
  1050. this._getAddressMode(texture.wrapV),
  1051. this._getAddressMode(texture.wrapR));
  1052. this._updateAnisotropicLevel(texture);
  1053. this._native.setTexture(uniform, internalTexture._webGLTexture);
  1054. return true;
  1055. }
  1056. // TODO: Share more of this logic with the base implementation.
  1057. // TODO: Rename to match naming in base implementation once refactoring allows different parameters.
  1058. private _updateAnisotropicLevel(texture: BaseTexture) {
  1059. var internalTexture = texture.getInternalTexture();
  1060. var value = texture.anisotropicFilteringLevel;
  1061. if (!internalTexture || !internalTexture._webGLTexture) {
  1062. return;
  1063. }
  1064. if (internalTexture._cachedAnisotropicFilteringLevel !== value) {
  1065. this._native.setTextureAnisotropicLevel(internalTexture._webGLTexture, value);
  1066. internalTexture._cachedAnisotropicFilteringLevel = value;
  1067. }
  1068. }
  1069. // Returns a NativeAddressMode.XXX value.
  1070. private _getAddressMode(wrapMode: number): number {
  1071. switch (wrapMode) {
  1072. case Engine.TEXTURE_WRAP_ADDRESSMODE:
  1073. return NativeAddressMode.WRAP;
  1074. case Engine.TEXTURE_CLAMP_ADDRESSMODE:
  1075. return NativeAddressMode.CLAMP;
  1076. case Engine.TEXTURE_MIRROR_ADDRESSMODE:
  1077. return NativeAddressMode.MIRROR;
  1078. default:
  1079. throw new Error("Unexpected wrap mode: " + wrapMode + ".");
  1080. }
  1081. }
  1082. /** @hidden */
  1083. public _bindTexture(channel: number, texture: InternalTexture): void {
  1084. throw new Error("_bindTexture not implemented.");
  1085. }
  1086. protected _deleteBuffer(buffer: WebGLBufferInfo): void {
  1087. if (buffer.nativeIndexBuffer) {
  1088. this._native.deleteIndexBuffer(buffer.nativeIndexBuffer);
  1089. delete buffer.nativeIndexBuffer;
  1090. }
  1091. if (buffer.nativeVertexBuffer) {
  1092. this._native.deleteVertexBuffer(buffer.nativeVertexBuffer);
  1093. delete buffer.nativeVertexBuffer;
  1094. }
  1095. // if (buffer._vertexBuffers) {
  1096. // for (const vertexBuffer of buffer._vertexBuffers) {
  1097. // const nativeBuffer = vertexBuffer._nativeBuffer;
  1098. // if (nativeBuffer) {
  1099. // delete vertexBuffer._nativeBuffer;
  1100. // }
  1101. // }
  1102. // }
  1103. }
  1104. public releaseEffects() {
  1105. // TODO: Implement.
  1106. }
  1107. /** @hidden */
  1108. public _uploadCompressedDataToTextureDirectly(texture: InternalTexture, internalFormat: number, width: number, height: number, data: ArrayBufferView, faceIndex: number = 0, lod: number = 0) {
  1109. throw new Error("_uploadCompressedDataToTextureDirectly not implemented.");
  1110. }
  1111. /** @hidden */
  1112. public _uploadDataToTextureDirectly(texture: InternalTexture, imageData: ArrayBufferView, faceIndex: number = 0, lod: number = 0): void {
  1113. throw new Error("_uploadDataToTextureDirectly not implemented.");
  1114. }
  1115. /** @hidden */
  1116. public _uploadArrayBufferViewToTexture(texture: InternalTexture, imageData: ArrayBufferView, faceIndex: number = 0, lod: number = 0): void {
  1117. throw new Error("_uploadArrayBufferViewToTexture not implemented.");
  1118. }
  1119. /** @hidden */
  1120. public _uploadImageToTexture(texture: InternalTexture, image: HTMLImageElement, faceIndex: number = 0, lod: number = 0) {
  1121. throw new Error("_uploadArrayBufferViewToTexture not implemented.");
  1122. }
  1123. }