GlDriver.hx 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245
  1. package h3d.impl;
  2. import h3d.impl.Driver;
  3. import h3d.mat.Pass;
  4. import h3d.mat.Stencil;
  5. import h3d.mat.Data;
  6. #if (js||cpp||hlsdl||psgl)
  7. #if js
  8. import js.html.Uint16Array;
  9. import js.html.Uint8Array;
  10. import js.html.Float32Array;
  11. private typedef GL = js.html.webgl.GL;
  12. private typedef Uniform = js.html.webgl.UniformLocation;
  13. private typedef Program = js.html.webgl.Program;
  14. private typedef GLShader = js.html.webgl.Shader;
  15. private typedef Framebuffer = js.html.webgl.Framebuffer;
  16. #elseif lime
  17. import lime.graphics.opengl.GL;
  18. private typedef Uniform = Dynamic;
  19. private typedef Program = lime.graphics.opengl.GLProgram;
  20. private typedef GLShader = lime.graphics.opengl.GLShader;
  21. private typedef Framebuffer = lime.graphics.opengl.GLFramebuffer;
  22. private typedef Uint16Array = lime.utils.UInt16Array;
  23. private typedef Uint8Array = lime.utils.UInt8Array;
  24. private typedef Float32Array = lime.utils.Float32Array;
  25. #elseif nme
  26. import nme.gl.GL;
  27. private typedef Uniform = Dynamic;
  28. private typedef Program = nme.gl.GLProgram;
  29. private typedef GLShader = nme.gl.GLShader;
  30. private typedef Framebuffer = nme.gl.Framebuffer;
  31. private typedef Uint16Array = nme.utils.Int16Array;
  32. private typedef Uint8Array = nme.utils.UInt8Array;
  33. private typedef Float32Array = nme.utils.Float32Array;
  34. #elseif hlsdl
  35. import sdl.GL;
  36. private typedef Uniform = sdl.GL.Uniform;
  37. private typedef Program = sdl.GL.Program;
  38. private typedef GLShader = sdl.GL.Shader;
  39. private typedef Framebuffer = sdl.GL.Framebuffer;
  40. private typedef Texture = h3d.impl.Driver.Texture;
  41. private typedef Query = h3d.impl.Driver.Query;
  42. private typedef VertexArray = sdl.GL.VertexArray;
  43. #if cpp
  44. private typedef Float32Array = Array<cpp.Float32>;
  45. #end
  46. #elseif psgl
  47. import psgl.GL;
  48. private typedef Uniform = psgl.GL.Uniform;
  49. private typedef Program = psgl.GL.Program;
  50. private typedef GLShader = psgl.GL.Shader;
  51. private typedef Framebuffer = psgl.GL.Framebuffer;
  52. private typedef Texture = h3d.impl.Driver.Texture;
  53. private typedef Query = h3d.impl.Driver.Query;
  54. private typedef VertexArray = psgl.GL.VertexArray;
  55. #end
  56. private class CompiledShader {
  57. public var s : GLShader;
  58. public var vertex : Bool;
  59. public var globals : Uniform;
  60. public var params : Uniform;
  61. public var textures : Array<Uniform>;
  62. public var cubeTextures : Array<Uniform>;
  63. public var shader : hxsl.RuntimeShader.RuntimeShaderData;
  64. public function new(s,vertex,shader) {
  65. this.s = s;
  66. this.vertex = vertex;
  67. this.shader = shader;
  68. }
  69. }
  70. private class CompiledAttribute {
  71. public var index : Int;
  72. public var type : Int;
  73. public var size : Int;
  74. public var offset : Int;
  75. public function new() {
  76. }
  77. }
  78. private class CompiledProgram {
  79. public var p : Program;
  80. public var vertex : CompiledShader;
  81. public var fragment : CompiledShader;
  82. public var stride : Int;
  83. public var attribNames : Array<String>;
  84. public var attribs : Array<CompiledAttribute>;
  85. public function new() {
  86. }
  87. }
  88. @:access(h3d.impl.Shader)
  89. #if (cpp||hlsdl||psgl)
  90. @:build(h3d.impl.MacroHelper.replaceGL())
  91. #end
  92. class GlDriver extends Driver {
  93. #if js
  94. var canvas : js.html.CanvasElement;
  95. var mrtExt : { function drawBuffersWEBGL( colors : Array<Int> ) : Void; };
  96. public var gl : js.html.webgl.RenderingContext;
  97. #end
  98. #if (hlsdl||psgl)
  99. var commonVA : VertexArray;
  100. #end
  101. var commonFB : Framebuffer;
  102. var curAttribs : Int;
  103. var curShader : CompiledProgram;
  104. var curBuffer : h3d.Buffer;
  105. var curIndexBuffer : IndexBuffer;
  106. var curMatBits : Int;
  107. var curStOpBits : Int;
  108. var curStFrBits : Int;
  109. var curStBrBits : Int;
  110. var curStEnabled : Bool;
  111. var defStencil : Stencil;
  112. var programs : Map<Int, CompiledProgram>;
  113. var frame : Int;
  114. var bufferWidth : Int;
  115. var bufferHeight : Int;
  116. var curTarget : h3d.mat.Texture;
  117. var numTargets : Int;
  118. var debug : Bool;
  119. var boundTextures : Array<Texture> = [];
  120. var shaderVersion : Null<Int>;
  121. var firstShader = true;
  122. public function new(antiAlias=0) {
  123. #if js
  124. canvas = @:privateAccess hxd.Stage.getInstance().canvas;
  125. gl = canvas.getContextWebGL({alpha:false,antialias:antiAlias>0});
  126. if( gl == null ) throw "Could not acquire GL context";
  127. // debug if webgl_debug.js is included
  128. untyped if( __js__('typeof')(WebGLDebugUtils) != "undefined" ) gl = untyped WebGLDebugUtils.makeDebugContext(gl);
  129. #end
  130. commonFB = gl.createFramebuffer();
  131. programs = new Map();
  132. curAttribs = 0;
  133. curMatBits = -1;
  134. defStencil = new Stencil();
  135. #if hlsdl
  136. var v : String = gl.getParameter(GL.VERSION);
  137. if( v.indexOf("ES") < 0 ){
  138. commonVA = gl.createVertexArray();
  139. gl.bindVertexArray( commonVA );
  140. }
  141. var reg = ~/[0-9]+\.[0-9]+/;
  142. var v : String = gl.getParameter(GL.SHADING_LANGUAGE_VERSION);
  143. if( v.indexOf("ES") < 0 &&reg.match(v) )
  144. shaderVersion = hxd.Math.imin( 150, Math.round( Std.parseFloat(reg.matched(0)) * 100 ) );
  145. gl.pixelStorei(GL.PACK_ALIGNMENT, 1);
  146. gl.pixelStorei(GL.UNPACK_ALIGNMENT, 1);
  147. gl.finish(); // prevent glError() on first bufferData
  148. #end
  149. }
  150. override function logImpl( str : String ) {
  151. #if js
  152. untyped console.log(str);
  153. #else
  154. Sys.println(str);
  155. #end
  156. }
  157. override function setDebug(d) {
  158. this.debug = d;
  159. }
  160. override function begin(frame) {
  161. this.frame = frame;
  162. resetStream();
  163. #if cpp
  164. curAttribs = 0;
  165. curMatBits = -1;
  166. #end
  167. gl.useProgram(null);
  168. curShader = null;
  169. curBuffer = null;
  170. }
  171. override function getShaderInputNames() {
  172. return curShader.attribNames;
  173. }
  174. override function getNativeShaderCode( shader : hxsl.RuntimeShader ) {
  175. return "// vertex:\n" + hxsl.GlslOut.toGlsl(shader.vertex.data) + "// fragment:\n" + hxsl.GlslOut.toGlsl(shader.fragment.data);
  176. }
  177. override public function getDriverName(details:Bool) {
  178. var render = gl.getParameter(GL.RENDERER);
  179. if( details )
  180. render += " GLv" + gl.getParameter(GL.VERSION);
  181. else
  182. render = render.split("/").shift(); // GeForce reports "/PCIe/SSE2" extension
  183. #if js
  184. render = render.split("WebGL ").join("");
  185. #end
  186. return "OpenGL "+render;
  187. }
  188. function compileShader( glout : hxsl.GlslOut, shader : hxsl.RuntimeShader.RuntimeShaderData ) {
  189. var type = shader.vertex ? GL.VERTEX_SHADER : GL.FRAGMENT_SHADER;
  190. var s = gl.createShader(type);
  191. var code = glout.run(shader.data);
  192. gl.shaderSource(s, code);
  193. gl.compileShader(s);
  194. var log = gl.getShaderInfoLog(s);
  195. if ( gl.getShaderParameter(s, GL.COMPILE_STATUS) != cast 1 ) {
  196. var log = gl.getShaderInfoLog(s);
  197. var lid = Std.parseInt(log.substr(9));
  198. var line = lid == null ? null : code.split("\n")[lid - 1];
  199. if( line == null ) line = "" else line = "(" + StringTools.trim(line) + ")";
  200. var codeLines = code.split("\n");
  201. for( i in 0...codeLines.length )
  202. codeLines[i] = (i+1) + "\t" + codeLines[i];
  203. throw "An error occurred compiling the shaders: " + log + line+"\n\n"+codeLines.join("\n");
  204. }
  205. return new CompiledShader(s, shader.vertex, shader);
  206. }
  207. function initShader( p : CompiledProgram, s : CompiledShader, shader : hxsl.RuntimeShader.RuntimeShaderData ) {
  208. var prefix = s.vertex ? "vertex" : "fragment";
  209. s.globals = gl.getUniformLocation(p.p, prefix + "Globals");
  210. s.params = gl.getUniformLocation(p.p, prefix + "Params");
  211. s.textures = [for( i in 0...shader.textures2DCount ) gl.getUniformLocation(p.p, prefix + "Textures[" + i + "]")];
  212. s.cubeTextures = [for( i in 0...shader.texturesCubeCount ) gl.getUniformLocation(p.p, prefix + "TexturesCube[" + i + "]")];
  213. }
  214. override function selectShader( shader : hxsl.RuntimeShader ) {
  215. var p = programs.get(shader.id);
  216. if( p == null ) {
  217. p = new CompiledProgram();
  218. var glout = new hxsl.GlslOut();
  219. if( shaderVersion != null )
  220. glout.version = shaderVersion;
  221. else
  222. glout.glES = true;
  223. p.vertex = compileShader(glout,shader.vertex);
  224. p.fragment = compileShader(glout,shader.fragment);
  225. p.p = gl.createProgram();
  226. #if hlsdl
  227. if( !glout.glES ) {
  228. var outCount = 0;
  229. for( v in shader.fragment.data.vars )
  230. switch( v.kind ) {
  231. case Output:
  232. gl.bindFragDataLocation(p.p, outCount++, glout.varNames.get(v.id));
  233. default:
  234. }
  235. }
  236. #end
  237. gl.attachShader(p.p, p.vertex.s);
  238. gl.attachShader(p.p, p.fragment.s);
  239. var log = null;
  240. try {
  241. gl.linkProgram(p.p);
  242. if( gl.getProgramParameter(p.p, GL.LINK_STATUS) != cast 1 )
  243. log = gl.getProgramInfoLog(p.p);
  244. } catch( e : Dynamic ) {
  245. throw "Shader linkage error: "+Std.string(e)+" ("+getDriverName(false)+")";
  246. }
  247. gl.deleteShader(p.vertex.s);
  248. gl.deleteShader(p.fragment.s);
  249. if( log != null ) {
  250. #if js
  251. gl.deleteProgram(p.p);
  252. #end
  253. #if hlsdl
  254. /*
  255. Tentative patch on some driver that report an higher shader version that it's allowed to use.
  256. */
  257. if( log == "" && shaderVersion > 130 && firstShader ) {
  258. shaderVersion -= 10;
  259. return selectShader(shader);
  260. }
  261. #end
  262. throw "Program linkage failure: "+log+"\nVertex=\n"+glout.run(shader.vertex.data)+"\n\nFragment=\n"+glout.run(shader.fragment.data);
  263. }
  264. firstShader = false;
  265. initShader(p, p.vertex, shader.vertex);
  266. initShader(p, p.fragment, shader.fragment);
  267. p.attribNames = [];
  268. p.attribs = [];
  269. p.stride = 0;
  270. for( v in shader.vertex.data.vars )
  271. switch( v.kind ) {
  272. case Input:
  273. var t = GL.FLOAT;
  274. var size = switch( v.type ) {
  275. case TVec(n, _): n;
  276. case TBytes(n): t = GL.BYTE; n;
  277. case TFloat: 1;
  278. default: throw "assert " + v.type;
  279. }
  280. var index = gl.getAttribLocation(p.p, glout.varNames.get(v.id));
  281. if( index < 0 ) {
  282. p.stride += size;
  283. continue;
  284. }
  285. var a = new CompiledAttribute();
  286. a.type = t;
  287. a.size = size;
  288. a.index = index;
  289. a.offset = p.stride;
  290. p.attribs.push(a);
  291. p.attribNames.push(v.name);
  292. p.stride += size;
  293. default:
  294. }
  295. programs.set(shader.id, p);
  296. }
  297. if( curShader == p ) return false;
  298. gl.useProgram(p.p);
  299. for( i in curAttribs...p.attribs.length ) {
  300. gl.enableVertexAttribArray(i);
  301. curAttribs++;
  302. }
  303. while( curAttribs > p.attribs.length )
  304. gl.disableVertexAttribArray(--curAttribs);
  305. curShader = p;
  306. curBuffer = null;
  307. for( i in 0...boundTextures.length )
  308. boundTextures[i] = null;
  309. return true;
  310. }
  311. override function uploadShaderBuffers( buf : h3d.shader.Buffers, which : h3d.shader.Buffers.BufferKind ) {
  312. uploadBuffer(curShader.vertex, buf.vertex, which);
  313. uploadBuffer(curShader.fragment, buf.fragment, which);
  314. }
  315. function uploadBuffer( s : CompiledShader, buf : h3d.shader.Buffers.ShaderBuffers, which : h3d.shader.Buffers.BufferKind ) {
  316. switch( which ) {
  317. case Globals:
  318. if( s.globals != null ) {
  319. #if hl
  320. gl.uniform4fv(s.globals, streamData(hl.Bytes.getArray(buf.globals.toData()), 0, s.shader.globalsSize * 16), 0, s.shader.globalsSize * 4);
  321. #else
  322. var a = buf.globals.subarray(0, s.shader.globalsSize * 4);
  323. gl.uniform4fv(s.globals, a);
  324. #end
  325. }
  326. case Params:
  327. if( s.params != null ) {
  328. #if hl
  329. gl.uniform4fv(s.params, streamData(hl.Bytes.getArray(buf.params.toData()), 0, s.shader.paramsSize * 16), 0, s.shader.paramsSize * 4);
  330. #else
  331. var a = buf.params.subarray(0, s.shader.paramsSize * 4);
  332. gl.uniform4fv(s.params, a);
  333. #end
  334. }
  335. case Textures:
  336. var tcount = s.textures.length;
  337. for( i in 0...s.textures.length + s.cubeTextures.length ) {
  338. var t = buf.tex[i];
  339. if( t == null || t.isDisposed() ) {
  340. var color = h3d.mat.Defaults.loadingTextureColor;
  341. t = h3d.mat.Texture.fromColor(color,(color>>>24)/255);
  342. }
  343. if( t != null && t.t == null && t.realloc != null ) {
  344. t.alloc();
  345. t.realloc();
  346. }
  347. t.lastFrame = frame;
  348. var isCube = i >= tcount;
  349. var pt = isCube ? s.cubeTextures[i - tcount] : s.textures[i];
  350. if( pt == null ) continue;
  351. if( boundTextures[i] == t.t ) continue;
  352. boundTextures[i] = t.t;
  353. var mode = isCube ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
  354. gl.activeTexture(GL.TEXTURE0 + i);
  355. gl.uniform1i(pt, i);
  356. gl.bindTexture(mode, t.t.t);
  357. var mip = Type.enumIndex(t.mipMap);
  358. var filter = Type.enumIndex(t.filter);
  359. var wrap = Type.enumIndex(t.wrap);
  360. var bits = mip | (filter << 3) | (wrap << 6);
  361. if( bits != t.t.bits ) {
  362. t.t.bits = bits;
  363. var flags = TFILTERS[mip][filter];
  364. gl.texParameteri(mode, GL.TEXTURE_MAG_FILTER, flags[0]);
  365. gl.texParameteri(mode, GL.TEXTURE_MIN_FILTER, flags[1]);
  366. var w = TWRAP[wrap];
  367. gl.texParameteri(mode, GL.TEXTURE_WRAP_S, w);
  368. gl.texParameteri(mode, GL.TEXTURE_WRAP_T, w);
  369. }
  370. }
  371. }
  372. }
  373. override function selectMaterial( pass : Pass ) {
  374. selectMaterialBits(@:privateAccess pass.bits);
  375. var s = defStencil;
  376. if( pass.stencil == null ) {
  377. if( curStEnabled ) {
  378. gl.disable(GL.STENCIL_TEST);
  379. curStEnabled = false;
  380. }
  381. } else {
  382. s = pass.stencil;
  383. if( !curStEnabled ) {
  384. gl.enable(GL.STENCIL_TEST);
  385. curStEnabled = true;
  386. }
  387. }
  388. @:privateAccess selectStencilBits(s.opBits, s.frontRefBits, s.backRefBits);
  389. // TODO : Blend Op value sync
  390. }
  391. function selectMaterialBits( bits : Int ) {
  392. var diff = bits ^ curMatBits;
  393. if( curMatBits < 0 ) diff = -1;
  394. if( diff == 0 )
  395. return;
  396. if( diff & Pass.culling_mask != 0 ) {
  397. var cull = Pass.getCulling(bits);
  398. if( cull == 0 )
  399. gl.disable(GL.CULL_FACE);
  400. else {
  401. if( curMatBits < 0 || Pass.getCulling(curMatBits) == 0 )
  402. gl.enable(GL.CULL_FACE);
  403. gl.cullFace(FACES[cull]);
  404. }
  405. }
  406. if( diff & (Pass.blendSrc_mask | Pass.blendDst_mask | Pass.blendAlphaSrc_mask | Pass.blendAlphaDst_mask) != 0 ) {
  407. var csrc = Pass.getBlendSrc(bits);
  408. var cdst = Pass.getBlendDst(bits);
  409. var asrc = Pass.getBlendAlphaSrc(bits);
  410. var adst = Pass.getBlendAlphaDst(bits);
  411. if( csrc == asrc && cdst == adst ) {
  412. if( csrc == 0 && cdst == 1 )
  413. gl.disable(GL.BLEND);
  414. else {
  415. if( curMatBits < 0 || (Pass.getBlendSrc(curMatBits) == 0 && Pass.getBlendDst(curMatBits) == 1) ) gl.enable(GL.BLEND);
  416. gl.blendFunc(BLEND[csrc], BLEND[cdst]);
  417. }
  418. } else {
  419. if( curMatBits < 0 || (Pass.getBlendSrc(curMatBits) == 0 && Pass.getBlendDst(curMatBits) == 1) ) gl.enable(GL.BLEND);
  420. gl.blendFuncSeparate(BLEND[csrc], BLEND[cdst], BLEND[asrc], BLEND[adst]);
  421. }
  422. }
  423. if( diff & (Pass.blendOp_mask | Pass.blendAlphaOp_mask) != 0 ) {
  424. var cop = Pass.getBlendOp(bits);
  425. var aop = Pass.getBlendAlphaOp(bits);
  426. if( cop == aop ) {
  427. #if (nme || openfl)
  428. if( OP[cop] != GL.FUNC_ADD )
  429. throw "blendEquation() disable atm (crash)";
  430. #else
  431. gl.blendEquation(OP[cop]);
  432. #end
  433. }
  434. else
  435. gl.blendEquationSeparate(OP[cop], OP[aop]);
  436. }
  437. if( diff & Pass.depthWrite_mask != 0 )
  438. gl.depthMask(Pass.getDepthWrite(bits) != 0);
  439. if( diff & Pass.depthTest_mask != 0 ) {
  440. var cmp = Pass.getDepthTest(bits);
  441. if( cmp == 0 )
  442. gl.disable(GL.DEPTH_TEST);
  443. else {
  444. if( curMatBits < 0 || Pass.getDepthTest(curMatBits) == 0 ) gl.enable(GL.DEPTH_TEST);
  445. gl.depthFunc(COMPARE[cmp]);
  446. }
  447. }
  448. if( diff & Pass.colorMask_mask != 0 ) {
  449. var m = Pass.getColorMask(bits);
  450. gl.colorMask(m & 1 != 0, m & 2 != 0, m & 4 != 0, m & 8 != 0);
  451. }
  452. curMatBits = bits;
  453. }
  454. function selectStencilBits( opBits : Int, frBits : Int, brBits : Int ) {
  455. var diffOp = opBits ^ curStOpBits;
  456. var diffFr = frBits ^ curStFrBits;
  457. var diffBr = brBits ^ curStBrBits;
  458. if ( (diffOp | diffFr | diffBr) == 0 ) return;
  459. if( diffOp & (Stencil.frontSTfail_mask | Stencil.frontDPfail_mask | Stencil.frontDPpass_mask) != 0 ) {
  460. gl.stencilOpSeparate(
  461. FACES[Type.enumIndex(Front)],
  462. STENCIL_OP[Stencil.getFrontSTfail(opBits)],
  463. STENCIL_OP[Stencil.getFrontDPfail(opBits)],
  464. STENCIL_OP[Stencil.getFrontDPpass(opBits)]);
  465. }
  466. if( diffOp & (Stencil.backSTfail_mask | Stencil.backDPfail_mask | Stencil.backDPpass_mask) != 0 ) {
  467. gl.stencilOpSeparate(
  468. FACES[Type.enumIndex(Back)],
  469. STENCIL_OP[Stencil.getBackSTfail(opBits)],
  470. STENCIL_OP[Stencil.getBackDPfail(opBits)],
  471. STENCIL_OP[Stencil.getBackDPpass(opBits)]);
  472. }
  473. if( (diffOp & Stencil.frontTest_mask) | (diffFr & (Stencil.frontRef_mask | Stencil.frontReadMask_mask)) != 0 ) {
  474. gl.stencilFuncSeparate(
  475. FACES[Type.enumIndex(Front)],
  476. COMPARE[Stencil.getFrontTest(opBits)],
  477. Stencil.getFrontRef(frBits),
  478. Stencil.getFrontReadMask(frBits));
  479. }
  480. if( (diffOp & Stencil.backTest_mask) | (diffBr & (Stencil.backRef_mask | Stencil.backReadMask_mask)) != 0 ) {
  481. gl.stencilFuncSeparate(
  482. FACES[Type.enumIndex(Back)],
  483. COMPARE[Stencil.getBackTest(opBits)],
  484. Stencil.getBackRef(brBits),
  485. Stencil.getBackReadMask(brBits));
  486. }
  487. if( diffFr & Stencil.frontWriteMask_mask != 0 )
  488. gl.stencilMaskSeparate(FACES[Type.enumIndex(Front)], Stencil.getFrontWriteMask(frBits));
  489. if( diffBr & Stencil.backWriteMask_mask != 0 )
  490. gl.stencilMaskSeparate(FACES[Type.enumIndex(Back)], Stencil.getBackWriteMask(brBits));
  491. curStOpBits = opBits;
  492. curStFrBits = frBits;
  493. curStBrBits = brBits;
  494. }
  495. override function clear( ?color : h3d.Vector, ?depth : Float, ?stencil : Int ) {
  496. var bits = 0;
  497. if( color != null ) {
  498. gl.colorMask(true, true, true, true);
  499. if( curMatBits >= 0 ) curMatBits |= Pass.colorMask_mask;
  500. gl.clearColor(color.r, color.g, color.b, color.a);
  501. bits |= GL.COLOR_BUFFER_BIT;
  502. }
  503. if( depth != null ) {
  504. gl.depthMask(true);
  505. if( curMatBits >= 0 ) curMatBits |= Pass.depthWrite_mask;
  506. gl.clearDepth(depth);
  507. bits |= GL.DEPTH_BUFFER_BIT;
  508. }
  509. if( stencil != null ) {
  510. // reset stencyl mask when we allow to change it
  511. @:privateAccess selectStencilBits(defStencil.opBits, defStencil.frontRefBits, defStencil.backRefBits);
  512. gl.clearStencil(stencil);
  513. bits |= GL.STENCIL_BUFFER_BIT;
  514. }
  515. if( bits != 0 ) gl.clear(bits);
  516. if( curTarget != null ) curTarget.flags.set(WasCleared);
  517. }
  518. override function resize(width, height) {
  519. #if js
  520. // prevent infinite grow if pixelRatio != 1
  521. if( canvas.style.width == "" ) {
  522. canvas.style.width = Std.int(width / js.Browser.window.devicePixelRatio)+"px";
  523. canvas.style.height = Std.int(height / js.Browser.window.devicePixelRatio)+"px";
  524. }
  525. canvas.width = width;
  526. canvas.height = height;
  527. #elseif cpp
  528. // resize window
  529. #end
  530. bufferWidth = width;
  531. bufferHeight = height;
  532. gl.viewport(0, 0, width, height);
  533. @:privateAccess if( defaultDepth != null ) {
  534. disposeDepthBuffer(defaultDepth);
  535. defaultDepth.width = this.bufferWidth;
  536. defaultDepth.height = this.bufferHeight;
  537. defaultDepth.b = allocDepthBuffer(defaultDepth);
  538. }
  539. }
  540. function getChannels( t : Texture ) {
  541. return switch( t.internalFmt ) {
  542. #if !js
  543. case GL.RGBA32F, GL.RGBA16F: GL.RGBA;
  544. case GL.ALPHA16F, GL.ALPHA32F: GL.ALPHA;
  545. case GL.RGBA8: GL.BGRA;
  546. #end
  547. case GL.RGBA: GL.RGBA;
  548. case GL.ALPHA: GL.ALPHA;
  549. default: throw "Invalid format " + t.internalFmt;
  550. }
  551. }
  552. override function isSupportedFormat( fmt : h3d.mat.Data.TextureFormat ) {
  553. return switch( fmt ) {
  554. case RGBA, ALPHA8: true;
  555. case RGBA32F: hasFeature(FloatTextures);
  556. #if !js
  557. case ALPHA16F, ALPHA32F, RGBA16F: hasFeature(FloatTextures);
  558. #end
  559. default: false;
  560. }
  561. }
  562. override function allocTexture( t : h3d.mat.Texture ) : Texture {
  563. var tt = gl.createTexture();
  564. var tt : Texture = { t : tt, width : t.width, height : t.height, internalFmt : GL.RGBA, pixelFmt : GL.UNSIGNED_BYTE, bits : -1 };
  565. switch( t.format ) {
  566. case RGBA:
  567. // default
  568. case ALPHA8:
  569. tt.internalFmt = GL.ALPHA;
  570. case RGBA32F if( hasFeature(FloatTextures) ):
  571. #if js
  572. tt.pixelFmt = GL.FLOAT;
  573. #else
  574. tt.internalFmt = GL.RGBA32F;
  575. tt.pixelFmt = GL.FLOAT;
  576. #end
  577. #if !js
  578. case BGRA:
  579. tt.internalFmt = GL.RGBA8;
  580. case RGBA16F if( hasFeature(FloatTextures) ):
  581. tt.pixelFmt = GL.HALF_FLOAT;
  582. tt.internalFmt = GL.RGBA16F;
  583. case ALPHA16F if( hasFeature(FloatTextures) ):
  584. tt.pixelFmt = GL.HALF_FLOAT;
  585. tt.internalFmt = GL.ALPHA16F;
  586. case ALPHA32F if( hasFeature(FloatTextures) ):
  587. tt.pixelFmt = GL.FLOAT;
  588. tt.internalFmt = GL.ALPHA32F;
  589. #end
  590. default:
  591. throw "Unsupported texture format "+t.format;
  592. }
  593. t.lastFrame = frame;
  594. t.flags.unset(WasCleared);
  595. var bind = t.flags.has(Cube) ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
  596. gl.bindTexture(bind, tt.t);
  597. var outOfMem = false;
  598. if( t.flags.has(Cube) ) {
  599. for( i in 0...6 ) {
  600. gl.texImage2D(CUBE_FACES[i], 0, tt.internalFmt, tt.width, tt.height, 0, getChannels(tt), tt.pixelFmt, null);
  601. if( gl.getError() == GL.OUT_OF_MEMORY ) {
  602. outOfMem = true;
  603. break;
  604. }
  605. }
  606. } else {
  607. gl.texImage2D(bind, 0, tt.internalFmt, tt.width, tt.height, 0, getChannels(tt), tt.pixelFmt, null);
  608. if( gl.getError() == GL.OUT_OF_MEMORY )
  609. outOfMem = true;
  610. }
  611. gl.bindTexture(bind, null);
  612. if( outOfMem ) {
  613. gl.deleteTexture(tt.t);
  614. return null;
  615. }
  616. return tt;
  617. }
  618. override function allocDepthBuffer( b : h3d.mat.DepthBuffer ) : DepthBuffer {
  619. var r = gl.createRenderbuffer();
  620. gl.bindRenderbuffer(GL.RENDERBUFFER, r);
  621. gl.renderbufferStorage(GL.RENDERBUFFER, #if hl GL.DEPTH_COMPONENT24 #else GL.DEPTH_COMPONENT16 #end, b.width, b.height);
  622. gl.bindRenderbuffer(GL.RENDERBUFFER, null);
  623. return { r : r };
  624. }
  625. override function disposeDepthBuffer( b : h3d.mat.DepthBuffer ) {
  626. @:privateAccess if( b.b != null && b.b.r != null ) {
  627. gl.deleteRenderbuffer(b.b.r);
  628. b.b = null;
  629. }
  630. }
  631. var defaultDepth : h3d.mat.DepthBuffer;
  632. override function getDefaultDepthBuffer() : h3d.mat.DepthBuffer {
  633. if( defaultDepth != null )
  634. return defaultDepth;
  635. defaultDepth = new h3d.mat.DepthBuffer(bufferWidth, bufferHeight);
  636. return defaultDepth;
  637. }
  638. override function allocVertexes( m : ManagedBuffer ) : VertexBuffer {
  639. var b = gl.createBuffer();
  640. gl.bindBuffer(GL.ARRAY_BUFFER, b);
  641. if( m.size * m.stride == 0 ) throw "assert";
  642. #if js
  643. gl.bufferData(GL.ARRAY_BUFFER, m.size * m.stride * 4, m.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
  644. #elseif hl
  645. gl.bufferDataSize(GL.ARRAY_BUFFER, m.size * m.stride * 4, m.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
  646. #else
  647. var tmp = new Uint8Array(m.size * m.stride * 4);
  648. gl.bufferData(GL.ARRAY_BUFFER, tmp, m.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
  649. #end
  650. var outOfMem = gl.getError() == GL.OUT_OF_MEMORY;
  651. gl.bindBuffer(GL.ARRAY_BUFFER, null);
  652. if( outOfMem ) {
  653. gl.deleteBuffer(b);
  654. return null;
  655. }
  656. return { b : b, stride : m.stride };
  657. }
  658. override function allocIndexes( count : Int ) : IndexBuffer {
  659. var b = gl.createBuffer();
  660. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, b);
  661. #if js
  662. gl.bufferData(GL.ELEMENT_ARRAY_BUFFER, count * 2, GL.STATIC_DRAW);
  663. #elseif hl
  664. gl.bufferDataSize(GL.ELEMENT_ARRAY_BUFFER, count * 2, GL.STATIC_DRAW);
  665. #else
  666. var tmp = new Uint16Array(count);
  667. gl.bufferData(GL.ELEMENT_ARRAY_BUFFER, tmp, GL.STATIC_DRAW);
  668. #end
  669. var outOfMem = gl.getError() == GL.OUT_OF_MEMORY;
  670. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
  671. curIndexBuffer = null;
  672. if( outOfMem ) {
  673. gl.deleteBuffer(b);
  674. return null;
  675. }
  676. return b;
  677. }
  678. override function disposeTexture( t : h3d.mat.Texture ) {
  679. var tt = t.t;
  680. if( tt == null ) return;
  681. t.t = null;
  682. gl.deleteTexture(tt.t);
  683. }
  684. override function disposeIndexes( i : IndexBuffer ) {
  685. gl.deleteBuffer(i);
  686. }
  687. override function disposeVertexes( v : VertexBuffer ) {
  688. gl.deleteBuffer(v.b);
  689. }
  690. override function generateMipMaps( t : h3d.mat.Texture ) {
  691. var bind = t.flags.has(Cube) ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
  692. gl.bindTexture(bind, t.t.t);
  693. gl.generateMipmap(bind);
  694. gl.bindTexture(bind, null);
  695. }
  696. override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
  697. #if (nme || hlsdl || psgl || openfl || lime)
  698. var pixels = bmp.getPixels();
  699. uploadTexturePixels(t, pixels, mipLevel, side);
  700. pixels.dispose();
  701. #else
  702. if( t.format != RGBA || t.flags.has(Cube) ) {
  703. var pixels = bmp.getPixels();
  704. uploadTexturePixels(t, pixels, mipLevel, side);
  705. pixels.dispose();
  706. } else {
  707. var img = bmp.toNative();
  708. gl.bindTexture(GL.TEXTURE_2D, t.t.t);
  709. #if js
  710. gl.pixelStorei(GL.UNPACK_FLIP_Y_WEBGL, 1);
  711. #end
  712. gl.texImage2D(GL.TEXTURE_2D, mipLevel, t.t.internalFmt, getChannels(t.t), t.t.pixelFmt, img.getImageData(0, 0, bmp.width, bmp.height));
  713. gl.bindTexture(GL.TEXTURE_2D, null);
  714. }
  715. #end
  716. }
  717. #if !(hlsdl || psgl)
  718. inline static function bytesToUint8Array( b : haxe.io.Bytes ) : Uint8Array {
  719. #if (lime && !js)
  720. return new Uint8Array(b);
  721. #else
  722. return new Uint8Array(b.getData());
  723. #end
  724. }
  725. #end
  726. /*
  727. GL async model create crashes if the GC free the memory that we send it.
  728. Instead, we will copy the data into a temp location before uploading.
  729. */
  730. static inline var STREAM_POS = #if hl 0 #else 1 #end;
  731. #if hl
  732. var streamKeep : Array<{ f : Int, b : hl.Bytes }> = [];
  733. var streamBytes : hl.Bytes;
  734. var streamLen : Int;
  735. var streamPos : Int;
  736. function expandStream(needed:Int) {
  737. GL.finish();
  738. // too much data in our tmp buffer, let's flush it
  739. if( streamPos > (needed >> 1) && needed > 16 << 20 ) {
  740. needed -= streamPos;
  741. streamPos = 0;
  742. if( needed < streamLen )
  743. return;
  744. }
  745. var newLen = streamLen == 0 ? 0x10000 : streamLen;
  746. while( newLen < needed )
  747. newLen = (newLen * 3) >> 1;
  748. var newBytes = new hl.Bytes(newLen);
  749. if( streamPos > 0 )
  750. newBytes.blit(0, streamBytes, 0, streamPos);
  751. streamLen = newLen;
  752. if( streamBytes != null ) streamKeep.push({ f : frame, b : streamBytes });
  753. streamBytes = newBytes;
  754. }
  755. #end
  756. function resetStream() {
  757. #if hl
  758. streamPos = 0;
  759. // keep during 2 frames
  760. while( streamKeep.length > 0 && streamKeep[0].f < frame - 1 ) streamKeep.shift();
  761. #end
  762. }
  763. inline function streamData(data, pos:Int, length:Int) {
  764. #if hl
  765. var needed = streamPos + length;
  766. if( needed > streamLen ) expandStream(needed);
  767. streamBytes.blit(streamPos, data, pos, length);
  768. data = streamBytes.offset(streamPos);
  769. streamPos += length;
  770. #end
  771. return data;
  772. }
  773. override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
  774. var cubic = t.flags.has(Cube);
  775. var bind = cubic ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
  776. var face = cubic ? CUBE_FACES[side] : GL.TEXTURE_2D;
  777. gl.bindTexture(bind, t.t.t);
  778. pixels.convert(t.format);
  779. #if hl
  780. pixels.setFlip(!cubic);
  781. gl.texImage2D(face, mipLevel, t.t.internalFmt, pixels.width, pixels.height, 0, getChannels(t.t), t.t.pixelFmt, streamData(pixels.bytes.getData(),pixels.offset,pixels.width*pixels.height*4));
  782. #elseif lime
  783. pixels.setFlip(!cubic);
  784. gl.texImage2D(face, mipLevel, t.t.internalFmt, pixels.width, pixels.height, 0, getChannels(t.t), t.t.pixelFmt, bytesToUint8Array(pixels.bytes));
  785. #else
  786. gl.pixelStorei(GL.UNPACK_FLIP_Y_WEBGL, cubic ? 0 : 1);
  787. gl.texImage2D(face, mipLevel, t.t.internalFmt, pixels.width, pixels.height, 0, getChannels(t.t), t.t.pixelFmt, bytesToUint8Array(pixels.bytes));
  788. #end
  789. gl.bindTexture(bind, null);
  790. }
  791. override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
  792. var stride : Int = v.stride;
  793. gl.bindBuffer(GL.ARRAY_BUFFER, v.b);
  794. #if hl
  795. var data = #if hl hl.Bytes.getArray(buf.getNative()) #else buf.getNative() #end;
  796. gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride * 4, streamData(data,bufPos * 4,vertexCount * stride * 4), bufPos * 4 * STREAM_POS, vertexCount * stride * 4);
  797. #else
  798. var buf : Float32Array = buf.getNative();
  799. var sub = new Float32Array(buf.buffer, bufPos * 4, vertexCount * stride);
  800. gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride * 4, sub);
  801. #end
  802. gl.bindBuffer(GL.ARRAY_BUFFER, null);
  803. }
  804. override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
  805. var stride : Int = v.stride;
  806. gl.bindBuffer(GL.ARRAY_BUFFER, v.b);
  807. #if hl
  808. gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride * 4, streamData(buf.getData(),bufPos * 4,vertexCount * stride * 4), bufPos * 4 * STREAM_POS, vertexCount * stride * 4);
  809. #else
  810. var buf = bytesToUint8Array(buf);
  811. var sub = new Uint8Array(buf.buffer, bufPos * 4, vertexCount * stride * 4);
  812. gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride * 4, sub);
  813. #end
  814. gl.bindBuffer(GL.ARRAY_BUFFER, null);
  815. }
  816. override function uploadIndexBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
  817. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, i);
  818. #if hl
  819. var data = #if hl hl.Bytes.getArray(buf.getNative()) #else buf.getNative() #end;
  820. gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice * 2, streamData(data,bufPos*2,indiceCount*2), bufPos * 2 * STREAM_POS, indiceCount * 2);
  821. #else
  822. var buf = new Uint16Array(buf.getNative());
  823. var sub = new Uint16Array(buf.buffer, bufPos * 2, indiceCount);
  824. gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice * 2, sub);
  825. #end
  826. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
  827. curIndexBuffer = null;
  828. }
  829. override function uploadIndexBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes , bufPos : Int ) {
  830. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, i);
  831. #if hl
  832. gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice * 2, streamData(buf.getData(),bufPos * 2, indiceCount * 2), bufPos * 2 * STREAM_POS, indiceCount * 2);
  833. #else
  834. var buf = bytesToUint8Array(buf);
  835. var sub = new Uint8Array(buf.buffer, bufPos * 2, indiceCount * 2);
  836. gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice * 2, sub);
  837. #end
  838. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
  839. curIndexBuffer = null;
  840. }
  841. override function selectBuffer( v : h3d.Buffer ) {
  842. if( v == curBuffer )
  843. return;
  844. if( curBuffer != null && v.buffer == curBuffer.buffer && v.buffer.flags.has(RawFormat) == curBuffer.flags.has(RawFormat) ) {
  845. curBuffer = v;
  846. return;
  847. }
  848. if( curShader == null )
  849. throw "No shader selected";
  850. curBuffer = v;
  851. var m = @:privateAccess v.buffer.vbuf;
  852. if( m.stride < curShader.stride )
  853. throw "Buffer stride (" + m.stride + ") and shader stride (" + curShader.stride + ") mismatch";
  854. gl.bindBuffer(GL.ARRAY_BUFFER, m.b);
  855. if( v.flags.has(RawFormat) ) {
  856. for( a in curShader.attribs ) {
  857. var pos = a.offset;
  858. gl.vertexAttribPointer(a.index, a.size, a.type, false, m.stride * 4, pos * 4);
  859. }
  860. } else {
  861. var offset = 8;
  862. for( i in 0...curShader.attribs.length ) {
  863. var a = curShader.attribs[i];
  864. var pos;
  865. switch( curShader.attribNames[i] ) {
  866. case "position":
  867. pos = 0;
  868. case "normal":
  869. if( m.stride < 6 ) throw "Buffer is missing NORMAL data, set it to RAW format ?" #if debug + @:privateAccess v.allocPos #end;
  870. pos = 3;
  871. case "uv":
  872. if( m.stride < 8 ) throw "Buffer is missing UV data, set it to RAW format ?" #if debug + @:privateAccess v.allocPos #end;
  873. pos = 6;
  874. case s:
  875. pos = offset;
  876. offset += a.size;
  877. if( offset > m.stride ) throw "Buffer is missing '"+s+"' data, set it to RAW format ?" #if debug + @:privateAccess v.allocPos #end;
  878. }
  879. gl.vertexAttribPointer(a.index, a.size, a.type, false, m.stride * 4, pos * 4);
  880. }
  881. }
  882. }
  883. override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
  884. for( a in curShader.attribs ) {
  885. gl.bindBuffer(GL.ARRAY_BUFFER, @:privateAccess buffers.buffer.buffer.vbuf.b);
  886. gl.vertexAttribPointer(a.index, a.size, a.type, false, buffers.buffer.buffer.stride * 4, buffers.offset * 4);
  887. buffers = buffers.next;
  888. }
  889. curBuffer = null;
  890. }
  891. override function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
  892. if( ibuf != curIndexBuffer ) {
  893. curIndexBuffer = ibuf;
  894. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, ibuf);
  895. }
  896. gl.drawElements(GL.TRIANGLES, ntriangles * 3, GL.UNSIGNED_SHORT, startIndex * 2);
  897. }
  898. override function present() {
  899. // no gl finish or flush !
  900. }
  901. override function isDisposed() {
  902. #if (nme || openfl) //lime ??
  903. return false;
  904. #else
  905. return gl.isContextLost();
  906. #end
  907. }
  908. override function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
  909. if( x == 0 && y == 0 && width < 0 && height < 0 )
  910. gl.disable(GL.SCISSOR_TEST);
  911. else {
  912. gl.enable(GL.SCISSOR_TEST);
  913. var th = curTarget == null ? bufferHeight : curTarget.height;
  914. gl.scissor(x, th - (y + height), width, height);
  915. }
  916. }
  917. inline function unbindTargets() {
  918. if( curTarget != null && numTargets > 1 ) {
  919. while( numTargets > 1 )
  920. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0 + (--numTargets), GL.TEXTURE_2D, null, 0);
  921. #if js
  922. if( mrtExt != null )
  923. mrtExt.drawBuffersWEBGL([GL.COLOR_ATTACHMENT0]);
  924. #elseif hlsdl
  925. gl.drawBuffers(1, CBUFFERS);
  926. #end
  927. }
  928. }
  929. override function setRenderTarget( tex : h3d.mat.Texture, face = 0, mipLevel = 0 ) {
  930. unbindTargets();
  931. curTarget = tex;
  932. if( tex == null ) {
  933. gl.bindFramebuffer(GL.FRAMEBUFFER, null);
  934. gl.viewport(0, 0, bufferWidth, bufferHeight);
  935. return;
  936. }
  937. #if js
  938. if( mipLevel > 0 ) throw "Cannot render to mipLevel, use upload() instead";
  939. #end
  940. if( tex.t == null )
  941. tex.alloc();
  942. if( tex.flags.has(MipMapped) && !tex.flags.has(WasCleared) ) {
  943. var bind = tex.flags.has(Cube) ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
  944. gl.bindTexture(bind, tex.t.t);
  945. gl.generateMipmap(bind);
  946. gl.bindTexture(bind, null);
  947. }
  948. tex.flags.set(WasCleared); // once we draw to, do not clear again
  949. tex.lastFrame = frame;
  950. gl.bindFramebuffer(GL.FRAMEBUFFER, commonFB);
  951. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, tex.flags.has(Cube) ? CUBE_FACES[face] : GL.TEXTURE_2D, tex.t.t, mipLevel);
  952. if( tex.depthBuffer != null )
  953. gl.framebufferRenderbuffer(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, @:privateAccess tex.depthBuffer.b.r);
  954. else
  955. gl.framebufferRenderbuffer(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, null);
  956. gl.viewport(0, 0, tex.width >> mipLevel, tex.height >> mipLevel);
  957. for( i in 0...boundTextures.length )
  958. boundTextures[i] = null;
  959. }
  960. override function setRenderTargets( textures : Array<h3d.mat.Texture> ) {
  961. unbindTargets();
  962. setRenderTarget(textures[0]);
  963. if( textures.length < 2 )
  964. return;
  965. numTargets = textures.length;
  966. for( i in 1...textures.length ) {
  967. var tex = textures[i];
  968. if( tex.t == null )
  969. tex.alloc();
  970. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0 + i, GL.TEXTURE_2D, tex.t.t, 0);
  971. tex.lastFrame = frame;
  972. tex.flags.set(WasCleared); // once we draw to, do not clear again
  973. }
  974. #if js
  975. if( mrtExt != null )
  976. mrtExt.drawBuffersWEBGL([for( i in 0...textures.length ) GL.COLOR_ATTACHMENT0 + i]);
  977. #elseif hlsdl
  978. gl.drawBuffers(textures.length, CBUFFERS);
  979. #end
  980. }
  981. override function init( onCreate : Bool -> Void, forceSoftware = false ) {
  982. #if js
  983. var ready = false;
  984. // wait until all assets have properly load
  985. if( js.Browser.document.readyState == 'complete' )
  986. haxe.Timer.delay(onCreate.bind(false), 1);
  987. else
  988. js.Browser.window.addEventListener("load", function(_) {
  989. if( !ready ) {
  990. ready = true;
  991. onCreate(false);
  992. }
  993. });
  994. #else
  995. haxe.Timer.delay(onCreate.bind(false), 1);
  996. #end
  997. }
  998. override function hasFeature( f : Feature ) : Bool {
  999. return switch( f ) {
  1000. #if (hlsdl || psgl)
  1001. case StandardDerivatives, FloatTextures, MultipleRenderTargets, Queries:
  1002. true; // runtime extension detect required ?
  1003. #else
  1004. case StandardDerivatives:
  1005. gl.getExtension('OES_standard_derivatives') != null;
  1006. case FloatTextures:
  1007. gl.getExtension('OES_texture_float') != null && gl.getExtension('OES_texture_float_linear') != null;
  1008. case MultipleRenderTargets:
  1009. #if js
  1010. mrtExt != null || (mrtExt = gl.getExtension('WEBGL_draw_buffers')) != null;
  1011. #else
  1012. false; // no support for glDrawBuffers in OpenFL
  1013. #end
  1014. case Queries:
  1015. false;
  1016. #end
  1017. case HardwareAccelerated:
  1018. true;
  1019. case AllocDepthBuffer:
  1020. true;
  1021. }
  1022. }
  1023. override function captureRenderBuffer( pixels : hxd.Pixels ) {
  1024. if( curTarget == null )
  1025. throw "Can't capture main render buffer in GL";
  1026. #if (js || hl)
  1027. gl.readPixels(0, 0, pixels.width, pixels.height, GL.RGBA, GL.UNSIGNED_BYTE, @:privateAccess pixels.bytes.b);
  1028. @:privateAccess pixels.innerFormat = RGBA;
  1029. pixels.flags.set(FlipY);
  1030. #end
  1031. }
  1032. #if hl
  1033. override function allocQuery(kind:QueryKind) {
  1034. return { q : GL.createQuery(), kind : kind };
  1035. }
  1036. override function deleteQuery( q : Query ) {
  1037. GL.deleteQuery(q.q);
  1038. q.q = null;
  1039. }
  1040. override function beginQuery( q : Query ) {
  1041. switch( q.kind ) {
  1042. case TimeStamp:
  1043. throw "use endQuery() for timestamp queries";
  1044. case Samples:
  1045. GL.beginQuery(GL.SAMPLES_PASSED, q.q);
  1046. }
  1047. }
  1048. override function endQuery( q : Query ) {
  1049. switch( q.kind ) {
  1050. case TimeStamp:
  1051. GL.queryCounter(q.q, GL.TIMESTAMP);
  1052. case Samples:
  1053. GL.endQuery(GL.SAMPLES_PASSED);
  1054. }
  1055. }
  1056. override function queryResultAvailable(q:Query) {
  1057. return GL.queryResultAvailable(q.q);
  1058. }
  1059. override function queryResult(q:Query) {
  1060. return GL.queryResult(q.q);
  1061. }
  1062. #end
  1063. static var TFILTERS = [
  1064. [[GL.NEAREST,GL.NEAREST],[GL.LINEAR,GL.LINEAR]],
  1065. [[GL.NEAREST,GL.NEAREST_MIPMAP_NEAREST],[GL.LINEAR,GL.LINEAR_MIPMAP_NEAREST]],
  1066. [[GL.NEAREST,GL.NEAREST_MIPMAP_LINEAR],[GL.LINEAR,GL.LINEAR_MIPMAP_LINEAR]],
  1067. ];
  1068. static var TWRAP = [
  1069. GL.CLAMP_TO_EDGE,
  1070. GL.REPEAT,
  1071. ];
  1072. static var FACES = [
  1073. 0,
  1074. GL.FRONT,
  1075. GL.BACK,
  1076. GL.FRONT_AND_BACK,
  1077. ];
  1078. static var BLEND = [
  1079. GL.ONE,
  1080. GL.ZERO,
  1081. GL.SRC_ALPHA,
  1082. GL.SRC_COLOR,
  1083. GL.DST_ALPHA,
  1084. GL.DST_COLOR,
  1085. GL.ONE_MINUS_SRC_ALPHA,
  1086. GL.ONE_MINUS_SRC_COLOR,
  1087. GL.ONE_MINUS_DST_ALPHA,
  1088. GL.ONE_MINUS_DST_COLOR,
  1089. GL.CONSTANT_COLOR,
  1090. GL.CONSTANT_ALPHA,
  1091. GL.ONE_MINUS_CONSTANT_COLOR,
  1092. GL.ONE_MINUS_CONSTANT_ALPHA,
  1093. GL.SRC_ALPHA_SATURATE,
  1094. ];
  1095. static var COMPARE = [
  1096. GL.ALWAYS,
  1097. GL.NEVER,
  1098. GL.EQUAL,
  1099. GL.NOTEQUAL,
  1100. GL.GREATER,
  1101. GL.GEQUAL,
  1102. GL.LESS,
  1103. GL.LEQUAL,
  1104. ];
  1105. static var STENCIL_OP = [
  1106. GL.KEEP,
  1107. GL.ZERO,
  1108. GL.REPLACE,
  1109. GL.INCR,
  1110. GL.INCR_WRAP,
  1111. GL.DECR,
  1112. GL.DECR_WRAP,
  1113. GL.INVERT,
  1114. ];
  1115. static var OP = [
  1116. GL.FUNC_ADD,
  1117. GL.FUNC_SUBTRACT,
  1118. GL.FUNC_REVERSE_SUBTRACT
  1119. ];
  1120. static var CUBE_FACES = [
  1121. GL.TEXTURE_CUBE_MAP_POSITIVE_X,
  1122. GL.TEXTURE_CUBE_MAP_NEGATIVE_X,
  1123. GL.TEXTURE_CUBE_MAP_POSITIVE_Y,
  1124. GL.TEXTURE_CUBE_MAP_NEGATIVE_Y,
  1125. GL.TEXTURE_CUBE_MAP_POSITIVE_Z,
  1126. GL.TEXTURE_CUBE_MAP_NEGATIVE_Z,
  1127. ];
  1128. #if hlsdl
  1129. static var CBUFFERS = hl.Bytes.getArray([for( i in 0...32 ) GL.COLOR_ATTACHMENT0 + i]);
  1130. #end
  1131. }
  1132. #end