var pas = {}; var rtl = { quiet: false, debug_load_units: false, debug_rtti: false, debug: function(){ if (rtl.quiet || !console || !console.log) return; console.log(arguments); }, error: function(s){ rtl.debug('Error: ',s); throw s; }, warn: function(s){ rtl.debug('Warn: ',s); }, hasString: function(s){ return rtl.isString(s) && (s.length>0); }, isArray: function(a) { return Array.isArray(a); }, isFunction: function(f){ return typeof(f)==="function"; }, isModule: function(m){ return rtl.isObject(m) && rtl.hasString(m.$name) && (pas[m.$name]===m); }, isImplementation: function(m){ return rtl.isObject(m) && rtl.isModule(m.$module) && (m.$module.$impl===m); }, isNumber: function(n){ return typeof(n)==="number"; }, isObject: function(o){ var s=typeof(o); return (typeof(o)==="object") && (o!=null); }, isString: function(s){ return typeof(s)==="string"; }, getNumber: function(n){ return typeof(n)==="number"?n:NaN; }, getChar: function(c){ return ((typeof(c)==="string") && (c.length===1)) ? c : ""; }, getObject: function(o){ return ((typeof(o)==="object") || (typeof(o)==='function')) ? o : null; }, isPasClass: function(type){ return (rtl.isObject(type) && type.hasOwnProperty('$classname') && rtl.isObject(type.$module)); }, isPasClassInstance: function(type){ return (rtl.isObject(type) && rtl.isPasClass(type.$class)); }, hexStr: function(n,digits){ return ("000000000000000"+n.toString(16).toUpperCase()).slice(-digits); }, m_loading: 0, m_loading_intf: 1, m_intf_loaded: 2, m_loading_impl: 3, // loading all used unit m_initializing: 4, // running initialization m_initialized: 5, module: function(module_name, intfuseslist, intfcode, impluseslist, implcode){ if (rtl.debug_load_units) rtl.debug('rtl.module name="'+module_name+'" intfuses='+intfuseslist+' impluses='+impluseslist+' hasimplcode='+rtl.isFunction(implcode)); if (!rtl.hasString(module_name)) rtl.error('invalid module name "'+module_name+'"'); if (!rtl.isArray(intfuseslist)) rtl.error('invalid interface useslist of "'+module_name+'"'); if (!rtl.isFunction(intfcode)) rtl.error('invalid interface code of "'+module_name+'"'); if (!(impluseslist==undefined) && !rtl.isArray(impluseslist)) rtl.error('invalid implementation useslist of "'+module_name+'"'); if (!(implcode==undefined) && !rtl.isFunction(implcode)) rtl.error('invalid implementation code of "'+module_name+'"'); if (pas[module_name]) rtl.error('module "'+module_name+'" is already registered'); var module = pas[module_name] = { $name: module_name, $intfuseslist: intfuseslist, $impluseslist: impluseslist, $state: rtl.m_loading, $intfcode: intfcode, $implcode: implcode, $impl: null, $rtti: Object.create(rtl.tSectionRTTI) }; module.$rtti.$module = module; if (implcode) module.$impl = { $module: module, $rtti: module.$rtti }; }, exitcode: 0, run: function(module_name){ function doRun(){ if (!rtl.hasString(module_name)) module_name='program'; if (rtl.debug_load_units) rtl.debug('rtl.run module="'+module_name+'"'); rtl.initRTTI(); var module = pas[module_name]; if (!module) rtl.error('rtl.run module "'+module_name+'" missing'); rtl.loadintf(module); rtl.loadimpl(module); if (module_name=='program'){ if (rtl.debug_load_units) rtl.debug('running $main'); var r = pas.program.$main(); if (rtl.isNumber(r)) rtl.exitcode = r; } } if (rtl.showUncaughtExceptions) { try{ doRun(); } catch(re) { var errMsg = re.hasOwnProperty('$class') ? re.$class.$classname : ''; errMsg += ((errMsg) ? ': ' : '') + (re.hasOwnProperty('fMessage') ? re.fMessage : re); alert('Uncaught Exception : '+errMsg); rtl.exitCode = 216; } } else { doRun(); } return rtl.exitcode; }, loadintf: function(module){ if (module.$state>rtl.m_loading_intf) return; // already finished if (rtl.debug_load_units) rtl.debug('loadintf: "'+module.$name+'"'); if (module.$state===rtl.m_loading_intf) rtl.error('unit cycle detected "'+module.$name+'"'); module.$state=rtl.m_loading_intf; // load interfaces of interface useslist rtl.loaduseslist(module,module.$intfuseslist,rtl.loadintf); // run interface if (rtl.debug_load_units) rtl.debug('loadintf: run intf of "'+module.$name+'"'); module.$intfcode(module.$intfuseslist); // success module.$state=rtl.m_intf_loaded; // Note: units only used in implementations are not yet loaded (not even their interfaces) }, loaduseslist: function(module,useslist,f){ if (useslist==undefined) return; for (var i in useslist){ var unitname=useslist[i]; if (rtl.debug_load_units) rtl.debug('loaduseslist of "'+module.$name+'" uses="'+unitname+'"'); if (pas[unitname]==undefined) rtl.error('module "'+module.$name+'" misses "'+unitname+'"'); f(pas[unitname]); } }, loadimpl: function(module){ if (module.$state>=rtl.m_loading_impl) return; // already processing if (module.$state0){ o = this[newinstancefnname](fnname,args); } else { o = Object.create(this); } o.$class = this; // Note: o.$class === Object.getPrototypeOf(o) o.$init(); try{ o[fnname].apply(o,args); if (o.AfterConstruction) o.AfterConstruction(); } catch($e){ o.$destroy; throw $e; } return o; }; c.$destroy = function(fnname){ if (this.BeforeDestruction) this.BeforeDestruction(); this[fnname](); this.$final; }; rtl.initClass(c,parent,name,initfn); }, tObjectDestroy: "Destroy", free: function(obj,name){ if (obj[name]==null) return; obj[name].$destroy(rtl.tObjectDestroy); obj[name]=null; }, freeLoc: function(obj){ if (obj==null) return; obj.$destroy(rtl.tObjectDestroy); return null; }, is: function(instance,type){ return type.isPrototypeOf(instance) || (instance===type); }, isExt: function(instance,type,mode){ // mode===1 means instance must be a Pascal class instance // mode===2 means instance must be a Pascal class // Notes: // isPrototypeOf and instanceof return false on equal // isPrototypeOf does not work for Date.isPrototypeOf(new Date()) // so if isPrototypeOf is false test with instanceof // instanceof needs a function on right side if (instance == null) return false; // Note: ==null checks for undefined too if ((typeof(type) !== 'object') && (typeof(type) !== 'function')) return false; if (instance === type){ if (mode===1) return false; if (mode===2) return rtl.isPasClass(instance); return true; } if (type.isPrototypeOf && type.isPrototypeOf(instance)){ if (mode===1) return rtl.isPasClassInstance(instance); if (mode===2) return rtl.isPasClass(instance); return true; } if ((typeof type == 'function') && (instance instanceof type)) return true; return false; }, Exception: null, EInvalidCast: null, EAbstractError: null, ERangeError: null, raiseE: function(typename){ var t = rtl[typename]; if (t==null){ var mod = pas.SysUtils; if (!mod) mod = pas.sysutils; if (mod){ t = mod[typename]; if (!t) t = mod[typename.toLowerCase()]; if (!t) t = mod['Exception']; if (!t) t = mod['exception']; } } if (t){ if (t.Create){ throw t.$create("Create"); } else if (t.create){ throw t.$create("create"); } } if (typename === "EInvalidCast") throw "invalid type cast"; if (typename === "EAbstractError") throw "Abstract method called"; if (typename === "ERangeError") throw "range error"; throw typename; }, as: function(instance,type){ if((instance === null) || rtl.is(instance,type)) return instance; rtl.raiseE("EInvalidCast"); }, asExt: function(instance,type,mode){ if((instance === null) || rtl.isExt(instance,type,mode)) return instance; rtl.raiseE("EInvalidCast"); }, createInterface: function(module, name, guid, fnnames, ancestor, initfn){ //console.log('createInterface name="'+name+'" guid="'+guid+'" names='+fnnames); var i = ancestor?Object.create(ancestor):{}; module[name] = i; i.$module = module; i.$name = name; i.$fullname = module.$name+'.'+name; i.$guid = guid; i.$guidr = null; i.$names = fnnames?fnnames:[]; if (rtl.isFunction(initfn)){ // rtti if (rtl.debug_rtti) rtl.debug('createInterface '+i.$fullname); var t = i.$module.$rtti.$Interface(name,{ "interface": i, module: module }); i.$rtti = t; if (ancestor) t.ancestor = ancestor.$rtti; if (!t.ancestor) t.ancestor = null; initfn.call(i); } return i; }, strToGUIDR: function(s,g){ var p = 0; function n(l){ var h = s.substr(p,l); p+=l; return parseInt(h,16); } p+=1; // skip { g.D1 = n(8); p+=1; // skip - g.D2 = n(4); p+=1; // skip - g.D3 = n(4); p+=1; // skip - if (!g.D4) g.D4=[]; g.D4[0] = n(2); g.D4[1] = n(2); p+=1; // skip - for(var i=2; i<8; i++) g.D4[i] = n(2); return g; }, guidrToStr: function(g){ if (g.$intf) return g.$intf.$guid; var h = rtl.hexStr; var s='{'+h(g.D1,8)+'-'+h(g.D2,4)+'-'+h(g.D3,4)+'-'+h(g.D4[0],2)+h(g.D4[1],2)+'-'; for (var i=2; i<8; i++) s+=h(g.D4[i],2); s+='}'; return s; }, createTGUID: function(guid){ var TGuid = (pas.System)?pas.System.TGuid:pas.system.tguid; var g = rtl.strToGUIDR(guid,new TGuid()); return g; }, getIntfGUIDR: function(intfTypeOrVar){ if (!intfTypeOrVar) return null; if (!intfTypeOrVar.$guidr){ var g = rtl.createTGUID(intfTypeOrVar.$guid); if (!intfTypeOrVar.hasOwnProperty('$guid')) intfTypeOrVar = Object.getPrototypeOf(intfTypeOrVar); g.$intf = intfTypeOrVar; intfTypeOrVar.$guidr = g; } return intfTypeOrVar.$guidr; }, addIntf: function (aclass, intf, map){ function jmp(fn){ if (typeof(fn)==="function"){ return function(){ return fn.apply(this.$o,arguments); }; } else { return function(){ rtl.raiseE('EAbstractError'); }; } } if(!map) map = {}; var t = intf; var item = Object.create(t); aclass.$intfmaps[intf.$guid] = item; do{ var names = t.$names; if (!names) break; for (var i=0; i=minval) && (i<=maxval)) return i; rtl.raiseE('ERangeError'); }, rcc: function(c,minval,maxval){ // range check char if ((typeof(c)==='string') && (c.length===1)){ var i = c.charCodeAt(0); if ((i>=minval) && (i<=maxval)) return c; } rtl.raiseE('ERangeError'); }, rcSetCharAt: function(s,index,c){ // range check setCharAt if ((typeof(s)!=='string') || (index<0) || (index>=s.length)) rtl.raiseE('ERangeError'); return rtl.setCharAt(s,index,c); }, rcCharAt: function(s,index){ // range check charAt if ((typeof(s)!=='string') || (index<0) || (index>=s.length)) rtl.raiseE('ERangeError'); return s.charAt(index); }, rcArrR: function(arr,index){ // range check read array if (Array.isArray(arr) && (typeof(index)==='number') && (index>=0) && (index2){ // arr,index1,index2,... arr=arr[index]; for (var i=2; i=0) && (indexsrcarray.length) end = srcarray.length; if (index>=end) return []; if (type===0){ return srcarray.slice(index,end); } else { var a = []; a.length = end-index; rtl.arrayClone(type,srcarray,index,end,a,0); return a; } }, setCharAt: function(s,index,c){ return s.substr(0,index)+c+s.substr(index+1); }, getResStr: function(mod,name){ var rs = mod.$resourcestrings[name]; return rs.current?rs.current:rs.org; }, createSet: function(){ var s = {}; for (var i=0; i newlen){ return s.substring(0,newlen); } else if (s.repeat){ // Note: repeat needs ECMAScript6! return s+' '.repeat(newlen-oldlen); } else { while (oldlen=width) return s; if (s.repeat){ // Note: repeat needs ECMAScript6! return ' '.repeat(width-l) + s; } else { while (l2){ return rtl.spaceLeft(d.toFixed(p),w); } else { // exponent width var pad = ""; var ad = Math.abs(d); if (ad<1.0e+10) { pad='00'; } else if (ad<1.0e+100) { pad='0'; } if (arguments.length<2) { w=9; } else if (w<9) { w=9; } var p = w-8; var s=(d>0 ? " " : "" ) + d.toExponential(p); s=s.replace(/e(.)/,'E$1'+pad); return rtl.spaceLeft(s,w); } }, initRTTI: function(){ if (rtl.debug_rtti) rtl.debug('initRTTI'); // base types rtl.tTypeInfo = { name: "tTypeInfo" }; function newBaseTI(name,kind,ancestor){ if (!ancestor) ancestor = rtl.tTypeInfo; if (rtl.debug_rtti) rtl.debug('initRTTI.newBaseTI "'+name+'" '+kind+' ("'+ancestor.name+'")'); var t = Object.create(ancestor); t.name = name; t.kind = kind; rtl[name] = t; return t; }; function newBaseInt(name,minvalue,maxvalue,ordtype){ var t = newBaseTI(name,1 /* tkInteger */,rtl.tTypeInfoInteger); t.minvalue = minvalue; t.maxvalue = maxvalue; t.ordtype = ordtype; return t; }; newBaseTI("tTypeInfoInteger",1 /* tkInteger */); newBaseInt("shortint",-0x80,0x7f,0); newBaseInt("byte",0,0xff,1); newBaseInt("smallint",-0x8000,0x7fff,2); newBaseInt("word",0,0xffff,3); newBaseInt("longint",-0x80000000,0x7fffffff,4); newBaseInt("longword",0,0xffffffff,5); newBaseInt("nativeint",-0x10000000000000,0xfffffffffffff,6); newBaseInt("nativeuint",0,0xfffffffffffff,7); newBaseTI("char",2 /* tkChar */); newBaseTI("string",3 /* tkString */); newBaseTI("tTypeInfoEnum",4 /* tkEnumeration */,rtl.tTypeInfoInteger); newBaseTI("tTypeInfoSet",5 /* tkSet */); newBaseTI("double",6 /* tkDouble */); newBaseTI("boolean",7 /* tkBool */); newBaseTI("tTypeInfoProcVar",8 /* tkProcVar */); newBaseTI("tTypeInfoMethodVar",9 /* tkMethod */,rtl.tTypeInfoProcVar); newBaseTI("tTypeInfoArray",10 /* tkArray */); newBaseTI("tTypeInfoDynArray",11 /* tkDynArray */); newBaseTI("tTypeInfoPointer",15 /* tkPointer */); var t = newBaseTI("pointer",15 /* tkPointer */,rtl.tTypeInfoPointer); t.reftype = null; newBaseTI("jsvalue",16 /* tkJSValue */); newBaseTI("tTypeInfoRefToProcVar",17 /* tkRefToProcVar */,rtl.tTypeInfoProcVar); // member kinds rtl.tTypeMember = {}; function newMember(name,kind){ var m = Object.create(rtl.tTypeMember); m.name = name; m.kind = kind; rtl[name] = m; }; newMember("tTypeMemberField",1); // tmkField newMember("tTypeMemberMethod",2); // tmkMethod newMember("tTypeMemberProperty",3); // tmkProperty // base object for storing members: a simple object rtl.tTypeMembers = {}; // tTypeInfoStruct - base object for tTypeInfoClass, tTypeInfoRecord, tTypeInfoInterface var tis = newBaseTI("tTypeInfoStruct",0); tis.$addMember = function(name,ancestor,options){ if (rtl.debug_rtti){ if (!rtl.hasString(name) || (name.charAt()==='$')) throw 'invalid member "'+name+'", this="'+this.name+'"'; if (!rtl.is(ancestor,rtl.tTypeMember)) throw 'invalid ancestor "'+ancestor+':'+ancestor.name+'", "'+this.name+'.'+name+'"'; if ((options!=undefined) && (typeof(options)!='object')) throw 'invalid options "'+options+'", "'+this.name+'.'+name+'"'; }; var t = Object.create(ancestor); t.name = name; this.members[name] = t; this.names.push(name); if (rtl.isObject(options)){ for (var key in options) if (options.hasOwnProperty(key)) t[key] = options[key]; }; return t; }; tis.addField = function(name,type,options){ var t = this.$addMember(name,rtl.tTypeMemberField,options); if (rtl.debug_rtti){ if (!rtl.is(type,rtl.tTypeInfo)) throw 'invalid type "'+type+'", "'+this.name+'.'+name+'"'; }; t.typeinfo = type; this.fields.push(name); return t; }; tis.addFields = function(){ var i=0; while(i $mod.MaxConsoleLines) { CurrentCount -= 1; $impl.LinesParent.removeChild($impl.LinesParent.firstChild); }; $impl.LastLine = document.createElement("div"); $impl.LastLine.className = "pasconsole"; $impl.LinesParent.appendChild($impl.LastLine); }; $impl.WriteConsole = function (S, NewLine) { var CL = ""; CL = $impl.LastLine.innerText; CL = CL + ("" + S); $impl.LastLine.innerText = CL; if (NewLine) { if ($mod.ConsoleLinesToBrowserLog) window.console.log(CL); $impl.AppendLine(); }; }; }); rtl.module("Mat4",["System","browserconsole","JS"],function () { "use strict"; var $mod = this; var $impl = $mod.$impl; rtl.createClass($mod,"TMat4",pas.System.TObject,function () { this.$init = function () { pas.System.TObject.$init.call(this); this.RawComponents = rtl.arraySetLength(null,0.0,4,4); }; this.$final = function () { this.RawComponents = undefined; pas.System.TObject.$final.call(this); }; this.Identity = function () { this.RawComponents[0][0] = 1.0; this.RawComponents[0][1] = 0.0; this.RawComponents[0][2] = 0.0; this.RawComponents[0][3] = 0.0; this.RawComponents[1][0] = 0.0; this.RawComponents[1][1] = 1.0; this.RawComponents[1][2] = 0.0; this.RawComponents[1][3] = 0.0; this.RawComponents[2][0] = 0.0; this.RawComponents[2][1] = 0.0; this.RawComponents[2][2] = 1.0; this.RawComponents[2][3] = 0.0; this.RawComponents[3][0] = 0.0; this.RawComponents[3][1] = 0.0; this.RawComponents[3][2] = 0.0; this.RawComponents[3][3] = 1.0; }; }); $mod.$init = function () { $impl.Matrix4x4Identity = $mod.TMat4.$create("Identity"); }; },null,function () { "use strict"; var $mod = this; var $impl = $mod.$impl; $impl.Matrix4x4Identity = null; }); rtl.module("webgl",["System","JS","Web"],function () { "use strict"; var $mod = this; }); rtl.module("SysUtils",["System","JS"],function () { "use strict"; var $mod = this; rtl.createClass($mod,"TFormatSettings",pas.System.TObject,function () { }); this.FormatSettings = null; $mod.$init = function () { $mod.FormatSettings = $mod.TFormatSettings.$create("Create"); }; }); rtl.module("GLUtils",["System","Mat4","browserconsole","Web","webgl","JS","SysUtils"],function () { "use strict"; var $mod = this; var $impl = $mod.$impl; rtl.createClass($mod,"TShader",pas.System.TObject,function () { this.$init = function () { pas.System.TObject.$init.call(this); this.gl = null; this.vertexShader = null; this.fragmentShader = null; this.programID = null; }; this.$final = function () { this.gl = undefined; this.vertexShader = undefined; this.fragmentShader = undefined; this.programID = undefined; pas.System.TObject.$final.call(this); }; this.Create$1 = function (context, vertexShaderSource, fragmentShaderSource) { this.gl = context; this.vertexShader = this.CreateShader(this.gl.VERTEX_SHADER,vertexShaderSource); this.fragmentShader = this.CreateShader(this.gl.FRAGMENT_SHADER,fragmentShaderSource); }; this.Compile = function () { this.programID = this.gl.createProgram(); this.gl.attachShader(this.programID,this.vertexShader); this.gl.attachShader(this.programID,this.fragmentShader); }; this.Link = function () { this.gl.linkProgram(this.programID); if (!this.gl.getProgramParameter(this.programID,this.gl.LINK_STATUS)) { $impl.Fatal(this.gl.getProgramInfoLog(this.programID)); }; }; this.Use = function () { this.gl.useProgram(this.programID); }; this.CreateShader = function (theType, source) { var Result = null; var shader = null; shader = this.gl.createShader(theType); if (shader === null) $impl.Fatal("create shader failed"); this.gl.shaderSource(shader,source); this.gl.compileShader(shader); if (this.gl.getShaderParameter(shader,this.gl.COMPILE_STATUS)) { return shader; } else { $impl.Fatal$1(this.gl.getShaderInfoLog(shader)); }; return Result; }; }); },null,function () { "use strict"; var $mod = this; var $impl = $mod.$impl; $impl.Fatal = function (messageString) { pas.System.Writeln("*** FATAL: ",messageString); return; }; $impl.Fatal$1 = function (messageString) { pas.System.Writeln("*** FATAL: ",messageString); return; }; }); rtl.module("program",["System","GLUtils","SysUtils","browserconsole","Web","webgl","JS"],function () { "use strict"; var $mod = this; this.gl = null; this.shader = null; this.canvas = null; this.stride = 0; this.offset = 0; this.vertexShaderSource = ""; this.fragmentShaderSource = ""; this.buffer = null; this.verts = null; $mod.$main = function () { $mod.canvas = document.createElement("canvas"); $mod.canvas.width = 300; $mod.canvas.height = 300; document.body.appendChild($mod.canvas); $mod.gl = $mod.canvas.getContext("webgl"); if ($mod.gl === null) { pas.System.Writeln("failed to load webgl!"); return; }; $mod.vertexShaderSource = document.getElementById("vertex.glsl").textContent; $mod.fragmentShaderSource = document.getElementById("fragment.glsl").textContent; $mod.shader = pas.GLUtils.TShader.$create("Create$1",[$mod.gl,$mod.vertexShaderSource,$mod.fragmentShaderSource]); $mod.shader.Compile(); $mod.shader.Link(); $mod.shader.Use(); $mod.gl.clearColor(0.9,0.9,0.9,1); $mod.gl.viewport(0,0,$mod.canvas.width,$mod.canvas.height); $mod.gl.clear($mod.gl.COLOR_BUFFER_BIT); $mod.verts = new Array(0,0,0,0.5,0.7,0); $mod.buffer = $mod.gl.createBuffer(); $mod.gl.bindBuffer($mod.gl.ARRAY_BUFFER,$mod.buffer); $mod.gl.bufferData($mod.gl.ARRAY_BUFFER,new Float32Array($mod.verts),$mod.gl.STATIC_DRAW); $mod.offset = 0; $mod.stride = 4 * 2; $mod.gl.enableVertexAttribArray(0); $mod.gl.vertexAttribPointer(0,2,$mod.gl.FLOAT,false,$mod.stride,$mod.offset); $mod.gl.drawArrays($mod.gl.TRIANGLES,0,3); }; });