12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815 |
- import { IsWrapper } from "../Materials/drawWrapper.functions.js";
- import { Logger } from "../Misc/logger.js";
- import { IsWindowObjectExist } from "../Misc/domManagement.js";
- import { WebGLShaderProcessor } from "./WebGL/webGLShaderProcessors.js";
- import { WebGL2ShaderProcessor } from "./WebGL/webGL2ShaderProcessors.js";
- import { WebGLDataBuffer } from "../Meshes/WebGL/webGLDataBuffer.js";
- import { CeilingPOT, FloorPOT, GetExponentOfTwo, NearestPOT } from "../Misc/tools.functions.js";
- import { AbstractEngine, QueueNewFrame } from "./abstractEngine.js";
- import { WebGLHardwareTexture } from "./WebGL/webGLHardwareTexture.js";
- import { ShaderLanguage } from "../Materials/shaderLanguage.js";
- import { WebGLPipelineContext } from "./WebGL/webGLPipelineContext.js";
- import { InternalTexture, InternalTextureSource } from "../Materials/Textures/internalTexture.js";
- import { Effect } from "../Materials/effect.js";
- import { _WarnImport } from "../Misc/devTools.js";
- /**
- * Keeps track of all the buffer info used in engine.
- */
- class BufferPointer {
- }
- /**
- * The base engine class (root of all engines)
- */
- export class ThinEngine extends AbstractEngine {
- /**
- * Gets or sets the name of the engine
- */
- get name() {
- return this._name;
- }
- set name(value) {
- this._name = value;
- }
- /**
- * Returns the version of the engine
- */
- get version() {
- return this._webGLVersion;
- }
- /**
- * Gets or sets the relative url used to load shaders if using the engine in non-minified mode
- */
- static get ShadersRepository() {
- return Effect.ShadersRepository;
- }
- static set ShadersRepository(value) {
- Effect.ShadersRepository = value;
- }
- /**
- * Gets a boolean indicating that the engine supports uniform buffers
- * @see https://doc.babylonjs.com/setup/support/webGL2#uniform-buffer-objets
- */
- get supportsUniformBuffers() {
- return this.webGLVersion > 1 && !this.disableUniformBuffers;
- }
- /**
- * Gets the options used for engine creation
- * @returns EngineOptions object
- */
- getCreationOptions() {
- return this._creationOptions;
- }
- /**
- * Gets a boolean indicating that only power of 2 textures are supported
- * Please note that you can still use non power of 2 textures but in this case the engine will forcefully convert them
- */
- get needPOTTextures() {
- return this._webGLVersion < 2 || this.forcePOTTextures;
- }
- get _supportsHardwareTextureRescaling() {
- return false;
- }
- /**
- * sets the object from which width and height will be taken from when getting render width and height
- * Will fallback to the gl object
- * @param dimensions the framebuffer width and height that will be used.
- */
- set framebufferDimensionsObject(dimensions) {
- this._framebufferDimensionsObject = dimensions;
- }
- /**
- * Creates a new snapshot at the next frame using the current snapshotRenderingMode
- */
- snapshotRenderingReset() {
- this.snapshotRendering = false;
- }
- /**
- * Creates a new engine
- * @param canvasOrContext defines the canvas or WebGL context to use for rendering. If you provide a WebGL context, Babylon.js will not hook events on the canvas (like pointers, keyboards, etc...) so no event observables will be available. This is mostly used when Babylon.js is used as a plugin on a system which already used the WebGL context
- * @param antialias defines enable antialiasing (default: false)
- * @param options defines further options to be sent to the getContext() function
- * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
- */
- constructor(canvasOrContext, antialias, options, adaptToDeviceRatio) {
- options = options || {};
- super((antialias ?? options.antialias) || false, options, adaptToDeviceRatio);
- /** @internal */
- this._name = "WebGL";
- /**
- * Gets or sets a boolean that indicates if textures must be forced to power of 2 size even if not required
- */
- this.forcePOTTextures = false;
- /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
- this.validateShaderPrograms = false;
- /**
- * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
- */
- this.disableUniformBuffers = false;
- /** @internal */
- this._webGLVersion = 1.0;
- this._vertexAttribArraysEnabled = [];
- this._uintIndicesCurrentlySet = false;
- this._currentBoundBuffer = new Array();
- /** @internal */
- this._currentFramebuffer = null;
- /** @internal */
- this._dummyFramebuffer = null;
- this._currentBufferPointers = new Array();
- this._currentInstanceLocations = new Array();
- this._currentInstanceBuffers = new Array();
- this._vaoRecordInProgress = false;
- this._mustWipeVertexAttributes = false;
- this._nextFreeTextureSlots = new Array();
- this._maxSimultaneousTextures = 0;
- this._maxMSAASamplesOverride = null;
- this._unpackFlipYCached = null;
- /**
- * In case you are sharing the context with other applications, it might
- * be interested to not cache the unpack flip y state to ensure a consistent
- * value would be set.
- */
- this.enableUnpackFlipYCached = true;
- this._boundUniforms = {};
- this._creationOptions = options;
- if (!canvasOrContext) {
- return;
- }
- let canvas = null;
- if (canvasOrContext.getContext) {
- canvas = canvasOrContext;
- this._renderingCanvas = canvas;
- if (options.preserveDrawingBuffer === undefined) {
- options.preserveDrawingBuffer = false;
- }
- if (options.xrCompatible === undefined) {
- options.xrCompatible = true;
- }
- // Exceptions
- if (navigator && navigator.userAgent) {
- this._setupMobileChecks();
- const ua = navigator.userAgent;
- for (const exception of ThinEngine.ExceptionList) {
- const key = exception.key;
- const targets = exception.targets;
- const check = new RegExp(key);
- if (check.test(ua)) {
- if (exception.capture && exception.captureConstraint) {
- const capture = exception.capture;
- const constraint = exception.captureConstraint;
- const regex = new RegExp(capture);
- const matches = regex.exec(ua);
- if (matches && matches.length > 0) {
- const capturedValue = parseInt(matches[matches.length - 1]);
- if (capturedValue >= constraint) {
- continue;
- }
- }
- }
- for (const target of targets) {
- switch (target) {
- case "uniformBuffer":
- this.disableUniformBuffers = true;
- break;
- case "vao":
- this.disableVertexArrayObjects = true;
- break;
- case "antialias":
- options.antialias = false;
- break;
- case "maxMSAASamples":
- this._maxMSAASamplesOverride = 1;
- break;
- }
- }
- }
- }
- }
- // Context lost
- if (!this._doNotHandleContextLost) {
- this._onContextLost = (evt) => {
- evt.preventDefault();
- this._contextWasLost = true;
- Logger.Warn("WebGL context lost.");
- this.onContextLostObservable.notifyObservers(this);
- };
- this._onContextRestored = () => {
- this._restoreEngineAfterContextLost(() => this._initGLContext());
- };
- canvas.addEventListener("webglcontextlost", this._onContextLost, false);
- canvas.addEventListener("webglcontextrestored", this._onContextRestored, false);
- options.powerPreference = options.powerPreference || "high-performance";
- }
- if (this._badDesktopOS) {
- options.xrCompatible = false;
- }
- // GL
- if (!options.disableWebGL2Support) {
- try {
- this._gl = (canvas.getContext("webgl2", options) || canvas.getContext("experimental-webgl2", options));
- if (this._gl) {
- this._webGLVersion = 2.0;
- this._shaderPlatformName = "WEBGL2";
- // Prevent weird browsers to lie (yeah that happens!)
- if (!this._gl.deleteQuery) {
- this._webGLVersion = 1.0;
- this._shaderPlatformName = "WEBGL1";
- }
- }
- }
- catch (e) {
- // Do nothing
- }
- }
- if (!this._gl) {
- if (!canvas) {
- throw new Error("The provided canvas is null or undefined.");
- }
- try {
- this._gl = (canvas.getContext("webgl", options) || canvas.getContext("experimental-webgl", options));
- }
- catch (e) {
- throw new Error("WebGL not supported");
- }
- }
- if (!this._gl) {
- throw new Error("WebGL not supported");
- }
- }
- else {
- this._gl = canvasOrContext;
- this._renderingCanvas = this._gl.canvas;
- if (this._gl.renderbufferStorageMultisample) {
- this._webGLVersion = 2.0;
- this._shaderPlatformName = "WEBGL2";
- }
- else {
- this._shaderPlatformName = "WEBGL1";
- }
- const attributes = this._gl.getContextAttributes();
- if (attributes) {
- options.stencil = attributes.stencil;
- }
- }
- // Ensures a consistent color space unpacking of textures cross browser.
- this._gl.pixelStorei(this._gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, this._gl.NONE);
- if (options.useHighPrecisionFloats !== undefined) {
- this._highPrecisionShadersAllowed = options.useHighPrecisionFloats;
- }
- this.resize();
- this._initGLContext();
- this._initFeatures();
- // Prepare buffer pointers
- for (let i = 0; i < this._caps.maxVertexAttribs; i++) {
- this._currentBufferPointers[i] = new BufferPointer();
- }
- // Shader processor
- this._shaderProcessor = this.webGLVersion > 1 ? new WebGL2ShaderProcessor() : new WebGLShaderProcessor();
- // Starting with iOS 14, we can trust the browser
- // let matches = navigator.userAgent.match(/Version\/(\d+)/);
- // if (matches && matches.length === 2) {
- // if (parseInt(matches[1]) >= 14) {
- // this._badOS = false;
- // }
- // }
- const versionToLog = `Babylon.js v${ThinEngine.Version}`;
- Logger.Log(versionToLog + ` - ${this.description}`);
- // Check setAttribute in case of workers
- if (this._renderingCanvas && this._renderingCanvas.setAttribute) {
- this._renderingCanvas.setAttribute("data-engine", versionToLog);
- }
- }
- _clearEmptyResources() {
- this._dummyFramebuffer = null;
- super._clearEmptyResources();
- }
- /**
- * @internal
- */
- _getShaderProcessingContext(shaderLanguage) {
- return null;
- }
- /**
- * Gets a boolean indicating if all created effects are ready
- * @returns true if all effects are ready
- */
- areAllEffectsReady() {
- for (const key in this._compiledEffects) {
- const effect = this._compiledEffects[key];
- if (!effect.isReady()) {
- return false;
- }
- }
- return true;
- }
- _initGLContext() {
- // Caps
- this._caps = {
- maxTexturesImageUnits: this._gl.getParameter(this._gl.MAX_TEXTURE_IMAGE_UNITS),
- maxCombinedTexturesImageUnits: this._gl.getParameter(this._gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),
- maxVertexTextureImageUnits: this._gl.getParameter(this._gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS),
- maxTextureSize: this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE),
- maxSamples: this._webGLVersion > 1 ? this._gl.getParameter(this._gl.MAX_SAMPLES) : 1,
- maxCubemapTextureSize: this._gl.getParameter(this._gl.MAX_CUBE_MAP_TEXTURE_SIZE),
- maxRenderTextureSize: this._gl.getParameter(this._gl.MAX_RENDERBUFFER_SIZE),
- maxVertexAttribs: this._gl.getParameter(this._gl.MAX_VERTEX_ATTRIBS),
- maxVaryingVectors: this._gl.getParameter(this._gl.MAX_VARYING_VECTORS),
- maxFragmentUniformVectors: this._gl.getParameter(this._gl.MAX_FRAGMENT_UNIFORM_VECTORS),
- maxVertexUniformVectors: this._gl.getParameter(this._gl.MAX_VERTEX_UNIFORM_VECTORS),
- parallelShaderCompile: this._gl.getExtension("KHR_parallel_shader_compile") || undefined,
- standardDerivatives: this._webGLVersion > 1 || this._gl.getExtension("OES_standard_derivatives") !== null,
- maxAnisotropy: 1,
- astc: this._gl.getExtension("WEBGL_compressed_texture_astc") || this._gl.getExtension("WEBKIT_WEBGL_compressed_texture_astc"),
- bptc: this._gl.getExtension("EXT_texture_compression_bptc") || this._gl.getExtension("WEBKIT_EXT_texture_compression_bptc"),
- s3tc: this._gl.getExtension("WEBGL_compressed_texture_s3tc") || this._gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"),
- // eslint-disable-next-line @typescript-eslint/naming-convention
- s3tc_srgb: this._gl.getExtension("WEBGL_compressed_texture_s3tc_srgb") || this._gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc_srgb"),
- pvrtc: this._gl.getExtension("WEBGL_compressed_texture_pvrtc") || this._gl.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc"),
- etc1: this._gl.getExtension("WEBGL_compressed_texture_etc1") || this._gl.getExtension("WEBKIT_WEBGL_compressed_texture_etc1"),
- etc2: this._gl.getExtension("WEBGL_compressed_texture_etc") ||
- this._gl.getExtension("WEBKIT_WEBGL_compressed_texture_etc") ||
- this._gl.getExtension("WEBGL_compressed_texture_es3_0"),
- textureAnisotropicFilterExtension: this._gl.getExtension("EXT_texture_filter_anisotropic") ||
- this._gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic") ||
- this._gl.getExtension("MOZ_EXT_texture_filter_anisotropic"),
- uintIndices: this._webGLVersion > 1 || this._gl.getExtension("OES_element_index_uint") !== null,
- fragmentDepthSupported: this._webGLVersion > 1 || this._gl.getExtension("EXT_frag_depth") !== null,
- highPrecisionShaderSupported: false,
- timerQuery: this._gl.getExtension("EXT_disjoint_timer_query_webgl2") || this._gl.getExtension("EXT_disjoint_timer_query"),
- supportOcclusionQuery: this._webGLVersion > 1,
- canUseTimestampForTimerQuery: false,
- drawBuffersExtension: false,
- maxMSAASamples: 1,
- colorBufferFloat: !!(this._webGLVersion > 1 && this._gl.getExtension("EXT_color_buffer_float")),
- supportFloatTexturesResolve: false,
- rg11b10ufColorRenderable: false,
- colorBufferHalfFloat: !!(this._webGLVersion > 1 && this._gl.getExtension("EXT_color_buffer_half_float")),
- textureFloat: this._webGLVersion > 1 || this._gl.getExtension("OES_texture_float") ? true : false,
- textureHalfFloat: this._webGLVersion > 1 || this._gl.getExtension("OES_texture_half_float") ? true : false,
- textureHalfFloatRender: false,
- textureFloatLinearFiltering: false,
- textureFloatRender: false,
- textureHalfFloatLinearFiltering: false,
- vertexArrayObject: false,
- instancedArrays: false,
- textureLOD: this._webGLVersion > 1 || this._gl.getExtension("EXT_shader_texture_lod") ? true : false,
- texelFetch: this._webGLVersion !== 1,
- blendMinMax: false,
- multiview: this._gl.getExtension("OVR_multiview2"),
- oculusMultiview: this._gl.getExtension("OCULUS_multiview"),
- depthTextureExtension: false,
- canUseGLInstanceID: this._webGLVersion > 1,
- canUseGLVertexID: this._webGLVersion > 1,
- supportComputeShaders: false,
- supportSRGBBuffers: false,
- supportTransformFeedbacks: this._webGLVersion > 1,
- textureMaxLevel: this._webGLVersion > 1,
- texture2DArrayMaxLayerCount: this._webGLVersion > 1 ? this._gl.getParameter(this._gl.MAX_ARRAY_TEXTURE_LAYERS) : 128,
- disableMorphTargetTexture: false,
- };
- this._caps.supportFloatTexturesResolve = this._caps.colorBufferFloat;
- this._caps.rg11b10ufColorRenderable = this._caps.colorBufferFloat;
- // Infos
- this._glVersion = this._gl.getParameter(this._gl.VERSION);
- const rendererInfo = this._gl.getExtension("WEBGL_debug_renderer_info");
- if (rendererInfo != null) {
- this._glRenderer = this._gl.getParameter(rendererInfo.UNMASKED_RENDERER_WEBGL);
- this._glVendor = this._gl.getParameter(rendererInfo.UNMASKED_VENDOR_WEBGL);
- }
- if (!this._glVendor) {
- this._glVendor = this._gl.getParameter(this._gl.VENDOR) || "Unknown vendor";
- }
- if (!this._glRenderer) {
- this._glRenderer = this._gl.getParameter(this._gl.RENDERER) || "Unknown renderer";
- }
- // Constants
- if (this._gl.HALF_FLOAT_OES !== 0x8d61) {
- this._gl.HALF_FLOAT_OES = 0x8d61; // Half floating-point type (16-bit).
- }
- if (this._gl.RGBA16F !== 0x881a) {
- this._gl.RGBA16F = 0x881a; // RGBA 16-bit floating-point color-renderable internal sized format.
- }
- if (this._gl.RGBA32F !== 0x8814) {
- this._gl.RGBA32F = 0x8814; // RGBA 32-bit floating-point color-renderable internal sized format.
- }
- if (this._gl.DEPTH24_STENCIL8 !== 35056) {
- this._gl.DEPTH24_STENCIL8 = 35056;
- }
- // Extensions
- if (this._caps.timerQuery) {
- if (this._webGLVersion === 1) {
- this._gl.getQuery = this._caps.timerQuery.getQueryEXT.bind(this._caps.timerQuery);
- }
- // WebGLQuery casted to number to avoid TS error
- this._caps.canUseTimestampForTimerQuery = (this._gl.getQuery(this._caps.timerQuery.TIMESTAMP_EXT, this._caps.timerQuery.QUERY_COUNTER_BITS_EXT) ?? 0) > 0;
- }
- this._caps.maxAnisotropy = this._caps.textureAnisotropicFilterExtension
- ? this._gl.getParameter(this._caps.textureAnisotropicFilterExtension.MAX_TEXTURE_MAX_ANISOTROPY_EXT)
- : 0;
- this._caps.textureFloatLinearFiltering = this._caps.textureFloat && this._gl.getExtension("OES_texture_float_linear") ? true : false;
- this._caps.textureFloatRender = this._caps.textureFloat && this._canRenderToFloatFramebuffer() ? true : false;
- this._caps.textureHalfFloatLinearFiltering =
- this._webGLVersion > 1 || (this._caps.textureHalfFloat && this._gl.getExtension("OES_texture_half_float_linear")) ? true : false;
- // Compressed formats
- if (this._caps.astc) {
- this._gl.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = this._caps.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR;
- }
- if (this._caps.bptc) {
- this._gl.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT = this._caps.bptc.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT;
- }
- if (this._caps.s3tc_srgb) {
- this._gl.COMPRESSED_SRGB_S3TC_DXT1_EXT = this._caps.s3tc_srgb.COMPRESSED_SRGB_S3TC_DXT1_EXT;
- this._gl.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = this._caps.s3tc_srgb.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
- this._gl.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = this._caps.s3tc_srgb.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
- }
- if (this._caps.etc2) {
- this._gl.COMPRESSED_SRGB8_ETC2 = this._caps.etc2.COMPRESSED_SRGB8_ETC2;
- this._gl.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = this._caps.etc2.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
- }
- // Checks if some of the format renders first to allow the use of webgl inspector.
- if (this._webGLVersion > 1) {
- if (this._gl.HALF_FLOAT_OES !== 0x140b) {
- this._gl.HALF_FLOAT_OES = 0x140b;
- }
- }
- this._caps.textureHalfFloatRender = this._caps.textureHalfFloat && this._canRenderToHalfFloatFramebuffer();
- // Draw buffers
- if (this._webGLVersion > 1) {
- this._caps.drawBuffersExtension = true;
- this._caps.maxMSAASamples = this._maxMSAASamplesOverride !== null ? this._maxMSAASamplesOverride : this._gl.getParameter(this._gl.MAX_SAMPLES);
- }
- else {
- const drawBuffersExtension = this._gl.getExtension("WEBGL_draw_buffers");
- if (drawBuffersExtension !== null) {
- this._caps.drawBuffersExtension = true;
- this._gl.drawBuffers = drawBuffersExtension.drawBuffersWEBGL.bind(drawBuffersExtension);
- this._gl.DRAW_FRAMEBUFFER = this._gl.FRAMEBUFFER;
- for (let i = 0; i < 16; i++) {
- this._gl["COLOR_ATTACHMENT" + i + "_WEBGL"] = drawBuffersExtension["COLOR_ATTACHMENT" + i + "_WEBGL"];
- }
- }
- }
- // Depth Texture
- if (this._webGLVersion > 1) {
- this._caps.depthTextureExtension = true;
- }
- else {
- const depthTextureExtension = this._gl.getExtension("WEBGL_depth_texture");
- if (depthTextureExtension != null) {
- this._caps.depthTextureExtension = true;
- this._gl.UNSIGNED_INT_24_8 = depthTextureExtension.UNSIGNED_INT_24_8_WEBGL;
- }
- }
- // Vertex array object
- if (this.disableVertexArrayObjects) {
- this._caps.vertexArrayObject = false;
- }
- else if (this._webGLVersion > 1) {
- this._caps.vertexArrayObject = true;
- }
- else {
- const vertexArrayObjectExtension = this._gl.getExtension("OES_vertex_array_object");
- if (vertexArrayObjectExtension != null) {
- this._caps.vertexArrayObject = true;
- this._gl.createVertexArray = vertexArrayObjectExtension.createVertexArrayOES.bind(vertexArrayObjectExtension);
- this._gl.bindVertexArray = vertexArrayObjectExtension.bindVertexArrayOES.bind(vertexArrayObjectExtension);
- this._gl.deleteVertexArray = vertexArrayObjectExtension.deleteVertexArrayOES.bind(vertexArrayObjectExtension);
- }
- }
- // Instances count
- if (this._webGLVersion > 1) {
- this._caps.instancedArrays = true;
- }
- else {
- const instanceExtension = this._gl.getExtension("ANGLE_instanced_arrays");
- if (instanceExtension != null) {
- this._caps.instancedArrays = true;
- this._gl.drawArraysInstanced = instanceExtension.drawArraysInstancedANGLE.bind(instanceExtension);
- this._gl.drawElementsInstanced = instanceExtension.drawElementsInstancedANGLE.bind(instanceExtension);
- this._gl.vertexAttribDivisor = instanceExtension.vertexAttribDivisorANGLE.bind(instanceExtension);
- }
- else {
- this._caps.instancedArrays = false;
- }
- }
- if (this._gl.getShaderPrecisionFormat) {
- const vertexhighp = this._gl.getShaderPrecisionFormat(this._gl.VERTEX_SHADER, this._gl.HIGH_FLOAT);
- const fragmenthighp = this._gl.getShaderPrecisionFormat(this._gl.FRAGMENT_SHADER, this._gl.HIGH_FLOAT);
- if (vertexhighp && fragmenthighp) {
- this._caps.highPrecisionShaderSupported = vertexhighp.precision !== 0 && fragmenthighp.precision !== 0;
- }
- }
- if (this._webGLVersion > 1) {
- this._caps.blendMinMax = true;
- }
- else {
- const blendMinMaxExtension = this._gl.getExtension("EXT_blend_minmax");
- if (blendMinMaxExtension != null) {
- this._caps.blendMinMax = true;
- this._gl.MAX = blendMinMaxExtension.MAX_EXT;
- this._gl.MIN = blendMinMaxExtension.MIN_EXT;
- }
- }
- // sRGB buffers
- // only run this if not already set to true (in the constructor, for example)
- if (!this._caps.supportSRGBBuffers) {
- if (this._webGLVersion > 1) {
- this._caps.supportSRGBBuffers = true;
- this._glSRGBExtensionValues = {
- SRGB: WebGL2RenderingContext.SRGB,
- SRGB8: WebGL2RenderingContext.SRGB8,
- SRGB8_ALPHA8: WebGL2RenderingContext.SRGB8_ALPHA8,
- };
- }
- else {
- const sRGBExtension = this._gl.getExtension("EXT_sRGB");
- if (sRGBExtension != null) {
- this._caps.supportSRGBBuffers = true;
- this._glSRGBExtensionValues = {
- SRGB: sRGBExtension.SRGB_EXT,
- SRGB8: sRGBExtension.SRGB_ALPHA_EXT,
- SRGB8_ALPHA8: sRGBExtension.SRGB_ALPHA_EXT,
- };
- }
- }
- // take into account the forced state that was provided in options
- // When the issue in angle/chrome is fixed the flag should be taken into account only when it is explicitly defined
- this._caps.supportSRGBBuffers = this._caps.supportSRGBBuffers && !!(this._creationOptions && this._creationOptions.forceSRGBBufferSupportState);
- }
- // Depth buffer
- this._depthCullingState.depthTest = true;
- this._depthCullingState.depthFunc = this._gl.LEQUAL;
- this._depthCullingState.depthMask = true;
- // Texture maps
- this._maxSimultaneousTextures = this._caps.maxCombinedTexturesImageUnits;
- for (let slot = 0; slot < this._maxSimultaneousTextures; slot++) {
- this._nextFreeTextureSlots.push(slot);
- }
- if (this._glRenderer === "Mali-G72") {
- // Overcome a bug when using a texture to store morph targets on Mali-G72
- this._caps.disableMorphTargetTexture = true;
- }
- }
- _initFeatures() {
- this._features = {
- forceBitmapOverHTMLImageElement: typeof HTMLImageElement === "undefined",
- supportRenderAndCopyToLodForFloatTextures: this._webGLVersion !== 1,
- supportDepthStencilTexture: this._webGLVersion !== 1,
- supportShadowSamplers: this._webGLVersion !== 1,
- uniformBufferHardCheckMatrix: false,
- allowTexturePrefiltering: this._webGLVersion !== 1,
- trackUbosInFrame: false,
- checkUbosContentBeforeUpload: false,
- supportCSM: this._webGLVersion !== 1,
- basisNeedsPOT: this._webGLVersion === 1,
- support3DTextures: this._webGLVersion !== 1,
- needTypeSuffixInShaderConstants: this._webGLVersion !== 1,
- supportMSAA: this._webGLVersion !== 1,
- supportSSAO2: this._webGLVersion !== 1,
- supportExtendedTextureFormats: this._webGLVersion !== 1,
- supportSwitchCaseInShader: this._webGLVersion !== 1,
- supportSyncTextureRead: true,
- needsInvertingBitmap: true,
- useUBOBindingCache: true,
- needShaderCodeInlining: false,
- needToAlwaysBindUniformBuffers: false,
- supportRenderPasses: false,
- supportSpriteInstancing: true,
- forceVertexBufferStrideAndOffsetMultiple4Bytes: false,
- _collectUbosUpdatedInFrame: false,
- };
- }
- /**
- * Gets version of the current webGL context
- * Keep it for back compat - use version instead
- */
- get webGLVersion() {
- return this._webGLVersion;
- }
- /**
- * Gets a string identifying the name of the class
- * @returns "Engine" string
- */
- getClassName() {
- return "ThinEngine";
- }
- /** @internal */
- _prepareWorkingCanvas() {
- if (this._workingCanvas) {
- return;
- }
- this._workingCanvas = this.createCanvas(1, 1);
- const context = this._workingCanvas.getContext("2d");
- if (context) {
- this._workingContext = context;
- }
- }
- /**
- * Gets an object containing information about the current engine context
- * @returns an object containing the vendor, the renderer and the version of the current engine context
- */
- getInfo() {
- return this.getGlInfo();
- }
- /**
- * Gets an object containing information about the current webGL context
- * @returns an object containing the vendor, the renderer and the version of the current webGL context
- */
- getGlInfo() {
- return {
- vendor: this._glVendor,
- renderer: this._glRenderer,
- version: this._glVersion,
- };
- }
- /**Gets driver info if available */
- extractDriverInfo() {
- const glInfo = this.getGlInfo();
- if (glInfo && glInfo.renderer) {
- return glInfo.renderer;
- }
- return "";
- }
- /**
- * Gets the current render width
- * @param useScreen defines if screen size must be used (or the current render target if any)
- * @returns a number defining the current render width
- */
- getRenderWidth(useScreen = false) {
- if (!useScreen && this._currentRenderTarget) {
- return this._currentRenderTarget.width;
- }
- return this._framebufferDimensionsObject ? this._framebufferDimensionsObject.framebufferWidth : this._gl.drawingBufferWidth;
- }
- /**
- * Gets the current render height
- * @param useScreen defines if screen size must be used (or the current render target if any)
- * @returns a number defining the current render height
- */
- getRenderHeight(useScreen = false) {
- if (!useScreen && this._currentRenderTarget) {
- return this._currentRenderTarget.height;
- }
- return this._framebufferDimensionsObject ? this._framebufferDimensionsObject.framebufferHeight : this._gl.drawingBufferHeight;
- }
- /**
- * Clear the current render buffer or the current render target (if any is set up)
- * @param color defines the color to use
- * @param backBuffer defines if the back buffer must be cleared
- * @param depth defines if the depth buffer must be cleared
- * @param stencil defines if the stencil buffer must be cleared
- */
- clear(color, backBuffer, depth, stencil = false) {
- const useStencilGlobalOnly = this.stencilStateComposer.useStencilGlobalOnly;
- this.stencilStateComposer.useStencilGlobalOnly = true; // make sure the stencil mask is coming from the global stencil and not from a material (effect) which would currently be in effect
- this.applyStates();
- this.stencilStateComposer.useStencilGlobalOnly = useStencilGlobalOnly;
- let mode = 0;
- if (backBuffer && color) {
- let setBackBufferColor = true;
- if (this._currentRenderTarget) {
- const textureFormat = this._currentRenderTarget.texture?.format;
- if (textureFormat === 8 ||
- textureFormat === 9 ||
- textureFormat === 10 ||
- textureFormat === 11) {
- const textureType = this._currentRenderTarget.texture?.type;
- if (textureType === 7 || textureType === 5) {
- ThinEngine._TempClearColorUint32[0] = color.r * 255;
- ThinEngine._TempClearColorUint32[1] = color.g * 255;
- ThinEngine._TempClearColorUint32[2] = color.b * 255;
- ThinEngine._TempClearColorUint32[3] = color.a * 255;
- this._gl.clearBufferuiv(this._gl.COLOR, 0, ThinEngine._TempClearColorUint32);
- setBackBufferColor = false;
- }
- else {
- ThinEngine._TempClearColorInt32[0] = color.r * 255;
- ThinEngine._TempClearColorInt32[1] = color.g * 255;
- ThinEngine._TempClearColorInt32[2] = color.b * 255;
- ThinEngine._TempClearColorInt32[3] = color.a * 255;
- this._gl.clearBufferiv(this._gl.COLOR, 0, ThinEngine._TempClearColorInt32);
- setBackBufferColor = false;
- }
- }
- }
- if (setBackBufferColor) {
- this._gl.clearColor(color.r, color.g, color.b, color.a !== undefined ? color.a : 1.0);
- mode |= this._gl.COLOR_BUFFER_BIT;
- }
- }
- if (depth) {
- if (this.useReverseDepthBuffer) {
- this._depthCullingState.depthFunc = this._gl.GEQUAL;
- this._gl.clearDepth(0.0);
- }
- else {
- this._gl.clearDepth(1.0);
- }
- mode |= this._gl.DEPTH_BUFFER_BIT;
- }
- if (stencil) {
- this._gl.clearStencil(0);
- mode |= this._gl.STENCIL_BUFFER_BIT;
- }
- this._gl.clear(mode);
- }
- /**
- * @internal
- */
- _viewport(x, y, width, height) {
- if (x !== this._viewportCached.x || y !== this._viewportCached.y || width !== this._viewportCached.z || height !== this._viewportCached.w) {
- this._viewportCached.x = x;
- this._viewportCached.y = y;
- this._viewportCached.z = width;
- this._viewportCached.w = height;
- this._gl.viewport(x, y, width, height);
- }
- }
- /**
- * End the current frame
- */
- endFrame() {
- super.endFrame();
- // Force a flush in case we are using a bad OS.
- if (this._badOS) {
- this.flushFramebuffer();
- }
- }
- /**
- * Gets the performance monitor attached to this engine
- * @see https://doc.babylonjs.com/features/featuresDeepDive/scene/optimize_your_scene#engineinstrumentation
- */
- get performanceMonitor() {
- throw new Error("Not Supported by ThinEngine");
- }
- /**
- * Binds the frame buffer to the specified texture.
- * @param rtWrapper The render target wrapper to render to
- * @param faceIndex The face of the texture to render to in case of cube texture and if the render target wrapper is not a multi render target
- * @param requiredWidth The width of the target to render to
- * @param requiredHeight The height of the target to render to
- * @param forceFullscreenViewport Forces the viewport to be the entire texture/screen if true
- * @param lodLevel Defines the lod level to bind to the frame buffer
- * @param layer Defines the 2d array index to bind to the frame buffer if the render target wrapper is not a multi render target
- */
- bindFramebuffer(rtWrapper, faceIndex = 0, requiredWidth, requiredHeight, forceFullscreenViewport, lodLevel = 0, layer = 0) {
- const webglRTWrapper = rtWrapper;
- if (this._currentRenderTarget) {
- this.unBindFramebuffer(this._currentRenderTarget);
- }
- this._currentRenderTarget = rtWrapper;
- this._bindUnboundFramebuffer(webglRTWrapper._MSAAFramebuffer ? webglRTWrapper._MSAAFramebuffer : webglRTWrapper._framebuffer);
- const gl = this._gl;
- if (!rtWrapper.isMulti) {
- if (rtWrapper.is2DArray || rtWrapper.is3D) {
- gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, rtWrapper.texture._hardwareTexture?.underlyingResource, lodLevel, layer);
- }
- else if (rtWrapper.isCube) {
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, rtWrapper.texture._hardwareTexture?.underlyingResource, lodLevel);
- }
- else if (webglRTWrapper._currentLOD !== lodLevel) {
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, rtWrapper.texture._hardwareTexture?.underlyingResource, lodLevel);
- webglRTWrapper._currentLOD = lodLevel;
- }
- }
- const depthStencilTexture = rtWrapper._depthStencilTexture;
- if (depthStencilTexture) {
- if (rtWrapper.is3D) {
- if (rtWrapper.texture.width !== depthStencilTexture.width ||
- rtWrapper.texture.height !== depthStencilTexture.height ||
- rtWrapper.texture.depth !== depthStencilTexture.depth) {
- Logger.Warn("Depth/Stencil attachment for 3D target must have same dimensions as color attachment");
- }
- }
- const attachment = rtWrapper._depthStencilTextureWithStencil ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
- if (rtWrapper.is2DArray || rtWrapper.is3D) {
- gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachment, depthStencilTexture._hardwareTexture?.underlyingResource, lodLevel, layer);
- }
- else if (rtWrapper.isCube) {
- gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._hardwareTexture?.underlyingResource, lodLevel);
- }
- else {
- gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, depthStencilTexture._hardwareTexture?.underlyingResource, lodLevel);
- }
- }
- if (this._cachedViewport && !forceFullscreenViewport) {
- this.setViewport(this._cachedViewport, requiredWidth, requiredHeight);
- }
- else {
- if (!requiredWidth) {
- requiredWidth = rtWrapper.width;
- if (lodLevel) {
- requiredWidth = requiredWidth / Math.pow(2, lodLevel);
- }
- }
- if (!requiredHeight) {
- requiredHeight = rtWrapper.height;
- if (lodLevel) {
- requiredHeight = requiredHeight / Math.pow(2, lodLevel);
- }
- }
- this._viewport(0, 0, requiredWidth, requiredHeight);
- }
- this.wipeCaches();
- }
- /**
- * Set various states to the webGL context
- * @param culling defines culling state: true to enable culling, false to disable it
- * @param zOffset defines the value to apply to zOffset (0 by default)
- * @param force defines if states must be applied even if cache is up to date
- * @param reverseSide defines if culling must be reversed (CCW if false, CW if true)
- * @param cullBackFaces true to cull back faces, false to cull front faces (if culling is enabled)
- * @param stencil stencil states to set
- * @param zOffsetUnits defines the value to apply to zOffsetUnits (0 by default)
- */
- setState(culling, zOffset = 0, force, reverseSide = false, cullBackFaces, stencil, zOffsetUnits = 0) {
- // Culling
- if (this._depthCullingState.cull !== culling || force) {
- this._depthCullingState.cull = culling;
- }
- // Cull face
- const cullFace = this.cullBackFaces ?? cullBackFaces ?? true ? this._gl.BACK : this._gl.FRONT;
- if (this._depthCullingState.cullFace !== cullFace || force) {
- this._depthCullingState.cullFace = cullFace;
- }
- // Z offset
- this.setZOffset(zOffset);
- this.setZOffsetUnits(zOffsetUnits);
- // Front face
- const frontFace = reverseSide ? this._gl.CW : this._gl.CCW;
- if (this._depthCullingState.frontFace !== frontFace || force) {
- this._depthCullingState.frontFace = frontFace;
- }
- this._stencilStateComposer.stencilMaterial = stencil;
- }
- /**
- * @internal
- */
- _bindUnboundFramebuffer(framebuffer) {
- if (this._currentFramebuffer !== framebuffer) {
- this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, framebuffer);
- this._currentFramebuffer = framebuffer;
- }
- }
- /** @internal */
- _currentFrameBufferIsDefaultFrameBuffer() {
- return this._currentFramebuffer === null;
- }
- /**
- * Generates the mipmaps for a texture
- * @param texture texture to generate the mipmaps for
- */
- generateMipmaps(texture) {
- const target = this._getTextureTarget(texture);
- this._bindTextureDirectly(target, texture, true);
- this._gl.generateMipmap(target);
- this._bindTextureDirectly(target, null);
- }
- /**
- * Unbind the current render target texture from the webGL context
- * @param texture defines the render target wrapper to unbind
- * @param disableGenerateMipMaps defines a boolean indicating that mipmaps must not be generated
- * @param onBeforeUnbind defines a function which will be called before the effective unbind
- */
- unBindFramebuffer(texture, disableGenerateMipMaps = false, onBeforeUnbind) {
- const webglRTWrapper = texture;
- this._currentRenderTarget = null;
- // If MSAA, we need to bitblt back to main texture
- const gl = this._gl;
- if (webglRTWrapper._MSAAFramebuffer) {
- if (texture.isMulti) {
- // This texture is part of a MRT texture, we need to treat all attachments
- this.unBindMultiColorAttachmentFramebuffer(texture, disableGenerateMipMaps, onBeforeUnbind);
- return;
- }
- gl.bindFramebuffer(gl.READ_FRAMEBUFFER, webglRTWrapper._MSAAFramebuffer);
- gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, webglRTWrapper._framebuffer);
- gl.blitFramebuffer(0, 0, texture.width, texture.height, 0, 0, texture.width, texture.height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
- }
- if (texture.texture?.generateMipMaps && !disableGenerateMipMaps && !texture.isCube) {
- this.generateMipmaps(texture.texture);
- }
- if (onBeforeUnbind) {
- if (webglRTWrapper._MSAAFramebuffer) {
- // Bind the correct framebuffer
- this._bindUnboundFramebuffer(webglRTWrapper._framebuffer);
- }
- onBeforeUnbind();
- }
- this._bindUnboundFramebuffer(null);
- }
- /**
- * Force a webGL flush (ie. a flush of all waiting webGL commands)
- */
- flushFramebuffer() {
- this._gl.flush();
- }
- /**
- * Unbind the current render target and bind the default framebuffer
- */
- restoreDefaultFramebuffer() {
- if (this._currentRenderTarget) {
- this.unBindFramebuffer(this._currentRenderTarget);
- }
- else {
- this._bindUnboundFramebuffer(null);
- }
- if (this._cachedViewport) {
- this.setViewport(this._cachedViewport);
- }
- this.wipeCaches();
- }
- // VBOs
- /** @internal */
- _resetVertexBufferBinding() {
- this.bindArrayBuffer(null);
- this._cachedVertexBuffers = null;
- }
- /**
- * Creates a vertex buffer
- * @param data the data or size for the vertex buffer
- * @param _updatable whether the buffer should be created as updatable
- * @param _label defines the label of the buffer (for debug purpose)
- * @returns the new WebGL static buffer
- */
- createVertexBuffer(data, _updatable, _label) {
- return this._createVertexBuffer(data, this._gl.STATIC_DRAW);
- }
- _createVertexBuffer(data, usage) {
- const vbo = this._gl.createBuffer();
- if (!vbo) {
- throw new Error("Unable to create vertex buffer");
- }
- const dataBuffer = new WebGLDataBuffer(vbo);
- this.bindArrayBuffer(dataBuffer);
- if (typeof data !== "number") {
- if (data instanceof Array) {
- this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array(data), usage);
- dataBuffer.capacity = data.length * 4;
- }
- else {
- this._gl.bufferData(this._gl.ARRAY_BUFFER, data, usage);
- dataBuffer.capacity = data.byteLength;
- }
- }
- else {
- this._gl.bufferData(this._gl.ARRAY_BUFFER, new Uint8Array(data), usage);
- dataBuffer.capacity = data;
- }
- this._resetVertexBufferBinding();
- dataBuffer.references = 1;
- return dataBuffer;
- }
- /**
- * Creates a dynamic vertex buffer
- * @param data the data for the dynamic vertex buffer
- * @param _label defines the label of the buffer (for debug purpose)
- * @returns the new WebGL dynamic buffer
- */
- createDynamicVertexBuffer(data, _label) {
- return this._createVertexBuffer(data, this._gl.DYNAMIC_DRAW);
- }
- _resetIndexBufferBinding() {
- this.bindIndexBuffer(null);
- this._cachedIndexBuffer = null;
- }
- /**
- * Creates a new index buffer
- * @param indices defines the content of the index buffer
- * @param updatable defines if the index buffer must be updatable
- * @param _label defines the label of the buffer (for debug purpose)
- * @returns a new webGL buffer
- */
- createIndexBuffer(indices, updatable, _label) {
- const vbo = this._gl.createBuffer();
- const dataBuffer = new WebGLDataBuffer(vbo);
- if (!vbo) {
- throw new Error("Unable to create index buffer");
- }
- this.bindIndexBuffer(dataBuffer);
- const data = this._normalizeIndexData(indices);
- this._gl.bufferData(this._gl.ELEMENT_ARRAY_BUFFER, data, updatable ? this._gl.DYNAMIC_DRAW : this._gl.STATIC_DRAW);
- this._resetIndexBufferBinding();
- dataBuffer.references = 1;
- dataBuffer.is32Bits = data.BYTES_PER_ELEMENT === 4;
- return dataBuffer;
- }
- _normalizeIndexData(indices) {
- const bytesPerElement = indices.BYTES_PER_ELEMENT;
- if (bytesPerElement === 2) {
- return indices;
- }
- // Check 32 bit support
- if (this._caps.uintIndices) {
- if (indices instanceof Uint32Array) {
- return indices;
- }
- else {
- // number[] or Int32Array, check if 32 bit is necessary
- for (let index = 0; index < indices.length; index++) {
- if (indices[index] >= 65535) {
- return new Uint32Array(indices);
- }
- }
- return new Uint16Array(indices);
- }
- }
- // No 32 bit support, force conversion to 16 bit (values greater 16 bit are lost)
- return new Uint16Array(indices);
- }
- /**
- * Bind a webGL buffer to the webGL context
- * @param buffer defines the buffer to bind
- */
- bindArrayBuffer(buffer) {
- if (!this._vaoRecordInProgress) {
- this._unbindVertexArrayObject();
- }
- this._bindBuffer(buffer, this._gl.ARRAY_BUFFER);
- }
- /**
- * Bind a specific block at a given index in a specific shader program
- * @param pipelineContext defines the pipeline context to use
- * @param blockName defines the block name
- * @param index defines the index where to bind the block
- */
- bindUniformBlock(pipelineContext, blockName, index) {
- const program = pipelineContext.program;
- const uniformLocation = this._gl.getUniformBlockIndex(program, blockName);
- this._gl.uniformBlockBinding(program, uniformLocation, index);
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- bindIndexBuffer(buffer) {
- if (!this._vaoRecordInProgress) {
- this._unbindVertexArrayObject();
- }
- this._bindBuffer(buffer, this._gl.ELEMENT_ARRAY_BUFFER);
- }
- _bindBuffer(buffer, target) {
- if (this._vaoRecordInProgress || this._currentBoundBuffer[target] !== buffer) {
- this._gl.bindBuffer(target, buffer ? buffer.underlyingResource : null);
- this._currentBoundBuffer[target] = buffer;
- }
- }
- /**
- * update the bound buffer with the given data
- * @param data defines the data to update
- */
- updateArrayBuffer(data) {
- this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, data);
- }
- _vertexAttribPointer(buffer, indx, size, type, normalized, stride, offset) {
- const pointer = this._currentBufferPointers[indx];
- if (!pointer) {
- return;
- }
- let changed = false;
- if (!pointer.active) {
- changed = true;
- pointer.active = true;
- pointer.index = indx;
- pointer.size = size;
- pointer.type = type;
- pointer.normalized = normalized;
- pointer.stride = stride;
- pointer.offset = offset;
- pointer.buffer = buffer;
- }
- else {
- if (pointer.buffer !== buffer) {
- pointer.buffer = buffer;
- changed = true;
- }
- if (pointer.size !== size) {
- pointer.size = size;
- changed = true;
- }
- if (pointer.type !== type) {
- pointer.type = type;
- changed = true;
- }
- if (pointer.normalized !== normalized) {
- pointer.normalized = normalized;
- changed = true;
- }
- if (pointer.stride !== stride) {
- pointer.stride = stride;
- changed = true;
- }
- if (pointer.offset !== offset) {
- pointer.offset = offset;
- changed = true;
- }
- }
- if (changed || this._vaoRecordInProgress) {
- this.bindArrayBuffer(buffer);
- if (type === this._gl.UNSIGNED_INT || type === this._gl.INT) {
- this._gl.vertexAttribIPointer(indx, size, type, stride, offset);
- }
- else {
- this._gl.vertexAttribPointer(indx, size, type, normalized, stride, offset);
- }
- }
- }
- /**
- * @internal
- */
- _bindIndexBufferWithCache(indexBuffer) {
- if (indexBuffer == null) {
- return;
- }
- if (this._cachedIndexBuffer !== indexBuffer) {
- this._cachedIndexBuffer = indexBuffer;
- this.bindIndexBuffer(indexBuffer);
- this._uintIndicesCurrentlySet = indexBuffer.is32Bits;
- }
- }
- _bindVertexBuffersAttributes(vertexBuffers, effect, overrideVertexBuffers) {
- const attributes = effect.getAttributesNames();
- if (!this._vaoRecordInProgress) {
- this._unbindVertexArrayObject();
- }
- this.unbindAllAttributes();
- for (let index = 0; index < attributes.length; index++) {
- const order = effect.getAttributeLocation(index);
- if (order >= 0) {
- const ai = attributes[index];
- let vertexBuffer = null;
- if (overrideVertexBuffers) {
- vertexBuffer = overrideVertexBuffers[ai];
- }
- if (!vertexBuffer) {
- vertexBuffer = vertexBuffers[ai];
- }
- if (!vertexBuffer) {
- continue;
- }
- this._gl.enableVertexAttribArray(order);
- if (!this._vaoRecordInProgress) {
- this._vertexAttribArraysEnabled[order] = true;
- }
- const buffer = vertexBuffer.getBuffer();
- if (buffer) {
- this._vertexAttribPointer(buffer, order, vertexBuffer.getSize(), vertexBuffer.type, vertexBuffer.normalized, vertexBuffer.byteStride, vertexBuffer.byteOffset);
- if (vertexBuffer.getIsInstanced()) {
- this._gl.vertexAttribDivisor(order, vertexBuffer.getInstanceDivisor());
- if (!this._vaoRecordInProgress) {
- this._currentInstanceLocations.push(order);
- this._currentInstanceBuffers.push(buffer);
- }
- }
- }
- }
- }
- }
- /**
- * Records a vertex array object
- * @see https://doc.babylonjs.com/setup/support/webGL2#vertex-array-objects
- * @param vertexBuffers defines the list of vertex buffers to store
- * @param indexBuffer defines the index buffer to store
- * @param effect defines the effect to store
- * @param overrideVertexBuffers defines optional list of avertex buffers that overrides the entries in vertexBuffers
- * @returns the new vertex array object
- */
- recordVertexArrayObject(vertexBuffers, indexBuffer, effect, overrideVertexBuffers) {
- const vao = this._gl.createVertexArray();
- if (!vao) {
- throw new Error("Unable to create VAO");
- }
- this._vaoRecordInProgress = true;
- this._gl.bindVertexArray(vao);
- this._mustWipeVertexAttributes = true;
- this._bindVertexBuffersAttributes(vertexBuffers, effect, overrideVertexBuffers);
- this.bindIndexBuffer(indexBuffer);
- this._vaoRecordInProgress = false;
- this._gl.bindVertexArray(null);
- return vao;
- }
- /**
- * Bind a specific vertex array object
- * @see https://doc.babylonjs.com/setup/support/webGL2#vertex-array-objects
- * @param vertexArrayObject defines the vertex array object to bind
- * @param indexBuffer defines the index buffer to bind
- */
- bindVertexArrayObject(vertexArrayObject, indexBuffer) {
- if (this._cachedVertexArrayObject !== vertexArrayObject) {
- this._cachedVertexArrayObject = vertexArrayObject;
- this._gl.bindVertexArray(vertexArrayObject);
- this._cachedVertexBuffers = null;
- this._cachedIndexBuffer = null;
- this._uintIndicesCurrentlySet = indexBuffer != null && indexBuffer.is32Bits;
- this._mustWipeVertexAttributes = true;
- }
- }
- /**
- * Bind webGl buffers directly to the webGL context
- * @param vertexBuffer defines the vertex buffer to bind
- * @param indexBuffer defines the index buffer to bind
- * @param vertexDeclaration defines the vertex declaration to use with the vertex buffer
- * @param vertexStrideSize defines the vertex stride of the vertex buffer
- * @param effect defines the effect associated with the vertex buffer
- */
- bindBuffersDirectly(vertexBuffer, indexBuffer, vertexDeclaration, vertexStrideSize, effect) {
- if (this._cachedVertexBuffers !== vertexBuffer || this._cachedEffectForVertexBuffers !== effect) {
- this._cachedVertexBuffers = vertexBuffer;
- this._cachedEffectForVertexBuffers = effect;
- const attributesCount = effect.getAttributesCount();
- this._unbindVertexArrayObject();
- this.unbindAllAttributes();
- let offset = 0;
- for (let index = 0; index < attributesCount; index++) {
- if (index < vertexDeclaration.length) {
- const order = effect.getAttributeLocation(index);
- if (order >= 0) {
- this._gl.enableVertexAttribArray(order);
- this._vertexAttribArraysEnabled[order] = true;
- this._vertexAttribPointer(vertexBuffer, order, vertexDeclaration[index], this._gl.FLOAT, false, vertexStrideSize, offset);
- }
- offset += vertexDeclaration[index] * 4;
- }
- }
- }
- this._bindIndexBufferWithCache(indexBuffer);
- }
- _unbindVertexArrayObject() {
- if (!this._cachedVertexArrayObject) {
- return;
- }
- this._cachedVertexArrayObject = null;
- this._gl.bindVertexArray(null);
- }
- /**
- * Bind a list of vertex buffers to the webGL context
- * @param vertexBuffers defines the list of vertex buffers to bind
- * @param indexBuffer defines the index buffer to bind
- * @param effect defines the effect associated with the vertex buffers
- * @param overrideVertexBuffers defines optional list of avertex buffers that overrides the entries in vertexBuffers
- */
- bindBuffers(vertexBuffers, indexBuffer, effect, overrideVertexBuffers) {
- if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
- this._cachedVertexBuffers = vertexBuffers;
- this._cachedEffectForVertexBuffers = effect;
- this._bindVertexBuffersAttributes(vertexBuffers, effect, overrideVertexBuffers);
- }
- this._bindIndexBufferWithCache(indexBuffer);
- }
- /**
- * Unbind all instance attributes
- */
- unbindInstanceAttributes() {
- let boundBuffer;
- for (let i = 0, ul = this._currentInstanceLocations.length; i < ul; i++) {
- const instancesBuffer = this._currentInstanceBuffers[i];
- if (boundBuffer != instancesBuffer && instancesBuffer.references) {
- boundBuffer = instancesBuffer;
- this.bindArrayBuffer(instancesBuffer);
- }
- const offsetLocation = this._currentInstanceLocations[i];
- this._gl.vertexAttribDivisor(offsetLocation, 0);
- }
- this._currentInstanceBuffers.length = 0;
- this._currentInstanceLocations.length = 0;
- }
- /**
- * Release and free the memory of a vertex array object
- * @param vao defines the vertex array object to delete
- */
- releaseVertexArrayObject(vao) {
- this._gl.deleteVertexArray(vao);
- }
- /**
- * @internal
- */
- _releaseBuffer(buffer) {
- buffer.references--;
- if (buffer.references === 0) {
- this._deleteBuffer(buffer);
- return true;
- }
- return false;
- }
- _deleteBuffer(buffer) {
- this._gl.deleteBuffer(buffer.underlyingResource);
- }
- /**
- * Update the content of a webGL buffer used with instantiation and bind it to the webGL context
- * @param instancesBuffer defines the webGL buffer to update and bind
- * @param data defines the data to store in the buffer
- * @param offsetLocations defines the offsets or attributes information used to determine where data must be stored in the buffer
- */
- updateAndBindInstancesBuffer(instancesBuffer, data, offsetLocations) {
- this.bindArrayBuffer(instancesBuffer);
- if (data) {
- this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, data);
- }
- if (offsetLocations[0].index !== undefined) {
- this.bindInstancesBuffer(instancesBuffer, offsetLocations, true);
- }
- else {
- for (let index = 0; index < 4; index++) {
- const offsetLocation = offsetLocations[index];
- if (!this._vertexAttribArraysEnabled[offsetLocation]) {
- this._gl.enableVertexAttribArray(offsetLocation);
- this._vertexAttribArraysEnabled[offsetLocation] = true;
- }
- this._vertexAttribPointer(instancesBuffer, offsetLocation, 4, this._gl.FLOAT, false, 64, index * 16);
- this._gl.vertexAttribDivisor(offsetLocation, 1);
- this._currentInstanceLocations.push(offsetLocation);
- this._currentInstanceBuffers.push(instancesBuffer);
- }
- }
- }
- /**
- * Bind the content of a webGL buffer used with instantiation
- * @param instancesBuffer defines the webGL buffer to bind
- * @param attributesInfo defines the offsets or attributes information used to determine where data must be stored in the buffer
- * @param computeStride defines Whether to compute the strides from the info or use the default 0
- */
- bindInstancesBuffer(instancesBuffer, attributesInfo, computeStride = true) {
- this.bindArrayBuffer(instancesBuffer);
- let stride = 0;
- if (computeStride) {
- for (let i = 0; i < attributesInfo.length; i++) {
- const ai = attributesInfo[i];
- stride += ai.attributeSize * 4;
- }
- }
- for (let i = 0; i < attributesInfo.length; i++) {
- const ai = attributesInfo[i];
- if (ai.index === undefined) {
- ai.index = this._currentEffect.getAttributeLocationByName(ai.attributeName);
- }
- if (ai.index < 0) {
- continue;
- }
- if (!this._vertexAttribArraysEnabled[ai.index]) {
- this._gl.enableVertexAttribArray(ai.index);
- this._vertexAttribArraysEnabled[ai.index] = true;
- }
- this._vertexAttribPointer(instancesBuffer, ai.index, ai.attributeSize, ai.attributeType || this._gl.FLOAT, ai.normalized || false, stride, ai.offset);
- this._gl.vertexAttribDivisor(ai.index, ai.divisor === undefined ? 1 : ai.divisor);
- this._currentInstanceLocations.push(ai.index);
- this._currentInstanceBuffers.push(instancesBuffer);
- }
- }
- /**
- * Disable the instance attribute corresponding to the name in parameter
- * @param name defines the name of the attribute to disable
- */
- disableInstanceAttributeByName(name) {
- if (!this._currentEffect) {
- return;
- }
- const attributeLocation = this._currentEffect.getAttributeLocationByName(name);
- this.disableInstanceAttribute(attributeLocation);
- }
- /**
- * Disable the instance attribute corresponding to the location in parameter
- * @param attributeLocation defines the attribute location of the attribute to disable
- */
- disableInstanceAttribute(attributeLocation) {
- let shouldClean = false;
- let index;
- while ((index = this._currentInstanceLocations.indexOf(attributeLocation)) !== -1) {
- this._currentInstanceLocations.splice(index, 1);
- this._currentInstanceBuffers.splice(index, 1);
- shouldClean = true;
- index = this._currentInstanceLocations.indexOf(attributeLocation);
- }
- if (shouldClean) {
- this._gl.vertexAttribDivisor(attributeLocation, 0);
- this.disableAttributeByIndex(attributeLocation);
- }
- }
- /**
- * Disable the attribute corresponding to the location in parameter
- * @param attributeLocation defines the attribute location of the attribute to disable
- */
- disableAttributeByIndex(attributeLocation) {
- this._gl.disableVertexAttribArray(attributeLocation);
- this._vertexAttribArraysEnabled[attributeLocation] = false;
- this._currentBufferPointers[attributeLocation].active = false;
- }
- /**
- * Send a draw order
- * @param useTriangles defines if triangles must be used to draw (else wireframe will be used)
- * @param indexStart defines the starting index
- * @param indexCount defines the number of index to draw
- * @param instancesCount defines the number of instances to draw (if instantiation is enabled)
- */
- draw(useTriangles, indexStart, indexCount, instancesCount) {
- this.drawElementsType(useTriangles ? 0 : 1, indexStart, indexCount, instancesCount);
- }
- /**
- * Draw a list of points
- * @param verticesStart defines the index of first vertex to draw
- * @param verticesCount defines the count of vertices to draw
- * @param instancesCount defines the number of instances to draw (if instantiation is enabled)
- */
- drawPointClouds(verticesStart, verticesCount, instancesCount) {
- this.drawArraysType(2, verticesStart, verticesCount, instancesCount);
- }
- /**
- * Draw a list of unindexed primitives
- * @param useTriangles defines if triangles must be used to draw (else wireframe will be used)
- * @param verticesStart defines the index of first vertex to draw
- * @param verticesCount defines the count of vertices to draw
- * @param instancesCount defines the number of instances to draw (if instantiation is enabled)
- */
- drawUnIndexed(useTriangles, verticesStart, verticesCount, instancesCount) {
- this.drawArraysType(useTriangles ? 0 : 1, verticesStart, verticesCount, instancesCount);
- }
- /**
- * Draw a list of indexed primitives
- * @param fillMode defines the primitive to use
- * @param indexStart defines the starting index
- * @param indexCount defines the number of index to draw
- * @param instancesCount defines the number of instances to draw (if instantiation is enabled)
- */
- drawElementsType(fillMode, indexStart, indexCount, instancesCount) {
- // Apply states
- this.applyStates();
- this._reportDrawCall();
- // Render
- const drawMode = this._drawMode(fillMode);
- const indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
- const mult = this._uintIndicesCurrentlySet ? 4 : 2;
- if (instancesCount) {
- this._gl.drawElementsInstanced(drawMode, indexCount, indexFormat, indexStart * mult, instancesCount);
- }
- else {
- this._gl.drawElements(drawMode, indexCount, indexFormat, indexStart * mult);
- }
- }
- /**
- * Draw a list of unindexed primitives
- * @param fillMode defines the primitive to use
- * @param verticesStart defines the index of first vertex to draw
- * @param verticesCount defines the count of vertices to draw
- * @param instancesCount defines the number of instances to draw (if instantiation is enabled)
- */
- drawArraysType(fillMode, verticesStart, verticesCount, instancesCount) {
- // Apply states
- this.applyStates();
- this._reportDrawCall();
- const drawMode = this._drawMode(fillMode);
- if (instancesCount) {
- this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
- }
- else {
- this._gl.drawArrays(drawMode, verticesStart, verticesCount);
- }
- }
- _drawMode(fillMode) {
- switch (fillMode) {
- // Triangle views
- case 0:
- return this._gl.TRIANGLES;
- case 2:
- return this._gl.POINTS;
- case 1:
- return this._gl.LINES;
- // Draw modes
- case 3:
- return this._gl.POINTS;
- case 4:
- return this._gl.LINES;
- case 5:
- return this._gl.LINE_LOOP;
- case 6:
- return this._gl.LINE_STRIP;
- case 7:
- return this._gl.TRIANGLE_STRIP;
- case 8:
- return this._gl.TRIANGLE_FAN;
- default:
- return this._gl.TRIANGLES;
- }
- }
- // Shaders
- /**
- * @internal
- */
- _releaseEffect(effect) {
- if (this._compiledEffects[effect._key]) {
- delete this._compiledEffects[effect._key];
- }
- const pipelineContext = effect.getPipelineContext();
- if (pipelineContext) {
- this._deletePipelineContext(pipelineContext);
- }
- }
- /**
- * @internal
- */
- _deletePipelineContext(pipelineContext) {
- const webGLPipelineContext = pipelineContext;
- if (webGLPipelineContext && webGLPipelineContext.program) {
- webGLPipelineContext.program.__SPECTOR_rebuildProgram = null;
- this._gl.deleteProgram(webGLPipelineContext.program);
- }
- }
- /**
- * Create a new effect (used to store vertex/fragment shaders)
- * @param baseName defines the base name of the effect (The name of file without .fragment.fx or .vertex.fx)
- * @param attributesNamesOrOptions defines either a list of attribute names or an IEffectCreationOptions object
- * @param uniformsNamesOrEngine defines either a list of uniform names or the engine to use
- * @param samplers defines an array of string used to represent textures
- * @param defines defines the string containing the defines to use to compile the shaders
- * @param fallbacks defines the list of potential fallbacks to use if shader compilation fails
- * @param onCompiled defines a function to call when the effect creation is successful
- * @param onError defines a function to call when the effect creation has failed
- * @param indexParameters defines an object containing the index values to use to compile shaders (like the maximum number of simultaneous lights)
- * @param shaderLanguage the language the shader is written in (default: GLSL)
- * @returns the new Effect
- */
- createEffect(baseName, attributesNamesOrOptions, uniformsNamesOrEngine, samplers, defines, fallbacks, onCompiled, onError, indexParameters, shaderLanguage = ShaderLanguage.GLSL) {
- const vertex = typeof baseName === "string" ? baseName : baseName.vertexToken || baseName.vertexSource || baseName.vertexElement || baseName.vertex;
- const fragment = typeof baseName === "string" ? baseName : baseName.fragmentToken || baseName.fragmentSource || baseName.fragmentElement || baseName.fragment;
- const globalDefines = this._getGlobalDefines();
- let fullDefines = defines ?? attributesNamesOrOptions.defines ?? "";
- if (globalDefines) {
- fullDefines += globalDefines;
- }
- const name = vertex + "+" + fragment + "@" + fullDefines;
- if (this._compiledEffects[name]) {
- const compiledEffect = this._compiledEffects[name];
- if (onCompiled && compiledEffect.isReady()) {
- onCompiled(compiledEffect);
- }
- return compiledEffect;
- }
- const effect = new Effect(baseName, attributesNamesOrOptions, uniformsNamesOrEngine, samplers, this, defines, fallbacks, onCompiled, onError, indexParameters, name, shaderLanguage);
- this._compiledEffects[name] = effect;
- return effect;
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- static _ConcatenateShader(source, defines, shaderVersion = "") {
- return shaderVersion + (defines ? defines + "\n" : "") + source;
- }
- _compileShader(source, type, defines, shaderVersion) {
- return this._compileRawShader(ThinEngine._ConcatenateShader(source, defines, shaderVersion), type);
- }
- _compileRawShader(source, type) {
- const gl = this._gl;
- const shader = gl.createShader(type === "vertex" ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
- if (!shader) {
- let error = gl.NO_ERROR;
- let tempError = gl.NO_ERROR;
- while ((tempError = gl.getError()) !== gl.NO_ERROR) {
- error = tempError;
- }
- throw new Error(`Something went wrong while creating a gl ${type} shader object. gl error=${error}, gl isContextLost=${gl.isContextLost()}, _contextWasLost=${this._contextWasLost}`);
- }
- gl.shaderSource(shader, source);
- gl.compileShader(shader);
- return shader;
- }
- /**
- * @internal
- */
- _getShaderSource(shader) {
- return this._gl.getShaderSource(shader);
- }
- /**
- * Directly creates a webGL program
- * @param pipelineContext defines the pipeline context to attach to
- * @param vertexCode defines the vertex shader code to use
- * @param fragmentCode defines the fragment shader code to use
- * @param context defines the webGL context to use (if not set, the current one will be used)
- * @param transformFeedbackVaryings defines the list of transform feedback varyings to use
- * @returns the new webGL program
- */
- createRawShaderProgram(pipelineContext, vertexCode, fragmentCode, context, transformFeedbackVaryings = null) {
- context = context || this._gl;
- const vertexShader = this._compileRawShader(vertexCode, "vertex");
- const fragmentShader = this._compileRawShader(fragmentCode, "fragment");
- return this._createShaderProgram(pipelineContext, vertexShader, fragmentShader, context, transformFeedbackVaryings);
- }
- /**
- * Creates a webGL program
- * @param pipelineContext defines the pipeline context to attach to
- * @param vertexCode defines the vertex shader code to use
- * @param fragmentCode defines the fragment shader code to use
- * @param defines defines the string containing the defines to use to compile the shaders
- * @param context defines the webGL context to use (if not set, the current one will be used)
- * @param transformFeedbackVaryings defines the list of transform feedback varyings to use
- * @returns the new webGL program
- */
- createShaderProgram(pipelineContext, vertexCode, fragmentCode, defines, context, transformFeedbackVaryings = null) {
- context = context || this._gl;
- const shaderVersion = this._webGLVersion > 1 ? "#version 300 es\n#define WEBGL2 \n" : "";
- const vertexShader = this._compileShader(vertexCode, "vertex", defines, shaderVersion);
- const fragmentShader = this._compileShader(fragmentCode, "fragment", defines, shaderVersion);
- return this._createShaderProgram(pipelineContext, vertexShader, fragmentShader, context, transformFeedbackVaryings);
- }
- /**
- * Inline functions in shader code that are marked to be inlined
- * @param code code to inline
- * @returns inlined code
- */
- inlineShaderCode(code) {
- // no inlining needed in the WebGL engine
- return code;
- }
- /**
- * Creates a new pipeline context
- * @param shaderProcessingContext defines the shader processing context used during the processing if available
- * @returns the new pipeline
- */
- createPipelineContext(shaderProcessingContext) {
- const pipelineContext = new WebGLPipelineContext();
- pipelineContext.engine = this;
- if (this._caps.parallelShaderCompile) {
- pipelineContext.isParallelCompiled = true;
- }
- return pipelineContext;
- }
- /**
- * Creates a new material context
- * @returns the new context
- */
- createMaterialContext() {
- return undefined;
- }
- /**
- * Creates a new draw context
- * @returns the new context
- */
- createDrawContext() {
- return undefined;
- }
- _createShaderProgram(pipelineContext, vertexShader, fragmentShader, context, transformFeedbackVaryings = null) {
- const shaderProgram = context.createProgram();
- pipelineContext.program = shaderProgram;
- if (!shaderProgram) {
- throw new Error("Unable to create program");
- }
- context.attachShader(shaderProgram, vertexShader);
- context.attachShader(shaderProgram, fragmentShader);
- context.linkProgram(shaderProgram);
- pipelineContext.context = context;
- pipelineContext.vertexShader = vertexShader;
- pipelineContext.fragmentShader = fragmentShader;
- if (!pipelineContext.isParallelCompiled) {
- this._finalizePipelineContext(pipelineContext);
- }
- return shaderProgram;
- }
- _finalizePipelineContext(pipelineContext) {
- const context = pipelineContext.context;
- const vertexShader = pipelineContext.vertexShader;
- const fragmentShader = pipelineContext.fragmentShader;
- const program = pipelineContext.program;
- const linked = context.getProgramParameter(program, context.LINK_STATUS);
- if (!linked) {
- // Get more info
- // Vertex
- if (!this._gl.getShaderParameter(vertexShader, this._gl.COMPILE_STATUS)) {
- const log = this._gl.getShaderInfoLog(vertexShader);
- if (log) {
- pipelineContext.vertexCompilationError = log;
- throw new Error("VERTEX SHADER " + log);
- }
- }
- // Fragment
- if (!this._gl.getShaderParameter(fragmentShader, this._gl.COMPILE_STATUS)) {
- const log = this._gl.getShaderInfoLog(fragmentShader);
- if (log) {
- pipelineContext.fragmentCompilationError = log;
- throw new Error("FRAGMENT SHADER " + log);
- }
- }
- const error = context.getProgramInfoLog(program);
- if (error) {
- pipelineContext.programLinkError = error;
- throw new Error(error);
- }
- }
- if (this.validateShaderPrograms) {
- context.validateProgram(program);
- const validated = context.getProgramParameter(program, context.VALIDATE_STATUS);
- if (!validated) {
- const error = context.getProgramInfoLog(program);
- if (error) {
- pipelineContext.programValidationError = error;
- throw new Error(error);
- }
- }
- }
- context.deleteShader(vertexShader);
- context.deleteShader(fragmentShader);
- pipelineContext.vertexShader = undefined;
- pipelineContext.fragmentShader = undefined;
- if (pipelineContext.onCompiled) {
- pipelineContext.onCompiled();
- pipelineContext.onCompiled = undefined;
- }
- }
- /**
- * @internal
- */
- _preparePipelineContext(pipelineContext, vertexSourceCode, fragmentSourceCode, createAsRaw, rawVertexSourceCode, rawFragmentSourceCode, rebuildRebind, defines, transformFeedbackVaryings, key) {
- const webGLRenderingState = pipelineContext;
- if (createAsRaw) {
- webGLRenderingState.program = this.createRawShaderProgram(webGLRenderingState, vertexSourceCode, fragmentSourceCode, undefined, transformFeedbackVaryings);
- }
- else {
- webGLRenderingState.program = this.createShaderProgram(webGLRenderingState, vertexSourceCode, fragmentSourceCode, defines, undefined, transformFeedbackVaryings);
- }
- webGLRenderingState.program.__SPECTOR_rebuildProgram = rebuildRebind;
- }
- /**
- * @internal
- */
- _isRenderingStateCompiled(pipelineContext) {
- const webGLPipelineContext = pipelineContext;
- if (this._isDisposed || webGLPipelineContext._isDisposed) {
- return false;
- }
- if (this._gl.getProgramParameter(webGLPipelineContext.program, this._caps.parallelShaderCompile.COMPLETION_STATUS_KHR)) {
- this._finalizePipelineContext(webGLPipelineContext);
- return true;
- }
- return false;
- }
- /**
- * @internal
- */
- _executeWhenRenderingStateIsCompiled(pipelineContext, action) {
- const webGLPipelineContext = pipelineContext;
- if (!webGLPipelineContext.isParallelCompiled) {
- action();
- return;
- }
- const oldHandler = webGLPipelineContext.onCompiled;
- if (oldHandler) {
- webGLPipelineContext.onCompiled = () => {
- oldHandler();
- action();
- };
- }
- else {
- webGLPipelineContext.onCompiled = action;
- }
- }
- /**
- * Gets the list of webGL uniform locations associated with a specific program based on a list of uniform names
- * @param pipelineContext defines the pipeline context to use
- * @param uniformsNames defines the list of uniform names
- * @returns an array of webGL uniform locations
- */
- getUniforms(pipelineContext, uniformsNames) {
- const results = new Array();
- const webGLPipelineContext = pipelineContext;
- for (let index = 0; index < uniformsNames.length; index++) {
- results.push(this._gl.getUniformLocation(webGLPipelineContext.program, uniformsNames[index]));
- }
- return results;
- }
- /**
- * Gets the list of active attributes for a given webGL program
- * @param pipelineContext defines the pipeline context to use
- * @param attributesNames defines the list of attribute names to get
- * @returns an array of indices indicating the offset of each attribute
- */
- getAttributes(pipelineContext, attributesNames) {
- const results = [];
- const webGLPipelineContext = pipelineContext;
- for (let index = 0; index < attributesNames.length; index++) {
- try {
- results.push(this._gl.getAttribLocation(webGLPipelineContext.program, attributesNames[index]));
- }
- catch (e) {
- results.push(-1);
- }
- }
- return results;
- }
- /**
- * Activates an effect, making it the current one (ie. the one used for rendering)
- * @param effect defines the effect to activate
- */
- enableEffect(effect) {
- effect = effect !== null && IsWrapper(effect) ? effect.effect : effect; // get only the effect, we don't need a Wrapper in the WebGL engine
- if (!effect || effect === this._currentEffect) {
- return;
- }
- this._stencilStateComposer.stencilMaterial = undefined;
- effect = effect;
- // Use program
- this.bindSamplers(effect);
- this._currentEffect = effect;
- if (effect.onBind) {
- effect.onBind(effect);
- }
- if (effect._onBindObservable) {
- effect._onBindObservable.notifyObservers(effect);
- }
- }
- /**
- * Set the value of an uniform to a number (int)
- * @param uniform defines the webGL uniform location where to store the value
- * @param value defines the int number to store
- * @returns true if the value was set
- */
- setInt(uniform, value) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform1i(uniform, value);
- return true;
- }
- /**
- * Set the value of an uniform to a int2
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @returns true if the value was set
- */
- setInt2(uniform, x, y) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform2i(uniform, x, y);
- return true;
- }
- /**
- * Set the value of an uniform to a int3
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @param z defines the 3rd component of the value
- * @returns true if the value was set
- */
- setInt3(uniform, x, y, z) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform3i(uniform, x, y, z);
- return true;
- }
- /**
- * Set the value of an uniform to a int4
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @param z defines the 3rd component of the value
- * @param w defines the 4th component of the value
- * @returns true if the value was set
- */
- setInt4(uniform, x, y, z, w) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform4i(uniform, x, y, z, w);
- return true;
- }
- /**
- * Set the value of an uniform to an array of int32
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of int32 to store
- * @returns true if the value was set
- */
- setIntArray(uniform, array) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform1iv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of int32 (stored as vec2)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of int32 to store
- * @returns true if the value was set
- */
- setIntArray2(uniform, array) {
- if (!uniform || array.length % 2 !== 0) {
- return false;
- }
- this._gl.uniform2iv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of int32 (stored as vec3)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of int32 to store
- * @returns true if the value was set
- */
- setIntArray3(uniform, array) {
- if (!uniform || array.length % 3 !== 0) {
- return false;
- }
- this._gl.uniform3iv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of int32 (stored as vec4)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of int32 to store
- * @returns true if the value was set
- */
- setIntArray4(uniform, array) {
- if (!uniform || array.length % 4 !== 0) {
- return false;
- }
- this._gl.uniform4iv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to a number (unsigned int)
- * @param uniform defines the webGL uniform location where to store the value
- * @param value defines the unsigned int number to store
- * @returns true if the value was set
- */
- setUInt(uniform, value) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform1ui(uniform, value);
- return true;
- }
- /**
- * Set the value of an uniform to a unsigned int2
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @returns true if the value was set
- */
- setUInt2(uniform, x, y) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform2ui(uniform, x, y);
- return true;
- }
- /**
- * Set the value of an uniform to a unsigned int3
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @param z defines the 3rd component of the value
- * @returns true if the value was set
- */
- setUInt3(uniform, x, y, z) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform3ui(uniform, x, y, z);
- return true;
- }
- /**
- * Set the value of an uniform to a unsigned int4
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @param z defines the 3rd component of the value
- * @param w defines the 4th component of the value
- * @returns true if the value was set
- */
- setUInt4(uniform, x, y, z, w) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform4ui(uniform, x, y, z, w);
- return true;
- }
- /**
- * Set the value of an uniform to an array of unsigned int32
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of unsigned int32 to store
- * @returns true if the value was set
- */
- setUIntArray(uniform, array) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform1uiv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of unsigned int32 (stored as vec2)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of unsigned int32 to store
- * @returns true if the value was set
- */
- setUIntArray2(uniform, array) {
- if (!uniform || array.length % 2 !== 0) {
- return false;
- }
- this._gl.uniform2uiv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of unsigned int32 (stored as vec3)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of unsigned int32 to store
- * @returns true if the value was set
- */
- setUIntArray3(uniform, array) {
- if (!uniform || array.length % 3 !== 0) {
- return false;
- }
- this._gl.uniform3uiv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of unsigned int32 (stored as vec4)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of unsigned int32 to store
- * @returns true if the value was set
- */
- setUIntArray4(uniform, array) {
- if (!uniform || array.length % 4 !== 0) {
- return false;
- }
- this._gl.uniform4uiv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of number
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of number to store
- * @returns true if the value was set
- */
- setArray(uniform, array) {
- if (!uniform) {
- return false;
- }
- if (array.length < 1) {
- return false;
- }
- this._gl.uniform1fv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of number (stored as vec2)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of number to store
- * @returns true if the value was set
- */
- setArray2(uniform, array) {
- if (!uniform || array.length % 2 !== 0) {
- return false;
- }
- this._gl.uniform2fv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of number (stored as vec3)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of number to store
- * @returns true if the value was set
- */
- setArray3(uniform, array) {
- if (!uniform || array.length % 3 !== 0) {
- return false;
- }
- this._gl.uniform3fv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of number (stored as vec4)
- * @param uniform defines the webGL uniform location where to store the value
- * @param array defines the array of number to store
- * @returns true if the value was set
- */
- setArray4(uniform, array) {
- if (!uniform || array.length % 4 !== 0) {
- return false;
- }
- this._gl.uniform4fv(uniform, array);
- return true;
- }
- /**
- * Set the value of an uniform to an array of float32 (stored as matrices)
- * @param uniform defines the webGL uniform location where to store the value
- * @param matrices defines the array of float32 to store
- * @returns true if the value was set
- */
- setMatrices(uniform, matrices) {
- if (!uniform) {
- return false;
- }
- this._gl.uniformMatrix4fv(uniform, false, matrices);
- return true;
- }
- /**
- * Set the value of an uniform to a matrix (3x3)
- * @param uniform defines the webGL uniform location where to store the value
- * @param matrix defines the Float32Array representing the 3x3 matrix to store
- * @returns true if the value was set
- */
- setMatrix3x3(uniform, matrix) {
- if (!uniform) {
- return false;
- }
- this._gl.uniformMatrix3fv(uniform, false, matrix);
- return true;
- }
- /**
- * Set the value of an uniform to a matrix (2x2)
- * @param uniform defines the webGL uniform location where to store the value
- * @param matrix defines the Float32Array representing the 2x2 matrix to store
- * @returns true if the value was set
- */
- setMatrix2x2(uniform, matrix) {
- if (!uniform) {
- return false;
- }
- this._gl.uniformMatrix2fv(uniform, false, matrix);
- return true;
- }
- /**
- * Set the value of an uniform to a number (float)
- * @param uniform defines the webGL uniform location where to store the value
- * @param value defines the float number to store
- * @returns true if the value was transferred
- */
- setFloat(uniform, value) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform1f(uniform, value);
- return true;
- }
- /**
- * Set the value of an uniform to a vec2
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @returns true if the value was set
- */
- setFloat2(uniform, x, y) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform2f(uniform, x, y);
- return true;
- }
- /**
- * Set the value of an uniform to a vec3
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @param z defines the 3rd component of the value
- * @returns true if the value was set
- */
- setFloat3(uniform, x, y, z) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform3f(uniform, x, y, z);
- return true;
- }
- /**
- * Set the value of an uniform to a vec4
- * @param uniform defines the webGL uniform location where to store the value
- * @param x defines the 1st component of the value
- * @param y defines the 2nd component of the value
- * @param z defines the 3rd component of the value
- * @param w defines the 4th component of the value
- * @returns true if the value was set
- */
- setFloat4(uniform, x, y, z, w) {
- if (!uniform) {
- return false;
- }
- this._gl.uniform4f(uniform, x, y, z, w);
- return true;
- }
- // States
- /**
- * Apply all cached states (depth, culling, stencil and alpha)
- */
- applyStates() {
- this._depthCullingState.apply(this._gl);
- this._stencilStateComposer.apply(this._gl);
- this._alphaState.apply(this._gl);
- if (this._colorWriteChanged) {
- this._colorWriteChanged = false;
- const enable = this._colorWrite;
- this._gl.colorMask(enable, enable, enable, enable);
- }
- }
- // Textures
- /**
- * Force the entire cache to be cleared
- * You should not have to use this function unless your engine needs to share the webGL context with another engine
- * @param bruteForce defines a boolean to force clearing ALL caches (including stencil, detoh and alpha states)
- */
- wipeCaches(bruteForce) {
- if (this.preventCacheWipeBetweenFrames && !bruteForce) {
- return;
- }
- this._currentEffect = null;
- this._viewportCached.x = 0;
- this._viewportCached.y = 0;
- this._viewportCached.z = 0;
- this._viewportCached.w = 0;
- // Done before in case we clean the attributes
- this._unbindVertexArrayObject();
- if (bruteForce) {
- this._currentProgram = null;
- this.resetTextureCache();
- this._stencilStateComposer.reset();
- this._depthCullingState.reset();
- this._depthCullingState.depthFunc = this._gl.LEQUAL;
- this._alphaState.reset();
- this._alphaMode = 1;
- this._alphaEquation = 0;
- this._colorWrite = true;
- this._colorWriteChanged = true;
- this._unpackFlipYCached = null;
- this._gl.pixelStorei(this._gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, this._gl.NONE);
- this._gl.pixelStorei(this._gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0);
- this._mustWipeVertexAttributes = true;
- this.unbindAllAttributes();
- }
- this._resetVertexBufferBinding();
- this._cachedIndexBuffer = null;
- this._cachedEffectForVertexBuffers = null;
- this.bindIndexBuffer(null);
- }
- setTextureFromPostProcess(channel, postProcess, name) {
- // Does nothing
- }
- setTextureFromPostProcessOutput(channel, postProcess, name) {
- // Does nothing
- }
- setDepthStencilTexture(channel, uniform, texture, name) {
- // Does nothing
- }
- /**
- * @internal
- */
- _getSamplingParameters(samplingMode, generateMipMaps) {
- const gl = this._gl;
- let magFilter = gl.NEAREST;
- let minFilter = gl.NEAREST;
- switch (samplingMode) {
- case 11:
- magFilter = gl.LINEAR;
- if (generateMipMaps) {
- minFilter = gl.LINEAR_MIPMAP_NEAREST;
- }
- else {
- minFilter = gl.LINEAR;
- }
- break;
- case 3:
- magFilter = gl.LINEAR;
- if (generateMipMaps) {
- minFilter = gl.LINEAR_MIPMAP_LINEAR;
- }
- else {
- minFilter = gl.LINEAR;
- }
- break;
- case 8:
- magFilter = gl.NEAREST;
- if (generateMipMaps) {
- minFilter = gl.NEAREST_MIPMAP_LINEAR;
- }
- else {
- minFilter = gl.NEAREST;
- }
- break;
- case 4:
- magFilter = gl.NEAREST;
- if (generateMipMaps) {
- minFilter = gl.NEAREST_MIPMAP_NEAREST;
- }
- else {
- minFilter = gl.NEAREST;
- }
- break;
- case 5:
- magFilter = gl.NEAREST;
- if (generateMipMaps) {
- minFilter = gl.LINEAR_MIPMAP_NEAREST;
- }
- else {
- minFilter = gl.LINEAR;
- }
- break;
- case 6:
- magFilter = gl.NEAREST;
- if (generateMipMaps) {
- minFilter = gl.LINEAR_MIPMAP_LINEAR;
- }
- else {
- minFilter = gl.LINEAR;
- }
- break;
- case 7:
- magFilter = gl.NEAREST;
- minFilter = gl.LINEAR;
- break;
- case 1:
- magFilter = gl.NEAREST;
- minFilter = gl.NEAREST;
- break;
- case 9:
- magFilter = gl.LINEAR;
- if (generateMipMaps) {
- minFilter = gl.NEAREST_MIPMAP_NEAREST;
- }
- else {
- minFilter = gl.NEAREST;
- }
- break;
- case 10:
- magFilter = gl.LINEAR;
- if (generateMipMaps) {
- minFilter = gl.NEAREST_MIPMAP_LINEAR;
- }
- else {
- minFilter = gl.NEAREST;
- }
- break;
- case 2:
- magFilter = gl.LINEAR;
- minFilter = gl.LINEAR;
- break;
- case 12:
- magFilter = gl.LINEAR;
- minFilter = gl.NEAREST;
- break;
- }
- return {
- min: minFilter,
- mag: magFilter,
- };
- }
- /** @internal */
- _createTexture() {
- const texture = this._gl.createTexture();
- if (!texture) {
- throw new Error("Unable to create texture");
- }
- return texture;
- }
- /** @internal */
- _createHardwareTexture() {
- return new WebGLHardwareTexture(this._createTexture(), this._gl);
- }
- /**
- * Creates an internal texture without binding it to a framebuffer
- * @internal
- * @param size defines the size of the texture
- * @param options defines the options used to create the texture
- * @param delayGPUTextureCreation true to delay the texture creation the first time it is really needed. false to create it right away
- * @param source source type of the texture
- * @returns a new internal texture
- */
- _createInternalTexture(size, options, delayGPUTextureCreation = true, source = InternalTextureSource.Unknown) {
- let generateMipMaps = false;
- let type = 0;
- let samplingMode = 3;
- let format = 5;
- let useSRGBBuffer = false;
- let samples = 1;
- let label;
- if (options !== undefined && typeof options === "object") {
- generateMipMaps = !!options.generateMipMaps;
- type = options.type === undefined ? 0 : options.type;
- samplingMode = options.samplingMode === undefined ? 3 : options.samplingMode;
- format = options.format === undefined ? 5 : options.format;
- useSRGBBuffer = options.useSRGBBuffer === undefined ? false : options.useSRGBBuffer;
- samples = options.samples ?? 1;
- label = options.label;
- }
- else {
- generateMipMaps = !!options;
- }
- useSRGBBuffer && (useSRGBBuffer = this._caps.supportSRGBBuffers && (this.webGLVersion > 1 || this.isWebGPU));
- if (type === 1 && !this._caps.textureFloatLinearFiltering) {
- // if floating point linear (gl.FLOAT) then force to NEAREST_SAMPLINGMODE
- samplingMode = 1;
- }
- else if (type === 2 && !this._caps.textureHalfFloatLinearFiltering) {
- // if floating point linear (HALF_FLOAT) then force to NEAREST_SAMPLINGMODE
- samplingMode = 1;
- }
- if (type === 1 && !this._caps.textureFloat) {
- type = 0;
- Logger.Warn("Float textures are not supported. Type forced to TEXTURETYPE_UNSIGNED_BYTE");
- }
- const gl = this._gl;
- const texture = new InternalTexture(this, source);
- const width = size.width || size;
- const height = size.height || size;
- const depth = size.depth || 0;
- const layers = size.layers || 0;
- const filters = this._getSamplingParameters(samplingMode, generateMipMaps);
- const target = layers !== 0 ? gl.TEXTURE_2D_ARRAY : depth !== 0 ? gl.TEXTURE_3D : gl.TEXTURE_2D;
- const sizedFormat = this._getRGBABufferInternalSizedFormat(type, format, useSRGBBuffer);
- const internalFormat = this._getInternalFormat(format);
- const textureType = this._getWebGLTextureType(type);
- // Bind
- this._bindTextureDirectly(target, texture);
- if (layers !== 0) {
- texture.is2DArray = true;
- gl.texImage3D(target, 0, sizedFormat, width, height, layers, 0, internalFormat, textureType, null);
- }
- else if (depth !== 0) {
- texture.is3D = true;
- gl.texImage3D(target, 0, sizedFormat, width, height, depth, 0, internalFormat, textureType, null);
- }
- else {
- gl.texImage2D(target, 0, sizedFormat, width, height, 0, internalFormat, textureType, null);
- }
- gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, filters.mag);
- gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, filters.min);
- gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- // MipMaps
- if (generateMipMaps) {
- this._gl.generateMipmap(target);
- }
- this._bindTextureDirectly(target, null);
- texture._useSRGBBuffer = useSRGBBuffer;
- texture.baseWidth = width;
- texture.baseHeight = height;
- texture.width = width;
- texture.height = height;
- texture.depth = layers;
- texture.isReady = true;
- texture.samples = samples;
- texture.generateMipMaps = generateMipMaps;
- texture.samplingMode = samplingMode;
- texture.type = type;
- texture.format = format;
- texture.label = label;
- this._internalTexturesCache.push(texture);
- return texture;
- }
- /**
- * @internal
- */
- _getUseSRGBBuffer(useSRGBBuffer, noMipmap) {
- // Generating mipmaps for sRGB textures is not supported in WebGL1 so we must disable the support if mipmaps is enabled
- return useSRGBBuffer && this._caps.supportSRGBBuffers && (this.webGLVersion > 1 || noMipmap);
- }
- /**
- * Usually called from Texture.ts.
- * Passed information to create a WebGLTexture
- * @param url defines a value which contains one of the following:
- * * A conventional http URL, e.g. 'http://...' or 'file://...'
- * * A base64 string of in-line texture data, e.g. 'data:image/jpg;base64,/...'
- * * An indicator that data being passed using the buffer parameter, e.g. 'data:mytexture.jpg'
- * @param noMipmap defines a boolean indicating that no mipmaps shall be generated. Ignored for compressed textures. They must be in the file
- * @param invertY when true, image is flipped when loaded. You probably want true. Certain compressed textures may invert this if their default is inverted (eg. ktx)
- * @param scene needed for loading to the correct scene
- * @param samplingMode mode with should be used sample / access the texture (Default: Texture.TRILINEAR_SAMPLINGMODE)
- * @param onLoad optional callback to be called upon successful completion
- * @param onError optional callback to be called upon failure
- * @param buffer a source of a file previously fetched as either a base64 string, an ArrayBuffer (compressed or image format), HTMLImageElement (image format), or a Blob
- * @param fallback an internal argument in case the function must be called again, due to etc1 not having alpha capabilities
- * @param format internal format. Default: RGB when extension is '.jpg' else RGBA. Ignored for compressed textures
- * @param forcedExtension defines the extension to use to pick the right loader
- * @param mimeType defines an optional mime type
- * @param loaderOptions options to be passed to the loader
- * @param creationFlags specific flags to use when creating the texture (1 for storage textures, for eg)
- * @param useSRGBBuffer defines if the texture must be loaded in a sRGB GPU buffer (if supported by the GPU).
- * @returns a InternalTexture for assignment back into BABYLON.Texture
- */
- createTexture(url, noMipmap, invertY, scene, samplingMode = 3, onLoad = null, onError = null, buffer = null, fallback = null, format = null, forcedExtension = null, mimeType, loaderOptions, creationFlags, useSRGBBuffer) {
- return this._createTextureBase(url, noMipmap, invertY, scene, samplingMode, onLoad, onError, this._prepareWebGLTexture.bind(this), (potWidth, potHeight, img, extension, texture, continuationCallback) => {
- const gl = this._gl;
- const isPot = img.width === potWidth && img.height === potHeight;
- texture._creationFlags = creationFlags ?? 0;
- const tip = this._getTexImageParametersForCreateTexture(format, extension, texture._useSRGBBuffer);
- if (isPot) {
- gl.texImage2D(gl.TEXTURE_2D, 0, tip.internalFormat, tip.format, tip.type, img);
- return false;
- }
- const maxTextureSize = this._caps.maxTextureSize;
- if (img.width > maxTextureSize || img.height > maxTextureSize || !this._supportsHardwareTextureRescaling) {
- this._prepareWorkingCanvas();
- if (!this._workingCanvas || !this._workingContext) {
- return false;
- }
- this._workingCanvas.width = potWidth;
- this._workingCanvas.height = potHeight;
- this._workingContext.drawImage(img, 0, 0, img.width, img.height, 0, 0, potWidth, potHeight);
- gl.texImage2D(gl.TEXTURE_2D, 0, tip.internalFormat, tip.format, tip.type, this._workingCanvas);
- texture.width = potWidth;
- texture.height = potHeight;
- return false;
- }
- else {
- // Using shaders when possible to rescale because canvas.drawImage is lossy
- const source = new InternalTexture(this, InternalTextureSource.Temp);
- this._bindTextureDirectly(gl.TEXTURE_2D, source, true);
- gl.texImage2D(gl.TEXTURE_2D, 0, tip.internalFormat, tip.format, tip.type, img);
- this._rescaleTexture(source, texture, scene, tip.format, () => {
- this._releaseTexture(source);
- this._bindTextureDirectly(gl.TEXTURE_2D, texture, true);
- continuationCallback();
- });
- }
- return true;
- }, buffer, fallback, format, forcedExtension, mimeType, loaderOptions, useSRGBBuffer);
- }
- /**
- * Calls to the GL texImage2D and texImage3D functions require three arguments describing the pixel format of the texture.
- * createTexture derives these from the babylonFormat and useSRGBBuffer arguments and also the file extension of the URL it's working with.
- * This function encapsulates that derivation for easy unit testing.
- * @param babylonFormat Babylon's format enum, as specified in ITextureCreationOptions.
- * @param fileExtension The file extension including the dot, e.g. .jpg.
- * @param useSRGBBuffer Use SRGB not linear.
- * @returns The options to pass to texImage2D or texImage3D calls.
- * @internal
- */
- _getTexImageParametersForCreateTexture(babylonFormat, fileExtension, useSRGBBuffer) {
- if (babylonFormat === undefined || babylonFormat === null) {
- babylonFormat = fileExtension === ".jpg" && !useSRGBBuffer ? 4 : 5;
- }
- let format, internalFormat;
- if (this.webGLVersion === 1) {
- // In WebGL 1, format and internalFormat must be the same and taken from a limited set of values, see https://docs.gl/es2/glTexImage2D.
- // The SRGB extension (https://developer.mozilla.org/en-US/docs/Web/API/EXT_sRGB) adds some extra values, hence passing useSRGBBuffer
- // to getInternalFormat.
- format = this._getInternalFormat(babylonFormat, useSRGBBuffer);
- internalFormat = format;
- }
- else {
- // In WebGL 2, format has a wider range of values and internal format can be one of the sized formats, see
- // https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml.
- // SRGB is included in the sized format and should not be passed in "format", hence always passing useSRGBBuffer as false.
- format = this._getInternalFormat(babylonFormat, false);
- internalFormat = this._getRGBABufferInternalSizedFormat(0, babylonFormat, useSRGBBuffer);
- }
- return {
- internalFormat,
- format,
- type: this._gl.UNSIGNED_BYTE,
- };
- }
- /**
- * @internal
- */
- _rescaleTexture(source, destination, scene, internalFormat, onComplete) { }
- // eslint-disable-next-line jsdoc/require-returns-check
- /**
- * Creates a raw texture
- * @param data defines the data to store in the texture
- * @param width defines the width of the texture
- * @param height defines the height of the texture
- * @param format defines the format of the data
- * @param generateMipMaps defines if the engine should generate the mip levels
- * @param invertY defines if data must be stored with Y axis inverted
- * @param samplingMode defines the required sampling mode (Texture.NEAREST_SAMPLINGMODE by default)
- * @param compression defines the compression used (null by default)
- * @param type defines the type fo the data (Engine.TEXTURETYPE_UNSIGNED_INT by default)
- * @param creationFlags specific flags to use when creating the texture (1 for storage textures, for eg)
- * @param useSRGBBuffer defines if the texture must be loaded in a sRGB GPU buffer (if supported by the GPU).
- * @returns the raw texture inside an InternalTexture
- */
- createRawTexture(data, width, height, format, generateMipMaps, invertY, samplingMode, compression = null, type = 0, creationFlags = 0, useSRGBBuffer = false) {
- throw _WarnImport("Engine.RawTexture");
- }
- // eslint-disable-next-line jsdoc/require-returns-check
- /**
- * Creates a new raw cube texture
- * @param data defines the array of data to use to create each face
- * @param size defines the size of the textures
- * @param format defines the format of the data
- * @param type defines the type of the data (like Engine.TEXTURETYPE_UNSIGNED_INT)
- * @param generateMipMaps defines if the engine should generate the mip levels
- * @param invertY defines if data must be stored with Y axis inverted
- * @param samplingMode defines the required sampling mode (like Texture.NEAREST_SAMPLINGMODE)
- * @param compression defines the compression used (null by default)
- * @returns the cube texture as an InternalTexture
- */
- createRawCubeTexture(data, size, format, type, generateMipMaps, invertY, samplingMode, compression = null) {
- throw _WarnImport("Engine.RawTexture");
- }
- // eslint-disable-next-line jsdoc/require-returns-check
- /**
- * Creates a new raw 3D texture
- * @param data defines the data used to create the texture
- * @param width defines the width of the texture
- * @param height defines the height of the texture
- * @param depth defines the depth of the texture
- * @param format defines the format of the texture
- * @param generateMipMaps defines if the engine must generate mip levels
- * @param invertY defines if data must be stored with Y axis inverted
- * @param samplingMode defines the required sampling mode (like Texture.NEAREST_SAMPLINGMODE)
- * @param compression defines the compressed used (can be null)
- * @param textureType defines the compressed used (can be null)
- * @returns a new raw 3D texture (stored in an InternalTexture)
- */
- createRawTexture3D(data, width, height, depth, format, generateMipMaps, invertY, samplingMode, compression = null, textureType = 0) {
- throw _WarnImport("Engine.RawTexture");
- }
- // eslint-disable-next-line jsdoc/require-returns-check
- /**
- * Creates a new raw 2D array texture
- * @param data defines the data used to create the texture
- * @param width defines the width of the texture
- * @param height defines the height of the texture
- * @param depth defines the number of layers of the texture
- * @param format defines the format of the texture
- * @param generateMipMaps defines if the engine must generate mip levels
- * @param invertY defines if data must be stored with Y axis inverted
- * @param samplingMode defines the required sampling mode (like Texture.NEAREST_SAMPLINGMODE)
- * @param compression defines the compressed used (can be null)
- * @param textureType defines the compressed used (can be null)
- * @returns a new raw 2D array texture (stored in an InternalTexture)
- */
- createRawTexture2DArray(data, width, height, depth, format, generateMipMaps, invertY, samplingMode, compression = null, textureType = 0) {
- throw _WarnImport("Engine.RawTexture");
- }
- /**
- * @internal
- */
- _unpackFlipY(value) {
- if (this._unpackFlipYCached !== value) {
- this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, value ? 1 : 0);
- if (this.enableUnpackFlipYCached) {
- this._unpackFlipYCached = value;
- }
- }
- }
- /** @internal */
- _getUnpackAlignement() {
- return this._gl.getParameter(this._gl.UNPACK_ALIGNMENT);
- }
- _getTextureTarget(texture) {
- if (texture.isCube) {
- return this._gl.TEXTURE_CUBE_MAP;
- }
- else if (texture.is3D) {
- return this._gl.TEXTURE_3D;
- }
- else if (texture.is2DArray || texture.isMultiview) {
- return this._gl.TEXTURE_2D_ARRAY;
- }
- return this._gl.TEXTURE_2D;
- }
- /**
- * Update the sampling mode of a given texture
- * @param samplingMode defines the required sampling mode
- * @param texture defines the texture to update
- * @param generateMipMaps defines whether to generate mipmaps for the texture
- */
- updateTextureSamplingMode(samplingMode, texture, generateMipMaps = false) {
- const target = this._getTextureTarget(texture);
- const filters = this._getSamplingParameters(samplingMode, texture.useMipMaps || generateMipMaps);
- this._setTextureParameterInteger(target, this._gl.TEXTURE_MAG_FILTER, filters.mag, texture);
- this._setTextureParameterInteger(target, this._gl.TEXTURE_MIN_FILTER, filters.min);
- if (generateMipMaps) {
- texture.generateMipMaps = true;
- this._gl.generateMipmap(target);
- }
- this._bindTextureDirectly(target, null);
- texture.samplingMode = samplingMode;
- }
- /**
- * Update the dimensions of a texture
- * @param texture texture to update
- * @param width new width of the texture
- * @param height new height of the texture
- * @param depth new depth of the texture
- */
- updateTextureDimensions(texture, width, height, depth = 1) { }
- /**
- * Update the sampling mode of a given texture
- * @param texture defines the texture to update
- * @param wrapU defines the texture wrap mode of the u coordinates
- * @param wrapV defines the texture wrap mode of the v coordinates
- * @param wrapR defines the texture wrap mode of the r coordinates
- */
- updateTextureWrappingMode(texture, wrapU, wrapV = null, wrapR = null) {
- const target = this._getTextureTarget(texture);
- if (wrapU !== null) {
- this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_S, this._getTextureWrapMode(wrapU), texture);
- texture._cachedWrapU = wrapU;
- }
- if (wrapV !== null) {
- this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_T, this._getTextureWrapMode(wrapV), texture);
- texture._cachedWrapV = wrapV;
- }
- if ((texture.is2DArray || texture.is3D) && wrapR !== null) {
- this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_R, this._getTextureWrapMode(wrapR), texture);
- texture._cachedWrapR = wrapR;
- }
- this._bindTextureDirectly(target, null);
- }
- /**
- * @internal
- */
- _setupDepthStencilTexture(internalTexture, size, generateStencil, bilinearFiltering, comparisonFunction, samples = 1) {
- const width = size.width || size;
- const height = size.height || size;
- const layers = size.layers || 0;
- const depth = size.depth || 0;
- internalTexture.baseWidth = width;
- internalTexture.baseHeight = height;
- internalTexture.width = width;
- internalTexture.height = height;
- internalTexture.is2DArray = layers > 0;
- internalTexture.depth = layers || depth;
- internalTexture.isReady = true;
- internalTexture.samples = samples;
- internalTexture.generateMipMaps = false;
- internalTexture.samplingMode = bilinearFiltering ? 2 : 1;
- internalTexture.type = 0;
- internalTexture._comparisonFunction = comparisonFunction;
- const gl = this._gl;
- const target = this._getTextureTarget(internalTexture);
- const samplingParameters = this._getSamplingParameters(internalTexture.samplingMode, false);
- gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, samplingParameters.mag);
- gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, samplingParameters.min);
- gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- // TEXTURE_COMPARE_FUNC/MODE are only availble in WebGL2.
- if (this.webGLVersion > 1) {
- if (comparisonFunction === 0) {
- gl.texParameteri(target, gl.TEXTURE_COMPARE_FUNC, 515);
- gl.texParameteri(target, gl.TEXTURE_COMPARE_MODE, gl.NONE);
- }
- else {
- gl.texParameteri(target, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
- gl.texParameteri(target, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
- }
- }
- }
- /**
- * @internal
- */
- _uploadCompressedDataToTextureDirectly(texture, internalFormat, width, height, data, faceIndex = 0, lod = 0) {
- const gl = this._gl;
- let target = gl.TEXTURE_2D;
- if (texture.isCube) {
- target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
- }
- if (texture._useSRGBBuffer) {
- switch (internalFormat) {
- case 37492:
- case 36196:
- // Note, if using ETC1 and sRGB is requested, this will use ETC2 if available.
- if (this._caps.etc2) {
- internalFormat = gl.COMPRESSED_SRGB8_ETC2;
- }
- else {
- texture._useSRGBBuffer = false;
- }
- break;
- case 37496:
- if (this._caps.etc2) {
- internalFormat = gl.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
- }
- else {
- texture._useSRGBBuffer = false;
- }
- break;
- case 36492:
- internalFormat = gl.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT;
- break;
- case 37808:
- internalFormat = gl.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR;
- break;
- case 33776:
- if (this._caps.s3tc_srgb) {
- internalFormat = gl.COMPRESSED_SRGB_S3TC_DXT1_EXT;
- }
- else {
- // S3TC sRGB extension not supported
- texture._useSRGBBuffer = false;
- }
- break;
- case 33777:
- if (this._caps.s3tc_srgb) {
- internalFormat = gl.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
- }
- else {
- // S3TC sRGB extension not supported
- texture._useSRGBBuffer = false;
- }
- break;
- case 33779:
- if (this._caps.s3tc_srgb) {
- internalFormat = gl.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
- }
- else {
- // S3TC sRGB extension not supported
- texture._useSRGBBuffer = false;
- }
- break;
- default:
- // We don't support a sRGB format corresponding to internalFormat, so revert to non sRGB format
- texture._useSRGBBuffer = false;
- break;
- }
- }
- this._gl.compressedTexImage2D(target, lod, internalFormat, width, height, 0, data);
- }
- /**
- * @internal
- */
- _uploadDataToTextureDirectly(texture, imageData, faceIndex = 0, lod = 0, babylonInternalFormat, useTextureWidthAndHeight = false) {
- const gl = this._gl;
- const textureType = this._getWebGLTextureType(texture.type);
- const format = this._getInternalFormat(texture.format);
- const internalFormat = babylonInternalFormat === undefined
- ? this._getRGBABufferInternalSizedFormat(texture.type, texture.format, texture._useSRGBBuffer)
- : this._getInternalFormat(babylonInternalFormat, texture._useSRGBBuffer);
- this._unpackFlipY(texture.invertY);
- let target = gl.TEXTURE_2D;
- if (texture.isCube) {
- target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
- }
- const lodMaxWidth = Math.round(Math.log(texture.width) * Math.LOG2E);
- const lodMaxHeight = Math.round(Math.log(texture.height) * Math.LOG2E);
- const width = useTextureWidthAndHeight ? texture.width : Math.pow(2, Math.max(lodMaxWidth - lod, 0));
- const height = useTextureWidthAndHeight ? texture.height : Math.pow(2, Math.max(lodMaxHeight - lod, 0));
- gl.texImage2D(target, lod, internalFormat, width, height, 0, format, textureType, imageData);
- }
- /**
- * Update a portion of an internal texture
- * @param texture defines the texture to update
- * @param imageData defines the data to store into the texture
- * @param xOffset defines the x coordinates of the update rectangle
- * @param yOffset defines the y coordinates of the update rectangle
- * @param width defines the width of the update rectangle
- * @param height defines the height of the update rectangle
- * @param faceIndex defines the face index if texture is a cube (0 by default)
- * @param lod defines the lod level to update (0 by default)
- * @param generateMipMaps defines whether to generate mipmaps or not
- */
- updateTextureData(texture, imageData, xOffset, yOffset, width, height, faceIndex = 0, lod = 0, generateMipMaps = false) {
- const gl = this._gl;
- const textureType = this._getWebGLTextureType(texture.type);
- const format = this._getInternalFormat(texture.format);
- this._unpackFlipY(texture.invertY);
- let targetForBinding = gl.TEXTURE_2D;
- let target = gl.TEXTURE_2D;
- if (texture.isCube) {
- target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
- targetForBinding = gl.TEXTURE_CUBE_MAP;
- }
- this._bindTextureDirectly(targetForBinding, texture, true);
- gl.texSubImage2D(target, lod, xOffset, yOffset, width, height, format, textureType, imageData);
- if (generateMipMaps) {
- this._gl.generateMipmap(target);
- }
- this._bindTextureDirectly(targetForBinding, null);
- }
- /**
- * @internal
- */
- _uploadArrayBufferViewToTexture(texture, imageData, faceIndex = 0, lod = 0) {
- const gl = this._gl;
- const bindTarget = texture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
- this._bindTextureDirectly(bindTarget, texture, true);
- this._uploadDataToTextureDirectly(texture, imageData, faceIndex, lod);
- this._bindTextureDirectly(bindTarget, null, true);
- }
- _prepareWebGLTextureContinuation(texture, scene, noMipmap, isCompressed, samplingMode) {
- const gl = this._gl;
- if (!gl) {
- return;
- }
- const filters = this._getSamplingParameters(samplingMode, !noMipmap);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filters.mag);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filters.min);
- if (!noMipmap && !isCompressed) {
- gl.generateMipmap(gl.TEXTURE_2D);
- }
- this._bindTextureDirectly(gl.TEXTURE_2D, null);
- // this.resetTextureCache();
- if (scene) {
- scene.removePendingData(texture);
- }
- texture.onLoadedObservable.notifyObservers(texture);
- texture.onLoadedObservable.clear();
- }
- _prepareWebGLTexture(texture, extension, scene, img, invertY, noMipmap, isCompressed, processFunction, samplingMode = 3) {
- const maxTextureSize = this.getCaps().maxTextureSize;
- const potWidth = Math.min(maxTextureSize, this.needPOTTextures ? GetExponentOfTwo(img.width, maxTextureSize) : img.width);
- const potHeight = Math.min(maxTextureSize, this.needPOTTextures ? GetExponentOfTwo(img.height, maxTextureSize) : img.height);
- const gl = this._gl;
- if (!gl) {
- return;
- }
- if (!texture._hardwareTexture) {
- // this.resetTextureCache();
- if (scene) {
- scene.removePendingData(texture);
- }
- return;
- }
- this._bindTextureDirectly(gl.TEXTURE_2D, texture, true);
- this._unpackFlipY(invertY === undefined ? true : invertY ? true : false);
- texture.baseWidth = img.width;
- texture.baseHeight = img.height;
- texture.width = potWidth;
- texture.height = potHeight;
- texture.isReady = true;
- texture.type = texture.type !== -1 ? texture.type : 0;
- texture.format = texture.format !== -1 ? texture.format : extension === ".jpg" && !texture._useSRGBBuffer ? 4 : 5;
- if (processFunction(potWidth, potHeight, img, extension, texture, () => {
- this._prepareWebGLTextureContinuation(texture, scene, noMipmap, isCompressed, samplingMode);
- })) {
- // Returning as texture needs extra async steps
- return;
- }
- this._prepareWebGLTextureContinuation(texture, scene, noMipmap, isCompressed, samplingMode);
- }
- /**
- * @internal
- */
- _setupFramebufferDepthAttachments(generateStencilBuffer, generateDepthBuffer, width, height, samples = 1) {
- const gl = this._gl;
- // Create the depth/stencil buffer
- if (generateStencilBuffer && generateDepthBuffer) {
- return this._createRenderBuffer(width, height, samples, gl.DEPTH_STENCIL, gl.DEPTH24_STENCIL8, gl.DEPTH_STENCIL_ATTACHMENT);
- }
- if (generateDepthBuffer) {
- let depthFormat = gl.DEPTH_COMPONENT16;
- if (this._webGLVersion > 1) {
- depthFormat = gl.DEPTH_COMPONENT32F;
- }
- return this._createRenderBuffer(width, height, samples, depthFormat, depthFormat, gl.DEPTH_ATTACHMENT);
- }
- if (generateStencilBuffer) {
- return this._createRenderBuffer(width, height, samples, gl.STENCIL_INDEX8, gl.STENCIL_INDEX8, gl.STENCIL_ATTACHMENT);
- }
- return null;
- }
- /**
- * @internal
- */
- _createRenderBuffer(width, height, samples, internalFormat, msInternalFormat, attachment, unbindBuffer = true) {
- const gl = this._gl;
- const renderBuffer = gl.createRenderbuffer();
- return this._updateRenderBuffer(renderBuffer, width, height, samples, internalFormat, msInternalFormat, attachment, unbindBuffer);
- }
- _updateRenderBuffer(renderBuffer, width, height, samples, internalFormat, msInternalFormat, attachment, unbindBuffer = true) {
- const gl = this._gl;
- gl.bindRenderbuffer(gl.RENDERBUFFER, renderBuffer);
- if (samples > 1 && gl.renderbufferStorageMultisample) {
- gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, msInternalFormat, width, height);
- }
- else {
- gl.renderbufferStorage(gl.RENDERBUFFER, internalFormat, width, height);
- }
- gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderBuffer);
- if (unbindBuffer) {
- gl.bindRenderbuffer(gl.RENDERBUFFER, null);
- }
- return renderBuffer;
- }
- /**
- * @internal
- */
- _releaseTexture(texture) {
- this._deleteTexture(texture._hardwareTexture?.underlyingResource);
- // Unbind channels
- this.unbindAllTextures();
- const index = this._internalTexturesCache.indexOf(texture);
- if (index !== -1) {
- this._internalTexturesCache.splice(index, 1);
- }
- // Integrated fixed lod samplers.
- if (texture._lodTextureHigh) {
- texture._lodTextureHigh.dispose();
- }
- if (texture._lodTextureMid) {
- texture._lodTextureMid.dispose();
- }
- if (texture._lodTextureLow) {
- texture._lodTextureLow.dispose();
- }
- // Integrated irradiance map.
- if (texture._irradianceTexture) {
- texture._irradianceTexture.dispose();
- }
- }
- _deleteTexture(texture) {
- if (texture) {
- this._gl.deleteTexture(texture);
- }
- }
- _setProgram(program) {
- if (this._currentProgram !== program) {
- this._gl.useProgram(program);
- this._currentProgram = program;
- }
- }
- /**
- * Binds an effect to the webGL context
- * @param effect defines the effect to bind
- */
- bindSamplers(effect) {
- const webGLPipelineContext = effect.getPipelineContext();
- this._setProgram(webGLPipelineContext.program);
- const samplers = effect.getSamplers();
- for (let index = 0; index < samplers.length; index++) {
- const uniform = effect.getUniform(samplers[index]);
- if (uniform) {
- this._boundUniforms[index] = uniform;
- }
- }
- this._currentEffect = null;
- }
- _activateCurrentTexture() {
- if (this._currentTextureChannel !== this._activeChannel) {
- this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
- this._currentTextureChannel = this._activeChannel;
- }
- }
- /**
- * @internal
- */
- _bindTextureDirectly(target, texture, forTextureDataUpdate = false, force = false) {
- let wasPreviouslyBound = false;
- const isTextureForRendering = texture && texture._associatedChannel > -1;
- if (forTextureDataUpdate && isTextureForRendering) {
- this._activeChannel = texture._associatedChannel;
- }
- const currentTextureBound = this._boundTexturesCache[this._activeChannel];
- if (currentTextureBound !== texture || force) {
- this._activateCurrentTexture();
- if (texture && texture.isMultiview) {
- //this._gl.bindTexture(target, texture ? texture._colorTextureArray : null);
- Logger.Error(["_bindTextureDirectly called with a multiview texture!", target, texture]);
- // eslint-disable-next-line no-throw-literal
- throw "_bindTextureDirectly called with a multiview texture!";
- }
- else {
- this._gl.bindTexture(target, texture?._hardwareTexture?.underlyingResource ?? null);
- }
- this._boundTexturesCache[this._activeChannel] = texture;
- if (texture) {
- texture._associatedChannel = this._activeChannel;
- }
- }
- else if (forTextureDataUpdate) {
- wasPreviouslyBound = true;
- this._activateCurrentTexture();
- }
- if (isTextureForRendering && !forTextureDataUpdate) {
- this._bindSamplerUniformToChannel(texture._associatedChannel, this._activeChannel);
- }
- return wasPreviouslyBound;
- }
- /**
- * @internal
- */
- _bindTexture(channel, texture, name) {
- if (channel === undefined) {
- return;
- }
- if (texture) {
- texture._associatedChannel = channel;
- }
- this._activeChannel = channel;
- const target = texture ? this._getTextureTarget(texture) : this._gl.TEXTURE_2D;
- this._bindTextureDirectly(target, texture);
- }
- /**
- * Unbind all textures from the webGL context
- */
- unbindAllTextures() {
- for (let channel = 0; channel < this._maxSimultaneousTextures; channel++) {
- this._activeChannel = channel;
- this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
- this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
- if (this.webGLVersion > 1) {
- this._bindTextureDirectly(this._gl.TEXTURE_3D, null);
- this._bindTextureDirectly(this._gl.TEXTURE_2D_ARRAY, null);
- }
- }
- }
- /**
- * Sets a texture to the according uniform.
- * @param channel The texture channel
- * @param uniform The uniform to set
- * @param texture The texture to apply
- * @param name The name of the uniform in the effect
- */
- setTexture(channel, uniform, texture, name) {
- if (channel === undefined) {
- return;
- }
- if (uniform) {
- this._boundUniforms[channel] = uniform;
- }
- this._setTexture(channel, texture);
- }
- _bindSamplerUniformToChannel(sourceSlot, destination) {
- const uniform = this._boundUniforms[sourceSlot];
- if (!uniform || uniform._currentState === destination) {
- return;
- }
- this._gl.uniform1i(uniform, destination);
- uniform._currentState = destination;
- }
- _getTextureWrapMode(mode) {
- switch (mode) {
- case 1:
- return this._gl.REPEAT;
- case 0:
- return this._gl.CLAMP_TO_EDGE;
- case 2:
- return this._gl.MIRRORED_REPEAT;
- }
- return this._gl.REPEAT;
- }
- _setTexture(channel, texture, isPartOfTextureArray = false, depthStencilTexture = false, name = "") {
- // Not ready?
- if (!texture) {
- if (this._boundTexturesCache[channel] != null) {
- this._activeChannel = channel;
- this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
- this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
- if (this.webGLVersion > 1) {
- this._bindTextureDirectly(this._gl.TEXTURE_3D, null);
- this._bindTextureDirectly(this._gl.TEXTURE_2D_ARRAY, null);
- }
- }
- return false;
- }
- // Video
- if (texture.video) {
- this._activeChannel = channel;
- const videoInternalTexture = texture.getInternalTexture();
- if (videoInternalTexture) {
- videoInternalTexture._associatedChannel = channel;
- }
- texture.update();
- }
- else if (texture.delayLoadState === 4) {
- // Delay loading
- texture.delayLoad();
- return false;
- }
- let internalTexture;
- if (depthStencilTexture) {
- internalTexture = texture.depthStencilTexture;
- }
- else if (texture.isReady()) {
- internalTexture = texture.getInternalTexture();
- }
- else if (texture.isCube) {
- internalTexture = this.emptyCubeTexture;
- }
- else if (texture.is3D) {
- internalTexture = this.emptyTexture3D;
- }
- else if (texture.is2DArray) {
- internalTexture = this.emptyTexture2DArray;
- }
- else {
- internalTexture = this.emptyTexture;
- }
- if (!isPartOfTextureArray && internalTexture) {
- internalTexture._associatedChannel = channel;
- }
- let needToBind = true;
- if (this._boundTexturesCache[channel] === internalTexture) {
- if (!isPartOfTextureArray) {
- this._bindSamplerUniformToChannel(internalTexture._associatedChannel, channel);
- }
- needToBind = false;
- }
- this._activeChannel = channel;
- const target = this._getTextureTarget(internalTexture);
- if (needToBind) {
- this._bindTextureDirectly(target, internalTexture, isPartOfTextureArray);
- }
- if (internalTexture && !internalTexture.isMultiview) {
- // CUBIC_MODE and SKYBOX_MODE both require CLAMP_TO_EDGE. All other modes use REPEAT.
- if (internalTexture.isCube && internalTexture._cachedCoordinatesMode !== texture.coordinatesMode) {
- internalTexture._cachedCoordinatesMode = texture.coordinatesMode;
- const textureWrapMode = texture.coordinatesMode !== 3 && texture.coordinatesMode !== 5
- ? 1
- : 0;
- texture.wrapU = textureWrapMode;
- texture.wrapV = textureWrapMode;
- }
- if (internalTexture._cachedWrapU !== texture.wrapU) {
- internalTexture._cachedWrapU = texture.wrapU;
- this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_S, this._getTextureWrapMode(texture.wrapU), internalTexture);
- }
- if (internalTexture._cachedWrapV !== texture.wrapV) {
- internalTexture._cachedWrapV = texture.wrapV;
- this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_T, this._getTextureWrapMode(texture.wrapV), internalTexture);
- }
- if (internalTexture.is3D && internalTexture._cachedWrapR !== texture.wrapR) {
- internalTexture._cachedWrapR = texture.wrapR;
- this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_R, this._getTextureWrapMode(texture.wrapR), internalTexture);
- }
- this._setAnisotropicLevel(target, internalTexture, texture.anisotropicFilteringLevel);
- }
- return true;
- }
- /**
- * Sets an array of texture to the webGL context
- * @param channel defines the channel where the texture array must be set
- * @param uniform defines the associated uniform location
- * @param textures defines the array of textures to bind
- * @param name name of the channel
- */
- setTextureArray(channel, uniform, textures, name) {
- if (channel === undefined || !uniform) {
- return;
- }
- if (!this._textureUnits || this._textureUnits.length !== textures.length) {
- this._textureUnits = new Int32Array(textures.length);
- }
- for (let i = 0; i < textures.length; i++) {
- const texture = textures[i].getInternalTexture();
- if (texture) {
- this._textureUnits[i] = channel + i;
- texture._associatedChannel = channel + i;
- }
- else {
- this._textureUnits[i] = -1;
- }
- }
- this._gl.uniform1iv(uniform, this._textureUnits);
- for (let index = 0; index < textures.length; index++) {
- this._setTexture(this._textureUnits[index], textures[index], true);
- }
- }
- /**
- * @internal
- */
- _setAnisotropicLevel(target, internalTexture, anisotropicFilteringLevel) {
- const anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
- if (internalTexture.samplingMode !== 11 &&
- internalTexture.samplingMode !== 3 &&
- internalTexture.samplingMode !== 2) {
- anisotropicFilteringLevel = 1; // Forcing the anisotropic to 1 because else webgl will force filters to linear
- }
- if (anisotropicFilterExtension && internalTexture._cachedAnisotropicFilteringLevel !== anisotropicFilteringLevel) {
- this._setTextureParameterFloat(target, anisotropicFilterExtension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(anisotropicFilteringLevel, this._caps.maxAnisotropy), internalTexture);
- internalTexture._cachedAnisotropicFilteringLevel = anisotropicFilteringLevel;
- }
- }
- _setTextureParameterFloat(target, parameter, value, texture) {
- this._bindTextureDirectly(target, texture, true, true);
- this._gl.texParameterf(target, parameter, value);
- }
- _setTextureParameterInteger(target, parameter, value, texture) {
- if (texture) {
- this._bindTextureDirectly(target, texture, true, true);
- }
- this._gl.texParameteri(target, parameter, value);
- }
- /**
- * Unbind all vertex attributes from the webGL context
- */
- unbindAllAttributes() {
- if (this._mustWipeVertexAttributes) {
- this._mustWipeVertexAttributes = false;
- for (let i = 0; i < this._caps.maxVertexAttribs; i++) {
- this.disableAttributeByIndex(i);
- }
- return;
- }
- for (let i = 0, ul = this._vertexAttribArraysEnabled.length; i < ul; i++) {
- if (i >= this._caps.maxVertexAttribs || !this._vertexAttribArraysEnabled[i]) {
- continue;
- }
- this.disableAttributeByIndex(i);
- }
- }
- /**
- * Force the engine to release all cached effects. This means that next effect compilation will have to be done completely even if a similar effect was already compiled
- */
- releaseEffects() {
- for (const name in this._compiledEffects) {
- const webGLPipelineContext = this._compiledEffects[name].getPipelineContext();
- this._deletePipelineContext(webGLPipelineContext);
- }
- this._compiledEffects = {};
- }
- /**
- * Dispose and release all associated resources
- */
- dispose() {
- super.dispose();
- if (this._dummyFramebuffer) {
- this._gl.deleteFramebuffer(this._dummyFramebuffer);
- }
- // Release effects
- this.releaseEffects();
- // Unbind
- this.unbindAllAttributes();
- this._boundUniforms = {};
- // Events
- if (IsWindowObjectExist()) {
- if (this._renderingCanvas) {
- if (!this._doNotHandleContextLost) {
- this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
- this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);
- }
- }
- }
- this._workingCanvas = null;
- this._workingContext = null;
- this._currentBufferPointers.length = 0;
- this._currentProgram = null;
- if (this._creationOptions.loseContextOnDispose) {
- this._gl.getExtension("WEBGL_lose_context")?.loseContext();
- }
- }
- /**
- * Attach a new callback raised when context lost event is fired
- * @param callback defines the callback to call
- */
- attachContextLostEvent(callback) {
- if (this._renderingCanvas) {
- this._renderingCanvas.addEventListener("webglcontextlost", callback, false);
- }
- }
- /**
- * Attach a new callback raised when context restored event is fired
- * @param callback defines the callback to call
- */
- attachContextRestoredEvent(callback) {
- if (this._renderingCanvas) {
- this._renderingCanvas.addEventListener("webglcontextrestored", callback, false);
- }
- }
- /**
- * Get the current error code of the webGL context
- * @returns the error code
- * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getError
- */
- getError() {
- return this._gl.getError();
- }
- _canRenderToFloatFramebuffer() {
- if (this._webGLVersion > 1) {
- return this._caps.colorBufferFloat;
- }
- return this._canRenderToFramebuffer(1);
- }
- _canRenderToHalfFloatFramebuffer() {
- if (this._webGLVersion > 1) {
- return this._caps.colorBufferFloat;
- }
- return this._canRenderToFramebuffer(2);
- }
- // Thank you : http://stackoverflow.com/questions/28827511/webgl-ios-render-to-floating-point-texture
- _canRenderToFramebuffer(type) {
- const gl = this._gl;
- //clear existing errors
- // eslint-disable-next-line no-empty
- while (gl.getError() !== gl.NO_ERROR) { }
- let successful = true;
- const texture = gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, this._getRGBABufferInternalSizedFormat(type), 1, 1, 0, gl.RGBA, this._getWebGLTextureType(type), null);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
- const fb = gl.createFramebuffer();
- gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
- const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
- successful = successful && status === gl.FRAMEBUFFER_COMPLETE;
- successful = successful && gl.getError() === gl.NO_ERROR;
- //try render by clearing frame buffer's color buffer
- if (successful) {
- gl.clear(gl.COLOR_BUFFER_BIT);
- successful = successful && gl.getError() === gl.NO_ERROR;
- }
- //try reading from frame to ensure render occurs (just creating the FBO is not sufficient to determine if rendering is supported)
- if (successful) {
- //in practice it's sufficient to just read from the backbuffer rather than handle potentially issues reading from the texture
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
- const readFormat = gl.RGBA;
- const readType = gl.UNSIGNED_BYTE;
- const buffer = new Uint8Array(4);
- gl.readPixels(0, 0, 1, 1, readFormat, readType, buffer);
- successful = successful && gl.getError() === gl.NO_ERROR;
- }
- //clean up
- gl.deleteTexture(texture);
- gl.deleteFramebuffer(fb);
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
- //clear accumulated errors
- // eslint-disable-next-line no-empty
- while (!successful && gl.getError() !== gl.NO_ERROR) { }
- return successful;
- }
- /**
- * @internal
- */
- _getWebGLTextureType(type) {
- if (this._webGLVersion === 1) {
- switch (type) {
- case 1:
- return this._gl.FLOAT;
- case 2:
- return this._gl.HALF_FLOAT_OES;
- case 0:
- return this._gl.UNSIGNED_BYTE;
- case 8:
- return this._gl.UNSIGNED_SHORT_4_4_4_4;
- case 9:
- return this._gl.UNSIGNED_SHORT_5_5_5_1;
- case 10:
- return this._gl.UNSIGNED_SHORT_5_6_5;
- }
- return this._gl.UNSIGNED_BYTE;
- }
- switch (type) {
- case 3:
- return this._gl.BYTE;
- case 0:
- return this._gl.UNSIGNED_BYTE;
- case 4:
- return this._gl.SHORT;
- case 5:
- return this._gl.UNSIGNED_SHORT;
- case 6:
- return this._gl.INT;
- case 7: // Refers to UNSIGNED_INT
- return this._gl.UNSIGNED_INT;
- case 1:
- return this._gl.FLOAT;
- case 2:
- return this._gl.HALF_FLOAT;
- case 8:
- return this._gl.UNSIGNED_SHORT_4_4_4_4;
- case 9:
- return this._gl.UNSIGNED_SHORT_5_5_5_1;
- case 10:
- return this._gl.UNSIGNED_SHORT_5_6_5;
- case 11:
- return this._gl.UNSIGNED_INT_2_10_10_10_REV;
- case 12:
- return this._gl.UNSIGNED_INT_24_8;
- case 13:
- return this._gl.UNSIGNED_INT_10F_11F_11F_REV;
- case 14:
- return this._gl.UNSIGNED_INT_5_9_9_9_REV;
- case 15:
- return this._gl.FLOAT_32_UNSIGNED_INT_24_8_REV;
- }
- return this._gl.UNSIGNED_BYTE;
- }
- /**
- * @internal
- */
- _getInternalFormat(format, useSRGBBuffer = false) {
- let internalFormat = useSRGBBuffer ? this._glSRGBExtensionValues.SRGB8_ALPHA8 : this._gl.RGBA;
- switch (format) {
- case 0:
- internalFormat = this._gl.ALPHA;
- break;
- case 1:
- internalFormat = this._gl.LUMINANCE;
- break;
- case 2:
- internalFormat = this._gl.LUMINANCE_ALPHA;
- break;
- case 6:
- internalFormat = this._gl.RED;
- break;
- case 7:
- internalFormat = this._gl.RG;
- break;
- case 4:
- internalFormat = useSRGBBuffer ? this._glSRGBExtensionValues.SRGB : this._gl.RGB;
- break;
- case 5:
- internalFormat = useSRGBBuffer ? this._glSRGBExtensionValues.SRGB8_ALPHA8 : this._gl.RGBA;
- break;
- }
- if (this._webGLVersion > 1) {
- switch (format) {
- case 8:
- internalFormat = this._gl.RED_INTEGER;
- break;
- case 9:
- internalFormat = this._gl.RG_INTEGER;
- break;
- case 10:
- internalFormat = this._gl.RGB_INTEGER;
- break;
- case 11:
- internalFormat = this._gl.RGBA_INTEGER;
- break;
- }
- }
- return internalFormat;
- }
- /**
- * @internal
- */
- _getRGBABufferInternalSizedFormat(type, format, useSRGBBuffer = false) {
- if (this._webGLVersion === 1) {
- if (format !== undefined) {
- switch (format) {
- case 0:
- return this._gl.ALPHA;
- case 1:
- return this._gl.LUMINANCE;
- case 2:
- return this._gl.LUMINANCE_ALPHA;
- case 4:
- return useSRGBBuffer ? this._glSRGBExtensionValues.SRGB : this._gl.RGB;
- }
- }
- return this._gl.RGBA;
- }
- switch (type) {
- case 3:
- switch (format) {
- case 6:
- return this._gl.R8_SNORM;
- case 7:
- return this._gl.RG8_SNORM;
- case 4:
- return this._gl.RGB8_SNORM;
- case 8:
- return this._gl.R8I;
- case 9:
- return this._gl.RG8I;
- case 10:
- return this._gl.RGB8I;
- case 11:
- return this._gl.RGBA8I;
- default:
- return this._gl.RGBA8_SNORM;
- }
- case 0:
- switch (format) {
- case 6:
- return this._gl.R8;
- case 7:
- return this._gl.RG8;
- case 4:
- return useSRGBBuffer ? this._glSRGBExtensionValues.SRGB8 : this._gl.RGB8; // By default. Other possibilities are RGB565, SRGB8.
- case 5:
- return useSRGBBuffer ? this._glSRGBExtensionValues.SRGB8_ALPHA8 : this._gl.RGBA8; // By default. Other possibilities are RGB5_A1, RGBA4, SRGB8_ALPHA8.
- case 8:
- return this._gl.R8UI;
- case 9:
- return this._gl.RG8UI;
- case 10:
- return this._gl.RGB8UI;
- case 11:
- return this._gl.RGBA8UI;
- case 0:
- return this._gl.ALPHA;
- case 1:
- return this._gl.LUMINANCE;
- case 2:
- return this._gl.LUMINANCE_ALPHA;
- default:
- return this._gl.RGBA8;
- }
- case 4:
- switch (format) {
- case 8:
- return this._gl.R16I;
- case 9:
- return this._gl.RG16I;
- case 10:
- return this._gl.RGB16I;
- case 11:
- return this._gl.RGBA16I;
- default:
- return this._gl.RGBA16I;
- }
- case 5:
- switch (format) {
- case 8:
- return this._gl.R16UI;
- case 9:
- return this._gl.RG16UI;
- case 10:
- return this._gl.RGB16UI;
- case 11:
- return this._gl.RGBA16UI;
- default:
- return this._gl.RGBA16UI;
- }
- case 6:
- switch (format) {
- case 8:
- return this._gl.R32I;
- case 9:
- return this._gl.RG32I;
- case 10:
- return this._gl.RGB32I;
- case 11:
- return this._gl.RGBA32I;
- default:
- return this._gl.RGBA32I;
- }
- case 7: // Refers to UNSIGNED_INT
- switch (format) {
- case 8:
- return this._gl.R32UI;
- case 9:
- return this._gl.RG32UI;
- case 10:
- return this._gl.RGB32UI;
- case 11:
- return this._gl.RGBA32UI;
- default:
- return this._gl.RGBA32UI;
- }
- case 1:
- switch (format) {
- case 6:
- return this._gl.R32F; // By default. Other possibility is R16F.
- case 7:
- return this._gl.RG32F; // By default. Other possibility is RG16F.
- case 4:
- return this._gl.RGB32F; // By default. Other possibilities are RGB16F, R11F_G11F_B10F, RGB9_E5.
- case 5:
- return this._gl.RGBA32F; // By default. Other possibility is RGBA16F.
- default:
- return this._gl.RGBA32F;
- }
- case 2:
- switch (format) {
- case 6:
- return this._gl.R16F;
- case 7:
- return this._gl.RG16F;
- case 4:
- return this._gl.RGB16F; // By default. Other possibilities are R11F_G11F_B10F, RGB9_E5.
- case 5:
- return this._gl.RGBA16F;
- default:
- return this._gl.RGBA16F;
- }
- case 10:
- return this._gl.RGB565;
- case 13:
- return this._gl.R11F_G11F_B10F;
- case 14:
- return this._gl.RGB9_E5;
- case 8:
- return this._gl.RGBA4;
- case 9:
- return this._gl.RGB5_A1;
- case 11:
- switch (format) {
- case 5:
- return this._gl.RGB10_A2; // By default. Other possibility is RGB5_A1.
- case 11:
- return this._gl.RGB10_A2UI;
- default:
- return this._gl.RGB10_A2;
- }
- }
- return useSRGBBuffer ? this._glSRGBExtensionValues.SRGB8_ALPHA8 : this._gl.RGBA8;
- }
- /**
- * Reads pixels from the current frame buffer. Please note that this function can be slow
- * @param x defines the x coordinate of the rectangle where pixels must be read
- * @param y defines the y coordinate of the rectangle where pixels must be read
- * @param width defines the width of the rectangle where pixels must be read
- * @param height defines the height of the rectangle where pixels must be read
- * @param hasAlpha defines whether the output should have alpha or not (defaults to true)
- * @param flushRenderer true to flush the renderer from the pending commands before reading the pixels
- * @returns a ArrayBufferView promise (Uint8Array) containing RGBA colors
- */
- readPixels(x, y, width, height, hasAlpha = true, flushRenderer = true) {
- const numChannels = hasAlpha ? 4 : 3;
- const format = hasAlpha ? this._gl.RGBA : this._gl.RGB;
- const data = new Uint8Array(height * width * numChannels);
- if (flushRenderer) {
- this.flushFramebuffer();
- }
- this._gl.readPixels(x, y, width, height, format, this._gl.UNSIGNED_BYTE, data);
- return Promise.resolve(data);
- }
- /**
- * Force the mipmap generation for the given render target texture
- * @param texture defines the render target texture to use
- * @param unbind defines whether or not to unbind the texture after generation. Defaults to true.
- */
- generateMipMapsForCubemap(texture, unbind) {
- // Does nothing
- // Child classes should implement this function
- }
- /**
- * Gets a Promise<boolean> indicating if the engine can be instantiated (ie. if a webGL context can be found)
- */
- static get IsSupportedAsync() {
- return Promise.resolve(this.isSupported());
- }
- /**
- * Gets a boolean indicating if the engine can be instantiated (ie. if a webGL context can be found)
- */
- static get IsSupported() {
- return this.isSupported(); // Backward compat
- }
- /**
- * Gets a boolean indicating if the engine can be instantiated (ie. if a webGL context can be found)
- * @returns true if the engine can be created
- * @ignorenaming
- */
- // eslint-disable-next-line @typescript-eslint/naming-convention
- static isSupported() {
- if (this._HasMajorPerformanceCaveat !== null) {
- return !this._HasMajorPerformanceCaveat; // We know it is performant so WebGL is supported
- }
- if (this._IsSupported === null) {
- try {
- const tempcanvas = AbstractEngine._CreateCanvas(1, 1);
- const gl = tempcanvas.getContext("webgl") || tempcanvas.getContext("experimental-webgl");
- this._IsSupported = gl != null && !!window.WebGLRenderingContext;
- }
- catch (e) {
- this._IsSupported = false;
- }
- }
- return this._IsSupported;
- }
- /**
- * Gets a boolean indicating if the engine can be instantiated on a performant device (ie. if a webGL context can be found and it does not use a slow implementation)
- */
- static get HasMajorPerformanceCaveat() {
- if (this._HasMajorPerformanceCaveat === null) {
- try {
- const tempcanvas = AbstractEngine._CreateCanvas(1, 1);
- const gl = tempcanvas.getContext("webgl", { failIfMajorPerformanceCaveat: true }) ||
- tempcanvas.getContext("experimental-webgl", { failIfMajorPerformanceCaveat: true });
- this._HasMajorPerformanceCaveat = !gl;
- }
- catch (e) {
- this._HasMajorPerformanceCaveat = false;
- }
- }
- return this._HasMajorPerformanceCaveat;
- }
- }
- ThinEngine._TempClearColorUint32 = new Uint32Array(4);
- ThinEngine._TempClearColorInt32 = new Int32Array(4);
- /** Use this array to turn off some WebGL2 features on known buggy browsers version */
- ThinEngine.ExceptionList = [
- { key: "Chrome/63.0", capture: "63\\.0\\.3239\\.(\\d+)", captureConstraint: 108, targets: ["uniformBuffer"] },
- { key: "Firefox/58", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
- { key: "Firefox/59", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
- { key: "Chrome/72.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
- { key: "Chrome/73.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
- { key: "Chrome/74.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
- { key: "Mac OS.+Chrome/71", capture: null, captureConstraint: null, targets: ["vao"] },
- { key: "Mac OS.+Chrome/72", capture: null, captureConstraint: null, targets: ["vao"] },
- { key: "Mac OS.+Chrome", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
- { key: "Chrome/12\\d\\..+?Mobile", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
- // desktop osx safari 15.4
- { key: ".*AppleWebKit.*(15.4).*Safari", capture: null, captureConstraint: null, targets: ["antialias", "maxMSAASamples"] },
- // mobile browsers using safari 15.4 on ios
- { key: ".*(15.4).*AppleWebKit.*Safari", capture: null, captureConstraint: null, targets: ["antialias", "maxMSAASamples"] },
- ];
- // Updatable statics so stick with vars here
- /**
- * Gets or sets the epsilon value used by collision engine
- */
- ThinEngine.CollisionsEpsilon = 0.001;
- // Statics
- ThinEngine._IsSupported = null;
- ThinEngine._HasMajorPerformanceCaveat = null;
- /**
- * Find the next highest power of two.
- * @param x Number to start search from.
- * @returns Next highest power of two.
- */
- ThinEngine.CeilingPOT = CeilingPOT;
- /**
- * Find the next lowest power of two.
- * @param x Number to start search from.
- * @returns Next lowest power of two.
- */
- ThinEngine.FloorPOT = FloorPOT;
- /**
- * Find the nearest power of two.
- * @param x Number to start search from.
- * @returns Next nearest power of two.
- */
- ThinEngine.NearestPOT = NearestPOT;
- /**
- * Get the closest exponent of two
- * @param value defines the value to approximate
- * @param max defines the maximum value to return
- * @param mode defines how to define the closest value
- * @returns closest exponent of two of the given value
- */
- ThinEngine.GetExponentOfTwo = GetExponentOfTwo;
- /**
- * Queue a new function into the requested animation frame pool (ie. this function will be executed by the browser (or the javascript engine) for the next frame)
- * @param func - the function to be called
- * @param requester - the object that will request the next frame. Falls back to window.
- * @returns frame number
- */
- ThinEngine.QueueNewFrame = QueueNewFrame;
- //# sourceMappingURL=thinEngine.js.map
|