nativeEngine.ts 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352
  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: ArrayBufferView, byteStride: number, infos: Array<{ location: number, numElements: number, type: number, normalized: boolean, byteOffset: number }>): 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. // Map the vertex buffers that point to the same underlying buffer.
  260. const map: { [id: number]: { buffer: WebGLBufferInfo, byteStride: number, infos: Array<{ location: number, numElements: number, type: number, normalized: boolean, byteOffset: number }> } } = {};
  261. const attributes = effect.getAttributesNames();
  262. for (let index = 0; index < attributes.length; index++) {
  263. const location = effect.getAttributeLocation(index);
  264. if (location >= 0) {
  265. const kind = attributes[index];
  266. const vertexBuffer = vertexBuffers[kind];
  267. if (vertexBuffer) {
  268. const buffer = vertexBuffer.getBuffer() as WebGLBufferInfo;
  269. if (buffer) {
  270. let entry = map[buffer.id];
  271. if (!entry) {
  272. entry = { buffer: buffer, byteStride: vertexBuffer.byteStride, infos: [] };
  273. map[buffer.id] = entry;
  274. }
  275. // TODO: check if byteStride matches for all vertex buffers??
  276. entry.infos.push({
  277. location: location,
  278. numElements: vertexBuffer.getSize(),
  279. type: vertexBuffer.type,
  280. normalized: vertexBuffer.normalized,
  281. byteOffset: vertexBuffer.byteOffset
  282. });
  283. }
  284. }
  285. }
  286. }
  287. // Record vertex buffer for each unique buffer.
  288. for (const id in map) {
  289. const entry = map[id];
  290. const buffer = entry.buffer;
  291. if (!buffer.nativeVertexBuffer) {
  292. // TODO: handle non-normalized non-float data (shader always expects float data)
  293. const data = ArrayBuffer.isView(buffer.data) ? buffer.data : new Float32Array(buffer.data);
  294. buffer.nativeVertexBuffer = this._native.createVertexBuffer(data, entry.byteStride, entry.infos);
  295. }
  296. this._native.recordVertexBuffer(vertexArray, buffer.nativeVertexBuffer);
  297. }
  298. return vertexArray;
  299. }
  300. public bindVertexArrayObject(vertexArray: WebGLVertexArrayObject): void {
  301. this._native.bindVertexArray(vertexArray);
  302. }
  303. public releaseVertexArrayObject(vertexArray: WebGLVertexArrayObject) {
  304. this._native.deleteVertexArray(vertexArray);
  305. }
  306. public getAttributes(shaderProgram: WebGLProgramInfo, attributesNames: string[]): number[] {
  307. return this._native.getAttributes(shaderProgram.nativeProgram, attributesNames);
  308. }
  309. /**
  310. * Draw a list of indexed primitives
  311. * @param fillMode defines the primitive to use
  312. * @param indexStart defines the starting index
  313. * @param indexCount defines the number of index to draw
  314. * @param instancesCount defines the number of instances to draw (if instanciation is enabled)
  315. */
  316. public drawElementsType(fillMode: number, indexStart: number, indexCount: number, instancesCount?: number): void {
  317. // Apply states
  318. this._drawCalls.addCount(1, false);
  319. // TODO: Make this implementation more robust like core Engine version.
  320. // Render
  321. //var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
  322. //var mult = this._uintIndicesCurrentlySet ? 4 : 2;
  323. // if (instancesCount) {
  324. // this._gl.drawElementsInstanced(drawMode, indexCount, indexFormat, indexStart * mult, instancesCount);
  325. // } else {
  326. this._native.drawIndexed(fillMode, indexStart, indexCount);
  327. // }
  328. }
  329. /**
  330. * Draw a list of unindexed primitives
  331. * @param fillMode defines the primitive to use
  332. * @param verticesStart defines the index of first vertex to draw
  333. * @param verticesCount defines the count of vertices to draw
  334. * @param instancesCount defines the number of instances to draw (if instanciation is enabled)
  335. */
  336. public drawArraysType(fillMode: number, verticesStart: number, verticesCount: number, instancesCount?: number): void {
  337. // Apply states
  338. this._drawCalls.addCount(1, false);
  339. // TODO: Make this implementation more robust like core Engine version.
  340. // if (instancesCount) {
  341. // this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
  342. // } else {
  343. this._native.draw(fillMode, verticesStart, verticesCount);
  344. // }
  345. }
  346. /**
  347. * Directly creates a webGL program
  348. * @param vertexCode defines the vertex shader code to use
  349. * @param fragmentCode defines the fragment shader code to use
  350. * @param context defines the webGL context to use (if not set, the current one will be used)
  351. * @param transformFeedbackVaryings defines the list of transform feedback varyings to use
  352. * @returns the new webGL program
  353. */
  354. public createRawShaderProgram(vertexCode: string, fragmentCode: string, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgramInfo {
  355. return {
  356. nativeProgram: this._native.createProgram(vertexCode, fragmentCode),
  357. isParallelCompiled: false
  358. };
  359. }
  360. /**
  361. * Creates a webGL program
  362. * @param vertexCode defines the vertex shader code to use
  363. * @param fragmentCode defines the fragment shader code to use
  364. * @param defines defines the string containing the defines to use to compile the shaders
  365. * @param context defines the webGL context to use (if not set, the current one will be used)
  366. * @param transformFeedbackVaryings defines the list of transform feedback varyings to use
  367. * @returns the new webGL program
  368. */
  369. public createShaderProgram(vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgramInfo {
  370. this.onBeforeShaderCompilationObservable.notifyObservers(this);
  371. // TODO: Share this shader version logic with base class.
  372. var shaderVersion = (this._webGLVersion > 1) ? "#version 300 es\n#define WEBGL2 \n" : "";
  373. var vertexCodeConcat = Engine._concatenateShader(vertexCode, defines, shaderVersion);
  374. var fragmentCodeConcat = Engine._concatenateShader(fragmentCode, defines, shaderVersion);
  375. var program = this.createRawShaderProgram(vertexCodeConcat, fragmentCodeConcat);
  376. program.transformFeedback = null;
  377. program.__SPECTOR_rebuildProgram = null;
  378. this.onAfterShaderCompilationObservable.notifyObservers(this);
  379. return program;
  380. }
  381. protected setProgram(program: WebGLProgramInfo): void {
  382. if (this._currentProgram !== program) {
  383. this._native.setProgram(program.nativeProgram);
  384. this._currentProgram = program;
  385. }
  386. }
  387. public getUniforms(shaderProgram: WebGLProgramInfo, uniformsNames: string[]): WebGLUniformLocation[] {
  388. return this._native.getUniforms(shaderProgram.nativeProgram, uniformsNames);
  389. }
  390. public setMatrix(uniform: WebGLUniformLocation, matrix: Matrix): void {
  391. if (!uniform) {
  392. return;
  393. }
  394. this._native.setMatrix(uniform, matrix.toArray() as Float32Array);
  395. }
  396. public getRenderWidth(useScreen = false): number {
  397. if (!useScreen && this._currentRenderTarget) {
  398. return this._currentRenderTarget.width;
  399. }
  400. return this._native.getRenderWidth();
  401. }
  402. public getRenderHeight(useScreen = false): number {
  403. if (!useScreen && this._currentRenderTarget) {
  404. return this._currentRenderTarget.height;
  405. }
  406. return this._native.getRenderHeight();
  407. }
  408. public setViewport(viewport: Viewport, requiredWidth?: number, requiredHeight?: number): void {
  409. // TODO: Implement.
  410. this._cachedViewport = viewport;
  411. }
  412. public setState(culling: boolean, zOffset: number = 0, force?: boolean, reverseSide = false): void {
  413. this._native.setState(culling, zOffset, reverseSide);
  414. }
  415. /**
  416. * Set the z offset to apply to current rendering
  417. * @param value defines the offset to apply
  418. */
  419. public setZOffset(value: number): void {
  420. this._native.setZOffset(value);
  421. }
  422. /**
  423. * Gets the current value of the zOffset
  424. * @returns the current zOffset state
  425. */
  426. public getZOffset(): number {
  427. return this._native.getZOffset();
  428. }
  429. /**
  430. * Enable or disable depth buffering
  431. * @param enable defines the state to set
  432. */
  433. public setDepthBuffer(enable: boolean): void {
  434. this._native.setDepthTest(enable);
  435. }
  436. /**
  437. * Gets a boolean indicating if depth writing is enabled
  438. * @returns the current depth writing state
  439. */
  440. public getDepthWrite(): boolean {
  441. return this._native.getDepthWrite();
  442. }
  443. /**
  444. * Enable or disable depth writing
  445. * @param enable defines the state to set
  446. */
  447. public setDepthWrite(enable: boolean): void {
  448. this._native.setDepthWrite(enable);
  449. }
  450. /**
  451. * Enable or disable color writing
  452. * @param enable defines the state to set
  453. */
  454. public setColorWrite(enable: boolean): void {
  455. this._native.setColorWrite(enable);
  456. this._colorWrite = enable;
  457. }
  458. /**
  459. * Gets a boolean indicating if color writing is enabled
  460. * @returns the current color writing state
  461. */
  462. public getColorWrite(): boolean {
  463. return this._colorWrite;
  464. }
  465. /**
  466. * Sets alpha constants used by some alpha blending modes
  467. * @param r defines the red component
  468. * @param g defines the green component
  469. * @param b defines the blue component
  470. * @param a defines the alpha component
  471. */
  472. public setAlphaConstants(r: number, g: number, b: number, a: number) {
  473. throw new Error("Setting alpha blend constant color not yet implemented.");
  474. }
  475. /**
  476. * Sets the current alpha mode
  477. * @param mode defines the mode to use (one of the BABYLON.Engine.ALPHA_XXX)
  478. * @param noDepthWriteChange defines if depth writing state should remains unchanged (false by default)
  479. * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
  480. */
  481. public setAlphaMode(mode: number, noDepthWriteChange: boolean = false): void {
  482. if (this._alphaMode === mode) {
  483. return;
  484. }
  485. this._native.setBlendMode(this._getBlendMode(mode));
  486. if (!noDepthWriteChange) {
  487. this.setDepthWrite(mode === Engine.ALPHA_DISABLE);
  488. }
  489. this._alphaMode = mode;
  490. }
  491. // Returns a NativeBlendMode.XXXX value.
  492. // Note: Many blend modes intentionally not implemented. If more are needed, they should be added.
  493. private _getBlendMode(mode: number): number {
  494. switch (mode) {
  495. case Engine.ALPHA_DISABLE:
  496. return NativeBlendMode.REPLACE;
  497. case Engine.ALPHA_PREMULTIPLIED_PORTERDUFF:
  498. return NativeBlendMode.OVER;
  499. case Engine.ALPHA_COMBINE:
  500. return NativeBlendMode.COMBINE;
  501. case Engine.ALPHA_SCREENMODE:
  502. return NativeBlendMode.SCREEN;
  503. default:
  504. throw new Error("Unexpected alpha mode: " + mode + ".");
  505. }
  506. }
  507. /**
  508. * Gets the current alpha mode
  509. * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
  510. * @returns the current alpha mode
  511. */
  512. public getAlphaMode(): number {
  513. return this._alphaMode;
  514. }
  515. public setIntArray(uniform: WebGLUniformLocation, array: Int32Array): void {
  516. if (!uniform) {
  517. return;
  518. }
  519. this._native.setIntArray(uniform, array);
  520. }
  521. public setIntArray2(uniform: WebGLUniformLocation, array: Int32Array): void {
  522. if (!uniform) {
  523. return;
  524. }
  525. this._native.setIntArray2(uniform, array);
  526. }
  527. public setIntArray3(uniform: WebGLUniformLocation, array: Int32Array): void {
  528. if (!uniform) {
  529. return;
  530. }
  531. this._native.setIntArray3(uniform, array);
  532. }
  533. public setIntArray4(uniform: WebGLUniformLocation, array: Int32Array): void {
  534. if (!uniform) {
  535. return;
  536. }
  537. this._native.setIntArray4(uniform, array);
  538. }
  539. public setFloatArray(uniform: WebGLUniformLocation, array: Float32Array): void {
  540. if (!uniform) {
  541. return;
  542. }
  543. this._native.setFloatArray(uniform, array);
  544. }
  545. public setFloatArray2(uniform: WebGLUniformLocation, array: Float32Array): void {
  546. if (!uniform) {
  547. return;
  548. }
  549. this._native.setFloatArray2(uniform, array);
  550. }
  551. public setFloatArray3(uniform: WebGLUniformLocation, array: Float32Array): void {
  552. if (!uniform) {
  553. return;
  554. }
  555. this._native.setFloatArray3(uniform, array);
  556. }
  557. public setFloatArray4(uniform: WebGLUniformLocation, array: Float32Array): void {
  558. if (!uniform) {
  559. return;
  560. }
  561. this._native.setFloatArray4(uniform, array);
  562. }
  563. public setArray(uniform: WebGLUniformLocation, array: number[]): void {
  564. if (!uniform) {
  565. return;
  566. }
  567. this._native.setFloatArray(uniform, array);
  568. }
  569. public setArray2(uniform: WebGLUniformLocation, array: number[]): void {
  570. if (!uniform) {
  571. return;
  572. }
  573. this._native.setFloatArray2(uniform, array);
  574. }
  575. public setArray3(uniform: WebGLUniformLocation, array: number[]): void {
  576. if (!uniform) {
  577. return;
  578. }
  579. this._native.setFloatArray3(uniform, array);
  580. }
  581. public setArray4(uniform: WebGLUniformLocation, array: number[]): void {
  582. if (!uniform) {
  583. return;
  584. }
  585. this._native.setFloatArray4(uniform, array);
  586. }
  587. public setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): void {
  588. if (!uniform) {
  589. return;
  590. }
  591. this._native.setMatrices(uniform, matrices);
  592. }
  593. public setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): void {
  594. if (!uniform) {
  595. return;
  596. }
  597. this._native.setMatrix3x3(uniform, matrix);
  598. }
  599. public setMatrix2x2(uniform: WebGLUniformLocation, matrix: Float32Array): void {
  600. if (!uniform) {
  601. return;
  602. }
  603. this._native.setMatrix2x2(uniform, matrix);
  604. }
  605. public setFloat(uniform: WebGLUniformLocation, value: number): void {
  606. if (!uniform) {
  607. return;
  608. }
  609. this._native.setFloat(uniform, value);
  610. }
  611. public setFloat2(uniform: WebGLUniformLocation, x: number, y: number): void {
  612. if (!uniform) {
  613. return;
  614. }
  615. this._native.setFloat2(uniform, x, y);
  616. }
  617. public setFloat3(uniform: WebGLUniformLocation, x: number, y: number, z: number): void {
  618. if (!uniform) {
  619. return;
  620. }
  621. this._native.setFloat3(uniform, x, y, z);
  622. }
  623. public setBool(uniform: WebGLUniformLocation, bool: number): void {
  624. if (!uniform) {
  625. return;
  626. }
  627. this._native.setBool(uniform, bool);
  628. }
  629. public setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void {
  630. if (!uniform) {
  631. return;
  632. }
  633. this._native.setFloat4(uniform, x, y, z, w);
  634. }
  635. public setColor3(uniform: WebGLUniformLocation, color3: Color3): void {
  636. if (!uniform) {
  637. return;
  638. }
  639. this._native.setFloat3(uniform, color3.r, color3.g, color3.b);
  640. }
  641. public setColor4(uniform: WebGLUniformLocation, color3: Color3, alpha: number): void {
  642. if (!uniform) {
  643. return;
  644. }
  645. this._native.setFloat4(uniform, color3.r, color3.g, color3.b, alpha);
  646. }
  647. public wipeCaches(bruteForce?: boolean): void {
  648. if (this.preventCacheWipeBetweenFrames) {
  649. return;
  650. }
  651. this.resetTextureCache();
  652. this._currentEffect = null;
  653. if (bruteForce) {
  654. this._currentProgram = null;
  655. this._stencilState.reset();
  656. this._depthCullingState.reset();
  657. this._alphaState.reset();
  658. }
  659. this._cachedVertexBuffers = null;
  660. this._cachedIndexBuffer = null;
  661. this._cachedEffectForVertexBuffers = null;
  662. }
  663. public _createTexture(): WebGLTexture {
  664. return this._native.createTexture();
  665. }
  666. protected _deleteTexture(texture: Nullable<WebGLTexture>): void {
  667. this._native.deleteTexture(texture);
  668. }
  669. // TODO: Refactor to share more logic with babylon.engine.ts version.
  670. /**
  671. * Usually called from BABYLON.Texture.ts.
  672. * Passed information to create a WebGLTexture
  673. * @param urlArg defines a value which contains one of the following:
  674. * * A conventional http URL, e.g. 'http://...' or 'file://...'
  675. * * A base64 string of in-line texture data, e.g. 'data:image/jpg;base64,/...'
  676. * * An indicator that data being passed using the buffer parameter, e.g. 'data:mytexture.jpg'
  677. * @param noMipmap defines a boolean indicating that no mipmaps shall be generated. Ignored for compressed textures. They must be in the file
  678. * @param invertY when true, image is flipped when loaded. You probably want true. Ignored for compressed textures. Must be flipped in the file
  679. * @param scene needed for loading to the correct scene
  680. * @param samplingMode mode with should be used sample / access the texture (Default: BABYLON.Texture.TRILINEAR_SAMPLINGMODE)
  681. * @param onLoad optional callback to be called upon successful completion
  682. * @param onError optional callback to be called upon failure
  683. * @param buffer a source of a file previously fetched as either a base64 string, an ArrayBuffer (compressed or image format), or a Blob
  684. * @param fallback an internal argument in case the function must be called again, due to etc1 not having alpha capabilities
  685. * @param format internal format. Default: RGB when extension is '.jpg' else RGBA. Ignored for compressed textures
  686. * @param forcedExtension defines the extension to use to pick the right loader
  687. * @returns a InternalTexture for assignment back into BABYLON.Texture
  688. */
  689. public createTexture(
  690. urlArg: Nullable<string>,
  691. noMipmap: boolean,
  692. invertY: boolean,
  693. scene: Nullable<Scene>,
  694. samplingMode: number = Engine.TEXTURE_TRILINEAR_SAMPLINGMODE,
  695. onLoad: Nullable<() => void> = null,
  696. onError: Nullable<(message: string, exception: any) => void> = null,
  697. buffer: Nullable<string | ArrayBuffer | Blob> = null,
  698. fallback: Nullable<InternalTexture> = null,
  699. format: Nullable<number> = null,
  700. forcedExtension: Nullable<string> = null): InternalTexture {
  701. var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
  702. var fromData = url.substr(0, 5) === "data:";
  703. var fromBlob = url.substr(0, 5) === "blob:";
  704. var isBase64 = fromData && url.indexOf("base64") !== -1;
  705. let texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_URL);
  706. // establish the file extension, if possible
  707. var lastDot = url.lastIndexOf('.');
  708. var extension = forcedExtension ? forcedExtension : (lastDot > -1 ? url.substring(lastDot).toLowerCase() : "");
  709. // TODO: Add support for compressed texture formats.
  710. var textureFormatInUse: Nullable<string> = null;
  711. let loader: Nullable<IInternalTextureLoader> = null;
  712. for (let availableLoader of Engine._TextureLoaders) {
  713. if (availableLoader.canLoad(extension, textureFormatInUse, fallback, isBase64, buffer ? true : false)) {
  714. loader = availableLoader;
  715. break;
  716. }
  717. }
  718. if (loader) {
  719. url = loader.transformUrl(url, textureFormatInUse);
  720. }
  721. if (scene) {
  722. scene._addPendingData(texture);
  723. }
  724. texture.url = url;
  725. texture.generateMipMaps = !noMipmap;
  726. texture.samplingMode = samplingMode;
  727. texture.invertY = invertY;
  728. if (!this.doNotHandleContextLost) {
  729. // Keep a link to the buffer only if we plan to handle context lost
  730. texture._buffer = buffer;
  731. }
  732. let onLoadObserver: Nullable<Observer<InternalTexture>> = null;
  733. if (onLoad && !fallback) {
  734. onLoadObserver = texture.onLoadedObservable.add(onLoad);
  735. }
  736. if (!fallback) { this._internalTexturesCache.push(texture); }
  737. let onInternalError = (message?: string, exception?: any) => {
  738. if (scene) {
  739. scene._removePendingData(texture);
  740. }
  741. let customFallback = false;
  742. if (loader) {
  743. const fallbackUrl = loader.getFallbackTextureUrl(url, textureFormatInUse);
  744. if (fallbackUrl) {
  745. // Add Back
  746. customFallback = true;
  747. this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
  748. }
  749. }
  750. if (!customFallback) {
  751. if (onLoadObserver) {
  752. texture.onLoadedObservable.remove(onLoadObserver);
  753. }
  754. if (Tools.UseFallbackTexture) {
  755. this.createTexture(Tools.fallbackTexture, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
  756. }
  757. }
  758. if (onError) {
  759. onError(message || "Unknown error", exception);
  760. }
  761. };
  762. // processing for non-image formats
  763. if (loader) {
  764. throw new Error("Loading textures from IInternalTextureLoader not yet implemented.");
  765. // var callback = (data: string | ArrayBuffer) => {
  766. // loader!.loadData(data as ArrayBuffer, texture, (width: number, height: number, loadMipmap: boolean, isCompressed: boolean, done: () => void) => {
  767. // this._prepareWebGLTexture(texture, scene, width, height, invertY, !loadMipmap, isCompressed, () => {
  768. // done();
  769. // return false;
  770. // },
  771. // samplingMode);
  772. // });
  773. // }
  774. // if (!buffer) {
  775. // this._loadFile(url, callback, undefined, scene ? scene.database : undefined, true, (request?: XMLHttpRequest, exception?: any) => {
  776. // onInternalError("Unable to load " + (request ? request.responseURL : url, exception));
  777. // });
  778. // } else {
  779. // callback(buffer as ArrayBuffer);
  780. // }
  781. } else {
  782. var onload = (data: string | ArrayBuffer | Blob, responseURL?: string) => {
  783. if (typeof (data) === "string") {
  784. throw new Error("Loading textures from string data not yet implemented.");
  785. }
  786. if (fromBlob && !this.doNotHandleContextLost) {
  787. // We need to store the image if we need to rebuild the texture
  788. // in case of a webgl context lost
  789. texture._buffer = data;
  790. }
  791. let webGLTexture = texture._webGLTexture;
  792. if (!webGLTexture) {
  793. // this.resetTextureCache();
  794. if (scene) {
  795. scene._removePendingData(texture);
  796. }
  797. return;
  798. }
  799. this._native.loadTexture(webGLTexture, data, !noMipmap);
  800. if (invertY) {
  801. throw new Error("Support for textures with inverted Y coordinates not yet implemented.");
  802. }
  803. //this._unpackFlipY(invertY === undefined ? true : (invertY ? true : false));
  804. texture.baseWidth = this._native.getTextureWidth(webGLTexture);
  805. texture.baseHeight = this._native.getTextureHeight(webGLTexture);
  806. texture.width = texture.baseWidth;
  807. texture.height = texture.baseHeight;
  808. texture.isReady = true;
  809. var filter = this._getSamplingFilter(samplingMode);
  810. this._native.setTextureSampling(webGLTexture, filter);
  811. // this.resetTextureCache();
  812. if (scene) {
  813. scene._removePendingData(texture);
  814. }
  815. texture.onLoadedObservable.notifyObservers(texture);
  816. texture.onLoadedObservable.clear();
  817. };
  818. if (buffer instanceof ArrayBuffer) {
  819. onload(buffer);
  820. } else if (buffer instanceof Blob) {
  821. throw new Error("Loading texture from Blob not yet implemented.");
  822. } else if (!fromData) {
  823. let onLoadFileError = (request?: XMLHttpRequest, exception?: any) => {
  824. onInternalError("Failed to retrieve " + url + ".", exception);
  825. };
  826. Tools.LoadFile(url, onload, undefined, undefined, /*useArrayBuffer*/true, onLoadFileError);
  827. } else {
  828. onload(Tools.DecodeBase64(buffer as string));
  829. }
  830. }
  831. return texture;
  832. }
  833. /**
  834. * Creates a cube texture
  835. * @param rootUrl defines the url where the files to load is located
  836. * @param scene defines the current scene
  837. * @param files defines the list of files to load (1 per face)
  838. * @param noMipmap defines a boolean indicating that no mipmaps shall be generated (false by default)
  839. * @param onLoad defines an optional callback raised when the texture is loaded
  840. * @param onError defines an optional callback raised if there is an issue to load the texture
  841. * @param format defines the format of the data
  842. * @param forcedExtension defines the extension to use to pick the right loader
  843. * @param createPolynomials if a polynomial sphere should be created for the cube texture
  844. * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
  845. * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
  846. * @param fallback defines texture to use while falling back when (compressed) texture file not found.
  847. * @returns the cube texture as an InternalTexture
  848. */
  849. public createCubeTexture(
  850. rootUrl: string,
  851. scene: Nullable<Scene>,
  852. files: Nullable<string[]>,
  853. noMipmap?: boolean,
  854. onLoad: Nullable<(data?: any) => void> = null,
  855. onError: Nullable<(message?: string, exception?: any) => void> = null,
  856. format?: number,
  857. forcedExtension: any = null,
  858. createPolynomials = false,
  859. lodScale: number = 0,
  860. lodOffset: number = 0,
  861. fallback: Nullable<InternalTexture> = null): InternalTexture
  862. {
  863. var texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
  864. texture.isCube = true;
  865. texture.url = rootUrl;
  866. texture.generateMipMaps = !noMipmap;
  867. texture._lodGenerationScale = lodScale;
  868. texture._lodGenerationOffset = lodOffset;
  869. if (!this._doNotHandleContextLost) {
  870. texture._extension = forcedExtension;
  871. texture._files = files;
  872. }
  873. var lastDot = rootUrl.lastIndexOf('.');
  874. var extension = forcedExtension ? forcedExtension : (lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "");
  875. if (extension === ".env") {
  876. const onloaddata = (data: any) => {
  877. data = data as ArrayBuffer;
  878. var info = EnvironmentTextureTools.GetEnvInfo(data)!;
  879. texture.width = info.width;
  880. texture.height = info.width;
  881. EnvironmentTextureTools.UploadEnvSpherical(texture, info);
  882. if (info.version !== 1) {
  883. throw new Error(`Unsupported babylon environment map version "${info.version}"`);
  884. }
  885. let specularInfo = info.specular as EnvironmentTextureSpecularInfoV1;
  886. if (!specularInfo) {
  887. throw new Error(`Nothing else parsed so far`);
  888. }
  889. texture._lodGenerationScale = specularInfo.lodGenerationScale;
  890. const imageData = EnvironmentTextureTools.CreateImageDataArrayBufferViews(data, info);
  891. texture.format = Engine.TEXTUREFORMAT_RGBA;
  892. texture.type = Engine.TEXTURETYPE_UNSIGNED_INT;
  893. texture.generateMipMaps = true;
  894. texture.getEngine().updateTextureSamplingMode(Texture.TRILINEAR_SAMPLINGMODE, texture);
  895. texture._isRGBD = true;
  896. texture.invertY = true;
  897. this._native.loadCubeTexture(texture._webGLTexture!, imageData, true);
  898. texture.isReady = true;
  899. if (onLoad) {
  900. onLoad();
  901. }
  902. };
  903. if (files && files.length === 6) {
  904. throw new Error(`Multi-file loading not yet supported.`);
  905. }
  906. else {
  907. let onInternalError = (request?: XMLHttpRequest, exception?: any) => {
  908. if (onError && request) {
  909. onError(request.status + " " + request.statusText, exception);
  910. }
  911. };
  912. this._loadFile(rootUrl, onloaddata, undefined, undefined, true, onInternalError);
  913. }
  914. }
  915. else {
  916. throw new Error("Cannot load cubemap: non-ENV format not supported.");
  917. }
  918. this._internalTexturesCache.push(texture);
  919. return texture;
  920. }
  921. // Returns a NativeFilter.XXXX value.
  922. private _getSamplingFilter(samplingMode: number): number {
  923. switch (samplingMode) {
  924. case Engine.TEXTURE_BILINEAR_SAMPLINGMODE:
  925. return NativeFilter.MINLINEAR_MAGLINEAR_MIPPOINT;
  926. case Engine.TEXTURE_TRILINEAR_SAMPLINGMODE:
  927. return NativeFilter.MINLINEAR_MAGLINEAR_MIPLINEAR;
  928. case Engine.TEXTURE_NEAREST_SAMPLINGMODE:
  929. return NativeFilter.MINPOINT_MAGPOINT_MIPLINEAR;
  930. case Engine.TEXTURE_NEAREST_NEAREST_MIPNEAREST:
  931. return NativeFilter.MINPOINT_MAGPOINT_MIPPOINT;
  932. case Engine.TEXTURE_NEAREST_LINEAR_MIPNEAREST:
  933. return NativeFilter.MINLINEAR_MAGPOINT_MIPPOINT;
  934. case Engine.TEXTURE_NEAREST_LINEAR_MIPLINEAR:
  935. return NativeFilter.MINLINEAR_MAGPOINT_MIPLINEAR;
  936. case Engine.TEXTURE_NEAREST_LINEAR:
  937. return NativeFilter.MINLINEAR_MAGPOINT_MIPLINEAR;
  938. case Engine.TEXTURE_NEAREST_NEAREST:
  939. return NativeFilter.MINPOINT_MAGPOINT_MIPPOINT;
  940. case Engine.TEXTURE_LINEAR_NEAREST_MIPNEAREST:
  941. return NativeFilter.MINPOINT_MAGLINEAR_MIPPOINT;
  942. case Engine.TEXTURE_LINEAR_NEAREST_MIPLINEAR:
  943. return NativeFilter.MINPOINT_MAGLINEAR_MIPLINEAR;
  944. case Engine.TEXTURE_LINEAR_LINEAR:
  945. return NativeFilter.MINLINEAR_MAGLINEAR_MIPLINEAR;
  946. case Engine.TEXTURE_LINEAR_NEAREST:
  947. return NativeFilter.MINPOINT_MAGLINEAR_MIPLINEAR;
  948. default:
  949. throw new Error("Unexpected sampling mode: " + samplingMode + ".");
  950. }
  951. }
  952. public createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture {
  953. let fullOptions = new RenderTargetCreationOptions();
  954. if (options !== undefined && typeof options === "object") {
  955. fullOptions.generateMipMaps = options.generateMipMaps;
  956. fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
  957. fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
  958. fullOptions.type = options.type === undefined ? Engine.TEXTURETYPE_UNSIGNED_INT : options.type;
  959. fullOptions.samplingMode = options.samplingMode === undefined ? Texture.TRILINEAR_SAMPLINGMODE : options.samplingMode;
  960. } else {
  961. fullOptions.generateMipMaps = <boolean>options;
  962. fullOptions.generateDepthBuffer = true;
  963. fullOptions.generateStencilBuffer = false;
  964. fullOptions.type = Engine.TEXTURETYPE_UNSIGNED_INT;
  965. fullOptions.samplingMode = Texture.TRILINEAR_SAMPLINGMODE;
  966. }
  967. var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
  968. var width = size.width || size;
  969. var height = size.height || size;
  970. texture._depthStencilBuffer = {};
  971. texture._framebuffer = {};
  972. texture.baseWidth = width;
  973. texture.baseHeight = height;
  974. texture.width = width;
  975. texture.height = height;
  976. texture.isReady = true;
  977. texture.samples = 1;
  978. texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
  979. texture.samplingMode = fullOptions.samplingMode;
  980. texture.type = fullOptions.type;
  981. texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
  982. texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
  983. this._internalTexturesCache.push(texture);
  984. return texture;
  985. }
  986. public updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void {
  987. if (texture._webGLTexture) {
  988. var filter = this._getSamplingFilter(samplingMode);
  989. this._native.setTextureSampling(texture._webGLTexture, filter);
  990. }
  991. texture.samplingMode = samplingMode;
  992. }
  993. public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void {
  994. throw new Error("bindFramebuffer not yet implemented.");
  995. }
  996. public unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps = false, onBeforeUnbind?: () => void): void {
  997. throw new Error("unBindFramebuffer not yet implemented.");
  998. }
  999. public createDynamicVertexBuffer(data: DataArray): WebGLBuffer {
  1000. throw new Error("createDynamicVertexBuffer not yet implemented.");
  1001. }
  1002. public updateDynamicIndexBuffer(indexBuffer: WebGLBuffer, indices: IndicesArray, offset: number = 0): void {
  1003. throw new Error("updateDynamicIndexBuffer not yet implemented.");
  1004. }
  1005. /**
  1006. * Updates a dynamic vertex buffer.
  1007. * @param vertexBuffer the vertex buffer to update
  1008. * @param data the data used to update the vertex buffer
  1009. * @param byteOffset the byte offset of the data (optional)
  1010. * @param byteLength the byte length of the data (optional)
  1011. */
  1012. public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
  1013. throw new Error("updateDynamicVertexBuffer not yet implemented.");
  1014. }
  1015. // TODO: Refactor to share more logic with base Engine implementation.
  1016. protected _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false, depthStencilTexture = false): boolean {
  1017. let uniform = this._boundUniforms[channel];
  1018. if (!uniform) {
  1019. return false;
  1020. }
  1021. // Not ready?
  1022. if (!texture) {
  1023. if (this._boundTexturesCache[channel] != null) {
  1024. this._activeChannel = channel;
  1025. this._native.setTexture(uniform, null);
  1026. }
  1027. return false;
  1028. }
  1029. // Video
  1030. if ((<VideoTexture>texture).video) {
  1031. this._activeChannel = channel;
  1032. (<VideoTexture>texture).update();
  1033. } else if (texture.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) { // Delay loading
  1034. texture.delayLoad();
  1035. return false;
  1036. }
  1037. let internalTexture: InternalTexture;
  1038. if (depthStencilTexture) {
  1039. internalTexture = (<RenderTargetTexture>texture).depthStencilTexture!;
  1040. } else if (texture.isReady()) {
  1041. internalTexture = <InternalTexture>texture.getInternalTexture();
  1042. } else if (texture.isCube) {
  1043. internalTexture = this.emptyCubeTexture;
  1044. } else if (texture.is3D) {
  1045. internalTexture = this.emptyTexture3D;
  1046. } else {
  1047. internalTexture = this.emptyTexture;
  1048. }
  1049. this._activeChannel = channel;
  1050. if (!internalTexture ||
  1051. !internalTexture._webGLTexture) {
  1052. return false;
  1053. }
  1054. this._native.setTextureWrapMode(
  1055. internalTexture._webGLTexture,
  1056. this._getAddressMode(texture.wrapU),
  1057. this._getAddressMode(texture.wrapV),
  1058. this._getAddressMode(texture.wrapR));
  1059. this._updateAnisotropicLevel(texture);
  1060. this._native.setTexture(uniform, internalTexture._webGLTexture);
  1061. return true;
  1062. }
  1063. // TODO: Share more of this logic with the base implementation.
  1064. // TODO: Rename to match naming in base implementation once refactoring allows different parameters.
  1065. private _updateAnisotropicLevel(texture: BaseTexture) {
  1066. var internalTexture = texture.getInternalTexture();
  1067. var value = texture.anisotropicFilteringLevel;
  1068. if (!internalTexture || !internalTexture._webGLTexture) {
  1069. return;
  1070. }
  1071. if (internalTexture._cachedAnisotropicFilteringLevel !== value) {
  1072. this._native.setTextureAnisotropicLevel(internalTexture._webGLTexture, value);
  1073. internalTexture._cachedAnisotropicFilteringLevel = value;
  1074. }
  1075. }
  1076. // Returns a NativeAddressMode.XXX value.
  1077. private _getAddressMode(wrapMode: number): number {
  1078. switch (wrapMode) {
  1079. case Engine.TEXTURE_WRAP_ADDRESSMODE:
  1080. return NativeAddressMode.WRAP;
  1081. case Engine.TEXTURE_CLAMP_ADDRESSMODE:
  1082. return NativeAddressMode.CLAMP;
  1083. case Engine.TEXTURE_MIRROR_ADDRESSMODE:
  1084. return NativeAddressMode.MIRROR;
  1085. default:
  1086. throw new Error("Unexpected wrap mode: " + wrapMode + ".");
  1087. }
  1088. }
  1089. /** @hidden */
  1090. public _bindTexture(channel: number, texture: InternalTexture): void {
  1091. throw new Error("_bindTexture not implemented.");
  1092. }
  1093. protected _deleteBuffer(buffer: WebGLBufferInfo): void {
  1094. if (buffer.nativeIndexBuffer) {
  1095. this._native.deleteIndexBuffer(buffer.nativeIndexBuffer);
  1096. delete buffer.nativeIndexBuffer;
  1097. }
  1098. if (buffer.nativeVertexBuffer) {
  1099. this._native.deleteVertexBuffer(buffer.nativeVertexBuffer);
  1100. delete buffer.nativeVertexBuffer;
  1101. }
  1102. // if (buffer._vertexBuffers) {
  1103. // for (const vertexBuffer of buffer._vertexBuffers) {
  1104. // const nativeBuffer = vertexBuffer._nativeBuffer;
  1105. // if (nativeBuffer) {
  1106. // delete vertexBuffer._nativeBuffer;
  1107. // }
  1108. // }
  1109. // }
  1110. }
  1111. public releaseEffects() {
  1112. // TODO: Implement.
  1113. }
  1114. /** @hidden */
  1115. public _uploadCompressedDataToTextureDirectly(texture: InternalTexture, internalFormat: number, width: number, height: number, data: ArrayBufferView, faceIndex: number = 0, lod: number = 0) {
  1116. throw new Error("_uploadCompressedDataToTextureDirectly not implemented.");
  1117. }
  1118. /** @hidden */
  1119. public _uploadDataToTextureDirectly(texture: InternalTexture, imageData: ArrayBufferView, faceIndex: number = 0, lod: number = 0): void {
  1120. throw new Error("_uploadDataToTextureDirectly not implemented.");
  1121. }
  1122. /** @hidden */
  1123. public _uploadArrayBufferViewToTexture(texture: InternalTexture, imageData: ArrayBufferView, faceIndex: number = 0, lod: number = 0): void {
  1124. throw new Error("_uploadArrayBufferViewToTexture not implemented.");
  1125. }
  1126. /** @hidden */
  1127. public _uploadImageToTexture(texture: InternalTexture, image: HTMLImageElement, faceIndex: number = 0, lod: number = 0) {
  1128. throw new Error("_uploadArrayBufferViewToTexture not implemented.");
  1129. }
  1130. }