Skip to content
Commits on Source (2)
...@@ -8,7 +8,7 @@ from flask_restx import Namespace, Resource ...@@ -8,7 +8,7 @@ from flask_restx import Namespace, Resource
from .data_access_object import ObservationBlockObject from .data_access_object import ObservationBlockObject
from .data_access_object import SetupObject from .data_access_object import SetupObject
from util.instances import dao tpl from util.instances import dao, tpl
api = Namespace('blocks', description='Observation blocks') api = Namespace('blocks', description='Observation blocks')
......
...@@ -6,7 +6,7 @@ from flask_restx import Namespace, Resource, fields ...@@ -6,7 +6,7 @@ from flask_restx import Namespace, Resource, fields
# Custom modules # Custom modules
from util import exception from util import exception
from util.instances import seq dao from util.instances import seq, dao
api = Namespace('sequencer', description='Sequencer') api = Namespace('sequencer', description='Sequencer')
......
...@@ -10,7 +10,7 @@ import sys ...@@ -10,7 +10,7 @@ import sys
# Third-party modules # Third-party modules
from flask import Flask, request from flask import Flask, request
from flask_cors import CORS #from flask_cors import CORS
from werkzeug.exceptions import HTTPException from werkzeug.exceptions import HTTPException
# Custom modules # Custom modules
...@@ -19,7 +19,7 @@ import api ...@@ -19,7 +19,7 @@ import api
app = Flask(__name__) app = Flask(__name__)
app.register_blueprint(api.api_blueprint, url_prefix='/api') app.register_blueprint(api.api_blueprint, url_prefix='/api')
app.threaded = True app.threaded = True
cors = CORS(app) #cors = CORS(app)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -191,17 +191,17 @@ class SHARKNIR_cal_tec_NCPA_PD_lab(SHINSApp): ...@@ -191,17 +191,17 @@ class SHARKNIR_cal_tec_NCPA_PD_lab(SHINSApp):
# from util import master_listener_davide # from util import master_listener_davide
# thread = master_listener_davide.PLOT_THREAD() # thread = master_listener_davide.PLOT_THREAD()
thread.start() # thread.start()
thread.RUN = True # thread.RUN = True
print("plot thread started") # print("plot thread started")
flat_name = ufun.save_flat(self.obsController, thread) flat_name = ufun.save_flat(self.obsController, thread)
logger.info("Save DM flat file... DONE") logger.info("Save DM flat file... DONE")
logger.info(flat_name) logger.info(flat_name)
thread.CLOSE = True # thread.CLOSE = True
thread.RUN = False # thread.RUN = False
print("plot thread stopped") # print("plot thread stopped")
logger.info("Flaten DM") logger.info("Flaten DM")
modes = [0] * 39 modes = [0] * 39
......
...@@ -8,11 +8,12 @@ import numpy as np ...@@ -8,11 +8,12 @@ import numpy as np
from tpl.shinsapp import SHINSApp from tpl.shinsapp import SHINSApp
from util import functions as ufun from util import functions as ufun
from util.mini_os import obsController
class DevicesObject(object): class DevicesObject(object):
def __init__(self): def __init__(self):
self.mini_os = SHINSApp() self.obsController = obsController
self.obsController = self.mini_os.os()
self.json_state = {} self.json_state = {}
self.soul_deltas = [-999,-999] self.soul_deltas = [-999,-999]
......
...@@ -219,7 +219,7 @@ class PLOT_THREAD(threading.Thread): ...@@ -219,7 +219,7 @@ class PLOT_THREAD(threading.Thread):
num_frames = 0 num_frames = 0
restart = 0 restart = 0
img_frame = [] img_frame = []
time.sleep(0.01) time.sleep(0.001)
if self.CLOSE: if self.CLOSE:
break break
...@@ -234,7 +234,7 @@ class PLOT_THREAD(threading.Thread): ...@@ -234,7 +234,7 @@ class PLOT_THREAD(threading.Thread):
# Instance # Instance
########### ###########
thread = master_listener_davide.PLOT_THREAD() thread = PLOT_THREAD()
try: try:
thread.start() thread.start()
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''Unique sequencer instance for all APIs'''
# Custom modules
from tpl.shinsapp import SHINSApp
mini_os = SHINSApp()
obsController = mini_os.os()
...@@ -7,10 +7,12 @@ import datetime ...@@ -7,10 +7,12 @@ import datetime
import numpy as np import numpy as np
from astropy.time import Time from astropy.time import Time
from tpl.shinsapp import SHINSApp
from util import functions as ufun from util import functions as ufun
from util import variables as uvars from util import variables as uvars
from util.master_listener_davide import thread from util.master_listener_davide import thread
from util.mini_os import obsController
signs_list = [] signs_list = []
with open(str(uvars.sign_map), "r") as f: with open(str(uvars.sign_map), "r") as f:
...@@ -24,32 +26,12 @@ class RtcObject(object): ...@@ -24,32 +26,12 @@ class RtcObject(object):
def __init__(self): def __init__(self):
self.counter = 0 self.counter = 0
self.todos = [] self.todos = []
self.mini_os = SHINSApp()
self.obsController = self.mini_os.os()
self.rotating_ncpa = False self.rotating_ncpa = False
self.ncpa_file = "No file" self.ncpa_file = "No file"
self.json_state = {} self.json_state = {}
self.thread = thread self.thread = thread
# try: self.obsController = obsController
# self.thread.start()
# self.thread.RUN = True
# print("plot thread started")
# except KeyboardInterrupt:
# print(" Intercepted Keyboard Interrupt")
# self.thread.CLOSE = True
# self.thread.RUN = False
# del self.obsController
# print("plot thread stopped")
# sys.exit(1)
# except Exception as e:
# print("here")
# print(e)
# self.thread.CLOSE = True
# self.thread.RUN = False
# del self.obsController
# print("plot thread stopped")
# sys.exit(1)
def reset(self): def reset(self):
print("reset") print("reset")
......
...@@ -21,10 +21,6 @@ ...@@ -21,10 +21,6 @@
<!-- SHARK-NIR Specific --> <!-- SHARK-NIR Specific -->
<script type="text/javascript" >
// var api_base_url = "{{ ext_base_url|safe }}"
</script>
{% block head %} {% block head %}
{% endblock head %} {% endblock head %}
......
{% if not included %}
{% extends 'index.html' %}
{% block title %}
Output
{% endblock title %}
{% endif %}
{% block head %}
<!-- Externals -->
<script src="/static/js/webgl-utils.js"></script>
<!-- Mine -->
<script src="/static/colorbars.js"></script>
<script src="/static/draw-webgl.js"></script>
{% endblock head %}
{% set included = True %}
{% block content %}
<div id="webgl" class="form mt-2 row">
<div class="col">
<figure class="card">
<canvas id="canvas-webgl" class="card-img-top"
data-status="canvas-webgl"
alt="canvas webgl">
</canvas>
<figcaption class="card-body">
<h5 class="card-title">Webgl FITS</h5>
<fieldset class="row">
<div class="row mt-2">
<div class="input-group col">
<button data-control="get-fits-api" class="btn btn-primary w-100" type="button"
>Display http</button>
</div>
</div>
<div class="row mt-2">
<div class="input-group col">
<button data-control="get-fits" class="btn btn-primary w-100" type="button"
>Display websocket</button>
</div>
</div>
<label for="min_value">min</label>
<input id="min_value" type="number" min="0" max="65535" value="0" step="1">
<label for="max_value">max</label>
<input id="max_value" type="number" min="0" max="65535" value="56635" step="1">
<label for="scale_factor">scale</label>
<input id="scale_factor" type="number" min="0" max="10" value="1" step="0.1">
<label for="x_0">x0</label>
<input id="x_0" type="number" min="0" value="0" step="1">
<label for="y_0">y0</label>
<input id="y_0" type="number" min="0" value="0" step="1">
</fieldset>
<aside class="row mt-2">
</aside>
</figcaption>
</figure>
</div>
</div>
<script>
var matrix;
// $(document).on("click",'[data-control="get-fits-api"]', function(e){
// const ref = new Date().getTime()/1000
// e.preventDefault();
// $(this).crud("GET", "/web/other/fits/", null, false).then(function(e){
// console.log("here")
// })
// });
// $(document).on("click",'[data-control="get-fits"]', function(e){
// const ref = new Date().getTime()/1000
// e.preventDefault();
// button = $(this)
// button.prop('disabled', true);
// socket.emit('send_fits');
// });
socket.on('data_fits',function(data){
matrix = data
drawMatrixWithWebGL(matrix, "canvas-webgl", 1, 0, 0, false)
$('[data-control="get-fits"]').prop('disabled', false);
console.log(difftime(data.timestamp))
})
socket.on('data_binary', function(data) {
console.log("arrived")
// // Event listeners for min and max value inputs
// var minValue = parseFloat(document.getElementById("min_value").value);
// var maxValue = parseFloat(document.getElementById("max_value").value);
// var scaleFactor = parseFloat(document.getElementById("scale_factor").value);
// var x0 = parseFloat(document.getElementById("x_0").value);
// var y0 = parseFloat(document.getElementById("y_0").value);
// var binaryData = data.data
// var diff1 = difftime(data.timestamp)
// var matrixData = reform(binaryData, data.shape[0], data.shape[1], data.dtype);
// var diff2 = difftime(data.timestamp)
// drawMatrixWithWebGL(matrixData, "matrixBinary", scaleFactor, x0, y0)
// var diff3 = difftime(data.timestamp)
// // matrix = data
// // drawMatrixWithWebGL(matrix, "canvas-webgl", scaleFactor, x0, y0, false)
// var diff4 = difftime(data.timestamp)
// console.log("arrived, reformed, js canvas, webgl",
// diff1,
// (diff2-diff1).toFixed(3),
// (diff3-diff2).toFixed(3),
// (diff4-diff3).toFixed(3) )
});
$("#scale_factor").change(function(e){
console.log("changed")
const val = +$(this).val()
drawMatrixWithWebGL(matrix, "canvas-webgl", val , 0, 0, false)
});
</script>
<script id="vertex-shader-2d" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
// Convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// Convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// Convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
// Pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
v_texCoord = a_texCoord;
}
</script>
<script id="fragment-shader-2d" type="x-shader/x-fragment">
// Precision
precision mediump float;
// Our texture
uniform sampler2D u_image;
// The texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
gl_FragColor = texture2D(u_image, v_texCoord);
}
</script>
{% endblock content %}
{% block footer %}
{% endblock footer %}
...@@ -20,16 +20,10 @@ def enable(app): ...@@ -20,16 +20,10 @@ def enable(app):
app.register_blueprint(routes.web, url_prefix='/web') app.register_blueprint(routes.web, url_prefix='/web')
# base_url = {"ext_base_url": "http://sharnirws.shark-nir.lbto.org:5001", # what browser needs
# "int_base_url": "http://192.168.61.113:5001"} # what server needs
# @app.context_processor
# def inject_variables():
# return base_url
socketio = SocketIO(app, socketio = SocketIO(app,
path="/web/socket", path="/web/socket",
async_mode='threading', async_mode='threading',
# transports=["websocket"],
threaded=True) threaded=True)
connected_clients = {} connected_clients = {}
...@@ -74,7 +68,7 @@ def enable(app): ...@@ -74,7 +68,7 @@ def enable(app):
def error_handler(e): def error_handler(e):
print('ERROR: {}'.format(e)) print('ERROR: {}'.format(e))
# socketio.start_background_task(send_binary, socketio=socketio)
socketio.start_background_task(stream.send_timestamp, socketio=socketio) socketio.start_background_task(stream.send_timestamp, socketio=socketio)
socketio.start_background_task(stream.send_status, socketio=socketio, socketio.start_background_task(stream.send_status, socketio=socketio,
...@@ -84,5 +78,7 @@ def enable(app): ...@@ -84,5 +78,7 @@ def enable(app):
socketio.start_background_task(stream.tail_f, socketio=socketio, socketio.start_background_task(stream.tail_f, socketio=socketio,
name="new-lines") name="new-lines")
# socketio.start_background_task(stream.send_binary, socketio=socketio)
return socketio return socketio
...@@ -85,6 +85,7 @@ def blocks(): ...@@ -85,6 +85,7 @@ def blocks():
data = sorted(dao.todos) data = sorted(dao.todos)
return render_template("blocks.html", data=data) return render_template("blocks.html", data=data)
@web.route("/blocks/<string:name>/") @web.route("/blocks/<string:name>/")
def blocks_name(name): def blocks_name(name):
"""Show a selected OB, update it, or add a new """Show a selected OB, update it, or add a new
...@@ -163,3 +164,12 @@ def rtcTest(): ...@@ -163,3 +164,12 @@ def rtcTest():
ncpas = RTC.todos_ncpa() ncpas = RTC.todos_ncpa()
return render_template("rtc.html", data=data, darks=darks, return render_template("rtc.html", data=data, darks=darks,
flats=flats, gains=gains, ncpas=ncpas) flats=flats, gains=gains, ncpas=ncpas)
###########
# Tests
###########
@web.route("/webgl")
def webglTest():
data = {}
return render_template("webgl.html", data=data)
...@@ -52,12 +52,7 @@ def send_status(socketio, name, url, sleep=1, once=False): ...@@ -52,12 +52,7 @@ def send_status(socketio, name, url, sleep=1, once=False):
while not once: while not once:
socketio.sleep(sleep) socketio.sleep(sleep)
with app.test_client() as client: with app.test_client() as client:
res = client.get(url).get_json() res = client.get(url).get_json()
# if name=="rtc-status":
# print(res["cred"]["data"][40][40:60])
# if name=="json-status":
# print(res["sasha_temp"])
status.last[name] = res status.last[name] = res
socketio.emit(name, res) socketio.emit(name, res)
# if res != old: # if res != old:
...@@ -101,8 +96,8 @@ def send_binary(socketio): ...@@ -101,8 +96,8 @@ def send_binary(socketio):
# Third-party modules # Third-party modules
import numpy as np import numpy as np
# while True: while True:
for i in range(1): # for i in range(1):
dtype = "uint16" dtype = "uint16"
shape = (248,248) shape = (248,248)
matrix = np.random.uniform(0, 65535, shape).astype(dtype) matrix = np.random.uniform(0, 65535, shape).astype(dtype)
...@@ -115,7 +110,7 @@ def send_binary(socketio): ...@@ -115,7 +110,7 @@ def send_binary(socketio):
"timestamp": unix, "timestamp": unix,
} }
socketio.emit('data_bundle', data_bundle) socketio.emit('data_binary', data_bundle)
print((to_seconds(datetime.utcnow())-unix), "emitted") print((to_seconds(datetime.utcnow())-unix), "emitted")
print("bin {}".format(len(binary_data))) print("bin {}".format(len(binary_data)))
......
const viridis = [[68, 1, 84], [68, 2, 85], [68, 3, 87], [69, 5, 88], [69, 6, 90], [69, 8, 91], [70, 9, 92], [70, 11, 94], [70, 12, 95], [70, 14, 97], [71, 15, 98], [71, 17, 99], [71, 18, 101], [71, 20, 102], [71, 21, 103], [71, 22, 105], [71, 24, 106], [72, 25, 107], [72, 26, 108], [72, 28, 110], [72, 29, 111], [72, 30, 112], [72, 32, 113], [72, 33, 114], [72, 34, 115], [72, 35, 116], [71, 37, 117], [71, 38, 118], [71, 39, 119], [71, 40, 120], [71, 42, 121], [71, 43, 122], [71, 44, 123], [70, 45, 124], [70, 47, 124], [70, 48, 125], [70, 49, 126], [69, 50, 127], [69, 52, 127], [69, 53, 128], [69, 54, 129], [68, 55, 129], [68, 57, 130], [67, 58, 131], [67, 59, 131], [67, 60, 132], [66, 61, 132], [66, 62, 133], [66, 64, 133], [65, 65, 134], [65, 66, 134], [64, 67, 135], [64, 68, 135], [63, 69, 135], [63, 71, 136], [62, 72, 136], [62, 73, 137], [61, 74, 137], [61, 75, 137], [61, 76, 137], [60, 77, 138], [60, 78, 138], [59, 80, 138], [59, 81, 138], [58, 82, 139], [58, 83, 139], [57, 84, 139], [57, 85, 139], [56, 86, 139], [56, 87, 140], [55, 88, 140], [55, 89, 140], [54, 90, 140], [54, 91, 140], [53, 92, 140], [53, 93, 140], [52, 94, 141], [52, 95, 141], [51, 96, 141], [51, 97, 141], [50, 98, 141], [50, 99, 141], [49, 100, 141], [49, 101, 141], [49, 102, 141], [48, 103, 141], [48, 104, 141], [47, 105, 141], [47, 106, 141], [46, 107, 142], [46, 108, 142], [46, 109, 142], [45, 110, 142], [45, 111, 142], [44, 112, 142], [44, 113, 142], [44, 114, 142], [43, 115, 142], [43, 116, 142], [42, 117, 142], [42, 118, 142], [42, 119, 142], [41, 120, 142], [41, 121, 142], [40, 122, 142], [40, 122, 142], [40, 123, 142], [39, 124, 142], [39, 125, 142], [39, 126, 142], [38, 127, 142], [38, 128, 142], [38, 129, 142], [37, 130, 142], [37, 131, 141], [36, 132, 141], [36, 133, 141], [36, 134, 141], [35, 135, 141], [35, 136, 141], [35, 137, 141], [34, 137, 141], [34, 138, 141], [34, 139, 141], [33, 140, 141], [33, 141, 140], [33, 142, 140], [32, 143, 140], [32, 144, 140], [32, 145, 140], [31, 146, 140], [31, 147, 139], [31, 148, 139], [31, 149, 139], [31, 150, 139], [30, 151, 138], [30, 152, 138], [30, 153, 138], [30, 153, 138], [30, 154, 137], [30, 155, 137], [30, 156, 137], [30, 157, 136], [30, 158, 136], [30, 159, 136], [30, 160, 135], [31, 161, 135], [31, 162, 134], [31, 163, 134], [32, 164, 133], [32, 165, 133], [33, 166, 133], [33, 167, 132], [34, 167, 132], [35, 168, 131], [35, 169, 130], [36, 170, 130], [37, 171, 129], [38, 172, 129], [39, 173, 128], [40, 174, 127], [41, 175, 127], [42, 176, 126], [43, 177, 125], [44, 177, 125], [46, 178, 124], [47, 179, 123], [48, 180, 122], [50, 181, 122], [51, 182, 121], [53, 183, 120], [54, 184, 119], [56, 185, 118], [57, 185, 118], [59, 186, 117], [61, 187, 116], [62, 188, 115], [64, 189, 114], [66, 190, 113], [68, 190, 112], [69, 191, 111], [71, 192, 110], [73, 193, 109], [75, 194, 108], [77, 194, 107], [79, 195, 105], [81, 196, 104], [83, 197, 103], [85, 198, 102], [87, 198, 101], [89, 199, 100], [91, 200, 98], [94, 201, 97], [96, 201, 96], [98, 202, 95], [100, 203, 93], [103, 204, 92], [105, 204, 91], [107, 205, 89], [109, 206, 88], [112, 206, 86], [114, 207, 85], [116, 208, 84], [119, 208, 82], [121, 209, 81], [124, 210, 79], [126, 210, 78], [129, 211, 76], [131, 211, 75], [134, 212, 73], [136, 213, 71], [139, 213, 70], [141, 214, 68], [144, 214, 67], [146, 215, 65], [149, 215, 63], [151, 216, 62], [154, 216, 60], [157, 217, 58], [159, 217, 56], [162, 218, 55], [165, 218, 53], [167, 219, 51], [170, 219, 50], [173, 220, 48], [175, 220, 46], [178, 221, 44], [181, 221, 43], [183, 221, 41], [186, 222, 39], [189, 222, 38], [191, 223, 36], [194, 223, 34], [197, 223, 33], [199, 224, 31], [202, 224, 30], [205, 224, 29], [207, 225, 28], [210, 225, 27], [212, 225, 26], [215, 226, 25], [218, 226, 24], [220, 226, 24], [223, 227, 24], [225, 227, 24], [228, 227, 24], [231, 228, 25], [233, 228, 25], [236, 228, 26], [238, 229, 27], [241, 229, 28], [243, 229, 30], [246, 230, 31], [248, 230, 33], [250, 230, 34], [253, 231, 36]]
const brbg = [[84, 48, 5], [86, 49, 5], [88, 50, 5], [90, 51, 5], [92, 53, 5], [94, 54, 5], [97, 55, 6], [99, 57, 6], [101, 58, 6], [103, 59, 6], [105, 60, 6], [108, 62, 7], [110, 63, 7], [112, 64, 7], [114, 66, 7], [116, 67, 7], [119, 68, 8], [121, 69, 8], [123, 71, 8], [125, 72, 8], [127, 73, 8], [130, 75, 9], [132, 76, 9], [134, 77, 9], [136, 79, 9], [138, 80, 9], [141, 81, 10], [143, 83, 12], [145, 85, 13], [147, 87, 14], [149, 89, 16], [151, 91, 17], [153, 93, 18], [155, 95, 20], [157, 97, 21], [159, 98, 23], [161, 100, 24], [163, 102, 25], [165, 104, 27], [167, 106, 28], [169, 108, 29], [171, 110, 31], [173, 112, 32], [175, 113, 34], [177, 115, 35], [179, 117, 36], [181, 119, 38], [183, 121, 39], [185, 123, 40], [187, 125, 42], [189, 127, 43], [191, 129, 45], [192, 131, 48], [193, 134, 51], [194, 136, 54], [196, 139, 57], [197, 141, 60], [198, 144, 63], [199, 146, 66], [201, 149, 70], [202, 151, 73], [203, 154, 76], [204, 157, 79], [206, 159, 82], [207, 162, 85], [208, 164, 88], [209, 167, 92], [211, 169, 95], [212, 172, 98], [213, 174, 101], [214, 177, 104], [216, 179, 107], [217, 182, 110], [218, 185, 114], [219, 187, 117], [221, 190, 120], [222, 192, 123], [223, 194, 126], [224, 196, 129], [225, 197, 131], [226, 199, 134], [227, 200, 137], [227, 202, 140], [228, 203, 142], [229, 205, 145], [230, 206, 148], [231, 208, 151], [232, 209, 153], [233, 211, 156], [234, 212, 159], [235, 214, 162], [236, 215, 164], [236, 217, 167], [237, 218, 170], [238, 220, 173], [239, 221, 175], [240, 223, 178], [241, 224, 181], [242, 226, 184], [243, 227, 186], [244, 229, 189], [245, 230, 192], [246, 232, 195], [245, 232, 196], [245, 233, 198], [245, 233, 200], [245, 234, 202], [245, 234, 204], [245, 235, 206], [245, 235, 208], [245, 236, 210], [245, 236, 212], [245, 237, 214], [245, 237, 216], [245, 238, 218], [245, 238, 220], [245, 239, 222], [245, 239, 224], [245, 240, 226], [245, 240, 228], [245, 241, 230], [245, 241, 232], [245, 242, 234], [245, 242, 236], [245, 243, 238], [245, 243, 240], [245, 244, 242], [245, 244, 244], [244, 244, 244], [242, 244, 244], [240, 243, 243], [238, 243, 242], [236, 243, 242], [235, 242, 241], [233, 242, 240], [231, 241, 240], [229, 241, 239], [227, 240, 239], [226, 240, 238], [224, 240, 237], [222, 239, 237], [220, 239, 236], [218, 238, 235], [217, 238, 235], [215, 237, 234], [213, 237, 234], [211, 237, 233], [209, 236, 232], [208, 236, 232], [206, 235, 231], [204, 235, 230], [202, 234, 230], [200, 234, 229], [199, 234, 229], [196, 232, 227], [193, 231, 226], [190, 230, 224], [187, 229, 223], [185, 228, 221], [182, 227, 220], [179, 226, 219], [176, 224, 217], [173, 223, 216], [171, 222, 214], [168, 221, 213], [165, 220, 212], [162, 219, 210], [160, 218, 209], [157, 216, 207], [154, 215, 206], [151, 214, 205], [148, 213, 203], [146, 212, 202], [143, 211, 200], [140, 210, 199], [137, 208, 197], [134, 207, 196], [132, 206, 195], [129, 205, 193], [126, 203, 192], [123, 201, 190], [120, 199, 188], [117, 197, 186], [114, 195, 184], [111, 193, 182], [108, 191, 180], [105, 189, 178], [103, 187, 176], [100, 184, 174], [97, 182, 172], [94, 180, 170], [91, 178, 168], [88, 176, 166], [85, 174, 164], [82, 172, 162], [79, 170, 160], [76, 167, 158], [73, 165, 156], [70, 163, 154], [67, 161, 152], [64, 159, 150], [61, 157, 148], [58, 155, 146], [55, 153, 144], [53, 151, 143], [50, 149, 141], [48, 147, 139], [46, 145, 137], [44, 143, 135], [42, 141, 133], [40, 139, 131], [38, 137, 129], [36, 135, 127], [34, 133, 125], [32, 131, 123], [30, 129, 121], [28, 127, 119], [26, 126, 118], [24, 124, 116], [22, 122, 114], [20, 120, 112], [18, 118, 110], [16, 116, 108], [14, 114, 106], [12, 112, 104], [10, 110, 102], [8, 108, 100], [6, 106, 98], [4, 104, 96], [2, 102, 94], [0, 101, 93], [0, 99, 91], [0, 97, 89], [0, 96, 87], [0, 94, 85], [0, 92, 84], [0, 91, 82], [0, 89, 80], [0, 88, 78], [0, 86, 76], [0, 84, 75], [0, 83, 73], [0, 81, 71], [0, 79, 69], [0, 78, 67], [0, 76, 66], [0, 74, 64], [0, 73, 62], [0, 71, 60], [0, 69, 58], [0, 68, 57], [0, 66, 55], [0, 64, 53], [0, 63, 51], [0, 61, 49], [0, 60, 48]]
// Define variables for WebGL resources
var gl;
var program;
var positionLocation;
var texcoordLocation;
var positionBuffer;
var texcoordBuffer;
var texture;
var resolutionLocation;
var textureLocation; // Define texture location
function difftime(unix_timestamp){
let client_unix_time = new Date().getTime()/1000.0
var diff = client_unix_time - unix_timestamp
return diff.toFixed(3)
}
// Function to set rectangle geometry in buffer
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]), gl.STATIC_DRAW);
}
// Function to setup WebGL resources
function setupWebGL(canvasId) {
// Get the WebGL context
var canvas = document.getElementById(canvasId);
gl = canvas.getContext("webgl");
if (!gl) {
return false; // WebGL not supported
}
// Setup GLSL program
program = webglUtils.createProgramFromScripts(gl, [
"vertex-shader-2d",
"fragment-shader-2d"
]);
// Lookup attribute and uniform locations
positionLocation = gl.getAttribLocation(program, "a_position");
texcoordLocation = gl.getAttribLocation(program, "a_texCoord");
resolutionLocation = gl.getUniformLocation(program, "u_resolution");
textureLocation = gl.getUniformLocation(program, "u_texture"); // Get texture location
// Create position buffer
positionBuffer = gl.createBuffer();
// Create texcoord buffer
texcoordBuffer = gl.createBuffer();
return true;
}
// Precompute texture data offline
var precomputedTextureData = [];
function typeArray(data, dtype) {
var typedArray = [];
var maxDataValue = 65535;
if (dtype === 'float32') {
typedArray = new Float32Array(data);
} else if (dtype === 'int32') {
typedArray = new Int32Array(data);
} else if (dtype === 'int16') {
typedArray = new Int16Array(data);
maxDataValue = 32767;
} else if (dtype === 'int8' || dtype === 'uint8') {
typedArray = new Uint8Array(data);
maxDataValue = 255;
} else if (dtype === 'uint16') {
typedArray = new Uint16Array(data);
} else {
console.error('Unsupported data type:', dtype);
return;
}
return typedArray
}
function precomputeTextureData(data, width, height, dtype, is_mask=false) {
var typedArray = typeArray(data, dtype);
var maxDataValue = 65535
if (is_mask) {
for (var i = 0; i < typedArray.length; i++) {
var value = typedArray[i];
precomputedTextureData.push(0,255,255, value * 0.8);
}
} else {
for (var i = 0; i < typedArray.length; i++) {
var value = typedArray[i];
var index = Math.round((value / maxDataValue) * (viridis.length - 1));
var rgb = viridis[index];
precomputedTextureData.push(rgb[0], rgb[1], rgb[2], 255);
}
}
}
// Upload precomputed texture data to GPU
function uploadTextureDataToGPU(width, height) {
// Create a texture
texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// Set texture parameters
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
var type = gl.UNSIGNED_BYTE;
var level = 0;
var internalFormat = gl.RGBA;
var border = 0;
var format = gl.RGBA;
var textureData = new Uint8Array(precomputedTextureData);
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border, format, type, textureData);
}
// Function to upload matrix data to texture
function uploadMatrixData(data, width, height, dtype, is_mask) {
precomputedTextureData = [];
precomputeTextureData(data, width, height, dtype, is_mask);
uploadTextureDataToGPU(width, height);
}
// Function to draw matrix with WebGL, scaling each value by a custom factor and starting coordinates
function drawMatrixWithWebGL(data, canvasId, scaleFactor=1, x0=0, y0=0, is_mask=false) {
// Check if WebGL resources need to be setup
if (!gl) {
if (!setupWebGL(canvasId)) {
console.error("WebGL not supported");
return;
}
}
// Clear the canvas
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
// Use the shader program
gl.useProgram(program);
// Setup vertex position buffer with adjusted starting coordinates
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
setRectangle(gl, x0, y0, data.shape[0] * scaleFactor + x0, data.shape[1] * scaleFactor + y0);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Setup texture coordinate buffer with scaled values
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0,
1, 0,
0, 1,
0, 1,
1, 0,
1, 1
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texcoordLocation);
gl.vertexAttribPointer(texcoordLocation, 2, gl.FLOAT, false, 0, 0);
// Set the resolution uniform
gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height);
// Upload matrix data to texture
uploadMatrixData(data.data, data.shape[0], data.shape[1], data.dtype, is_mask);
// Draw the rectangle with scaled dimensions
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
/*
* Copyright 2021 GFXFundamentals.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of GFXFundamentals. nor the names of his
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function(root, factory) { // eslint-disable-line
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], function() {
return factory.call(root);
});
} else {
// Browser globals
root.webglUtils = factory.call(root);
}
}(this, function() {
'use strict';
const topWindow = this;
/** @module webgl-utils */
function isInIFrame(w) {
w = w || topWindow;
return w !== w.top;
}
if (!isInIFrame()) {
console.log("%c%s", 'color:blue;font-weight:bold;', 'for more about webgl-utils.js see:'); // eslint-disable-line
console.log("%c%s", 'color:blue;font-weight:bold;', 'https://webglfundamentals.org/webgl/lessons/webgl-boilerplate.html'); // eslint-disable-line
}
/**
* Wrapped logging function.
* @param {string} msg The message to log.
*/
function error(msg) {
if (topWindow.console) {
if (topWindow.console.error) {
topWindow.console.error(msg);
} else if (topWindow.console.log) {
topWindow.console.log(msg);
}
}
}
/**
* Error Callback
* @callback ErrorCallback
* @param {string} msg error message.
* @memberOf module:webgl-utils
*/
/**
* Loads a shader.
* @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
* @param {string} shaderSource The shader source.
* @param {number} shaderType The type of shader.
* @param {module:webgl-utils.ErrorCallback} opt_errorCallback callback for errors.
* @return {WebGLShader} The created shader.
*/
function loadShader(gl, shaderSource, shaderType, opt_errorCallback) {
const errFn = opt_errorCallback || error;
// Create the shader object
const shader = gl.createShader(shaderType);
// Load the shader source
gl.shaderSource(shader, shaderSource);
// Compile the shader
gl.compileShader(shader);
// Check the compile status
const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
// Something went wrong during compilation; get the error
const lastError = gl.getShaderInfoLog(shader);
errFn('*** Error compiling shader \'' + shader + '\':' + lastError + `\n` + shaderSource.split('\n').map((l,i) => `${i + 1}: ${l}`).join('\n'));
gl.deleteShader(shader);
return null;
}
return shader;
}
/**
* Creates a program, attaches shaders, binds attrib locations, links the
* program and calls useProgram.
* @param {WebGLShader[]} shaders The shaders to attach
* @param {string[]} [opt_attribs] An array of attribs names. Locations will be assigned by index if not passed in
* @param {number[]} [opt_locations] The locations for the. A parallel array to opt_attribs letting you assign locations.
* @param {module:webgl-utils.ErrorCallback} opt_errorCallback callback for errors. By default it just prints an error to the console
* on error. If you want something else pass an callback. It's passed an error message.
* @memberOf module:webgl-utils
*/
function createProgram(
gl, shaders, opt_attribs, opt_locations, opt_errorCallback) {
const errFn = opt_errorCallback || error;
const program = gl.createProgram();
shaders.forEach(function(shader) {
gl.attachShader(program, shader);
});
if (opt_attribs) {
opt_attribs.forEach(function(attrib, ndx) {
gl.bindAttribLocation(
program,
opt_locations ? opt_locations[ndx] : ndx,
attrib);
});
}
gl.linkProgram(program);
// Check the link status
const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
// something went wrong with the link
const lastError = gl.getProgramInfoLog(program);
errFn('Error in program linking:' + lastError);
gl.deleteProgram(program);
return null;
}
return program;
}
/**
* Loads a shader from a script tag.
* @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
* @param {string} scriptId The id of the script tag.
* @param {number} opt_shaderType The type of shader. If not passed in it will
* be derived from the type of the script tag.
* @param {module:webgl-utils.ErrorCallback} opt_errorCallback callback for errors.
* @return {WebGLShader} The created shader.
*/
function createShaderFromScript(
gl, scriptId, opt_shaderType, opt_errorCallback) {
let shaderSource = '';
let shaderType;
const shaderScript = document.getElementById(scriptId);
if (!shaderScript) {
throw ('*** Error: unknown script element' + scriptId);
}
shaderSource = shaderScript.text;
if (!opt_shaderType) {
if (shaderScript.type === 'x-shader/x-vertex') {
shaderType = gl.VERTEX_SHADER;
} else if (shaderScript.type === 'x-shader/x-fragment') {
shaderType = gl.FRAGMENT_SHADER;
} else if (shaderType !== gl.VERTEX_SHADER && shaderType !== gl.FRAGMENT_SHADER) {
throw ('*** Error: unknown shader type');
}
}
return loadShader(
gl, shaderSource, opt_shaderType ? opt_shaderType : shaderType,
opt_errorCallback);
}
const defaultShaderType = [
'VERTEX_SHADER',
'FRAGMENT_SHADER',
];
/**
* Creates a program from 2 script tags.
*
* @param {WebGLRenderingContext} gl The WebGLRenderingContext
* to use.
* @param {string[]} shaderScriptIds Array of ids of the script
* tags for the shaders. The first is assumed to be the
* vertex shader, the second the fragment shader.
* @param {string[]} [opt_attribs] An array of attribs names. Locations will be assigned by index if not passed in
* @param {number[]} [opt_locations] The locations for the. A parallel array to opt_attribs letting you assign locations.
* @param {module:webgl-utils.ErrorCallback} opt_errorCallback callback for errors. By default it just prints an error to the console
* on error. If you want something else pass an callback. It's passed an error message.
* @return {WebGLProgram} The created program.
* @memberOf module:webgl-utils
*/
function createProgramFromScripts(
gl, shaderScriptIds, opt_attribs, opt_locations, opt_errorCallback) {
const shaders = [];
for (let ii = 0; ii < shaderScriptIds.length; ++ii) {
shaders.push(createShaderFromScript(
gl, shaderScriptIds[ii], gl[defaultShaderType[ii]], opt_errorCallback));
}
return createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback);
}
/**
* Creates a program from 2 sources.
*
* @param {WebGLRenderingContext} gl The WebGLRenderingContext
* to use.
* @param {string[]} shaderSourcess Array of sources for the
* shaders. The first is assumed to be the vertex shader,
* the second the fragment shader.
* @param {string[]} [opt_attribs] An array of attribs names. Locations will be assigned by index if not passed in
* @param {number[]} [opt_locations] The locations for the. A parallel array to opt_attribs letting you assign locations.
* @param {module:webgl-utils.ErrorCallback} opt_errorCallback callback for errors. By default it just prints an error to the console
* on error. If you want something else pass an callback. It's passed an error message.
* @return {WebGLProgram} The created program.
* @memberOf module:webgl-utils
*/
function createProgramFromSources(
gl, shaderSources, opt_attribs, opt_locations, opt_errorCallback) {
const shaders = [];
for (let ii = 0; ii < shaderSources.length; ++ii) {
shaders.push(loadShader(
gl, shaderSources[ii], gl[defaultShaderType[ii]], opt_errorCallback));
}
return createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback);
}
/**
* Returns the corresponding bind point for a given sampler type
*/
function getBindPointForSamplerType(gl, type) {
if (type === gl.SAMPLER_2D) return gl.TEXTURE_2D; // eslint-disable-line
if (type === gl.SAMPLER_CUBE) return gl.TEXTURE_CUBE_MAP; // eslint-disable-line
return undefined;
}
/**
* @typedef {Object.<string, function>} Setters
*/
/**
* Creates setter functions for all uniforms of a shader
* program.
*
* @see {@link module:webgl-utils.setUniforms}
*
* @param {WebGLProgram} program the program to create setters for.
* @returns {Object.<string, function>} an object with a setter by name for each uniform
* @memberOf module:webgl-utils
*/
function createUniformSetters(gl, program) {
let textureUnit = 0;
/**
* Creates a setter for a uniform of the given program with it's
* location embedded in the setter.
* @param {WebGLProgram} program
* @param {WebGLUniformInfo} uniformInfo
* @returns {function} the created setter.
*/
function createUniformSetter(program, uniformInfo) {
const location = gl.getUniformLocation(program, uniformInfo.name);
const type = uniformInfo.type;
// Check if this uniform is an array
const isArray = (uniformInfo.size > 1 && uniformInfo.name.substr(-3) === '[0]');
if (type === gl.FLOAT && isArray) {
return function(v) {
gl.uniform1fv(location, v);
};
}
if (type === gl.FLOAT) {
return function(v) {
gl.uniform1f(location, v);
};
}
if (type === gl.FLOAT_VEC2) {
return function(v) {
gl.uniform2fv(location, v);
};
}
if (type === gl.FLOAT_VEC3) {
return function(v) {
gl.uniform3fv(location, v);
};
}
if (type === gl.FLOAT_VEC4) {
return function(v) {
gl.uniform4fv(location, v);
};
}
if (type === gl.INT && isArray) {
return function(v) {
gl.uniform1iv(location, v);
};
}
if (type === gl.INT) {
return function(v) {
gl.uniform1i(location, v);
};
}
if (type === gl.INT_VEC2) {
return function(v) {
gl.uniform2iv(location, v);
};
}
if (type === gl.INT_VEC3) {
return function(v) {
gl.uniform3iv(location, v);
};
}
if (type === gl.INT_VEC4) {
return function(v) {
gl.uniform4iv(location, v);
};
}
if (type === gl.BOOL) {
return function(v) {
gl.uniform1iv(location, v);
};
}
if (type === gl.BOOL_VEC2) {
return function(v) {
gl.uniform2iv(location, v);
};
}
if (type === gl.BOOL_VEC3) {
return function(v) {
gl.uniform3iv(location, v);
};
}
if (type === gl.BOOL_VEC4) {
return function(v) {
gl.uniform4iv(location, v);
};
}
if (type === gl.FLOAT_MAT2) {
return function(v) {
gl.uniformMatrix2fv(location, false, v);
};
}
if (type === gl.FLOAT_MAT3) {
return function(v) {
gl.uniformMatrix3fv(location, false, v);
};
}
if (type === gl.FLOAT_MAT4) {
return function(v) {
gl.uniformMatrix4fv(location, false, v);
};
}
if ((type === gl.SAMPLER_2D || type === gl.SAMPLER_CUBE) && isArray) {
const units = [];
for (let ii = 0; ii < info.size; ++ii) {
units.push(textureUnit++);
}
return function(bindPoint, units) {
return function(textures) {
gl.uniform1iv(location, units);
textures.forEach(function(texture, index) {
gl.activeTexture(gl.TEXTURE0 + units[index]);
gl.bindTexture(bindPoint, texture);
});
};
}(getBindPointForSamplerType(gl, type), units);
}
if (type === gl.SAMPLER_2D || type === gl.SAMPLER_CUBE) {
return function(bindPoint, unit) {
return function(texture) {
gl.uniform1i(location, unit);
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(bindPoint, texture);
};
}(getBindPointForSamplerType(gl, type), textureUnit++);
}
throw ('unknown type: 0x' + type.toString(16)); // we should never get here.
}
const uniformSetters = { };
const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
for (let ii = 0; ii < numUniforms; ++ii) {
const uniformInfo = gl.getActiveUniform(program, ii);
if (!uniformInfo) {
break;
}
let name = uniformInfo.name;
// remove the array suffix.
if (name.substr(-3) === '[0]') {
name = name.substr(0, name.length - 3);
}
const setter = createUniformSetter(program, uniformInfo);
uniformSetters[name] = setter;
}
return uniformSetters;
}
/**
* Set uniforms and binds related textures.
*
* Example:
*
* let programInfo = createProgramInfo(
* gl, ["some-vs", "some-fs"]);
*
* let tex1 = gl.createTexture();
* let tex2 = gl.createTexture();
*
* ... assume we setup the textures with data ...
*
* let uniforms = {
* u_someSampler: tex1,
* u_someOtherSampler: tex2,
* u_someColor: [1,0,0,1],
* u_somePosition: [0,1,1],
* u_someMatrix: [
* 1,0,0,0,
* 0,1,0,0,
* 0,0,1,0,
* 0,0,0,0,
* ],
* };
*
* gl.useProgram(program);
*
* This will automatically bind the textures AND set the
* uniforms.
*
* setUniforms(programInfo.uniformSetters, uniforms);
*
* For the example above it is equivalent to
*
* let texUnit = 0;
* gl.activeTexture(gl.TEXTURE0 + texUnit);
* gl.bindTexture(gl.TEXTURE_2D, tex1);
* gl.uniform1i(u_someSamplerLocation, texUnit++);
* gl.activeTexture(gl.TEXTURE0 + texUnit);
* gl.bindTexture(gl.TEXTURE_2D, tex2);
* gl.uniform1i(u_someSamplerLocation, texUnit++);
* gl.uniform4fv(u_someColorLocation, [1, 0, 0, 1]);
* gl.uniform3fv(u_somePositionLocation, [0, 1, 1]);
* gl.uniformMatrix4fv(u_someMatrix, false, [
* 1,0,0,0,
* 0,1,0,0,
* 0,0,1,0,
* 0,0,0,0,
* ]);
*
* Note it is perfectly reasonable to call `setUniforms` multiple times. For example
*
* let uniforms = {
* u_someSampler: tex1,
* u_someOtherSampler: tex2,
* };
*
* let moreUniforms {
* u_someColor: [1,0,0,1],
* u_somePosition: [0,1,1],
* u_someMatrix: [
* 1,0,0,0,
* 0,1,0,0,
* 0,0,1,0,
* 0,0,0,0,
* ],
* };
*
* setUniforms(programInfo.uniformSetters, uniforms);
* setUniforms(programInfo.uniformSetters, moreUniforms);
*
* @param {Object.<string, function>|module:webgl-utils.ProgramInfo} setters the setters returned from
* `createUniformSetters` or a ProgramInfo from {@link module:webgl-utils.createProgramInfo}.
* @param {Object.<string, value>} an object with values for the
* uniforms.
* @memberOf module:webgl-utils
*/
function setUniforms(setters, ...values) {
setters = setters.uniformSetters || setters;
for (const uniforms of values) {
Object.keys(uniforms).forEach(function(name) {
const setter = setters[name];
if (setter) {
setter(uniforms[name]);
}
});
}
}
/**
* Creates setter functions for all attributes of a shader
* program. You can pass this to {@link module:webgl-utils.setBuffersAndAttributes} to set all your buffers and attributes.
*
* @see {@link module:webgl-utils.setAttributes} for example
* @param {WebGLProgram} program the program to create setters for.
* @return {Object.<string, function>} an object with a setter for each attribute by name.
* @memberOf module:webgl-utils
*/
function createAttributeSetters(gl, program) {
const attribSetters = {
};
function createAttribSetter(index) {
return function(b) {
if (b.value) {
gl.disableVertexAttribArray(index);
switch (b.value.length) {
case 4:
gl.vertexAttrib4fv(index, b.value);
break;
case 3:
gl.vertexAttrib3fv(index, b.value);
break;
case 2:
gl.vertexAttrib2fv(index, b.value);
break;
case 1:
gl.vertexAttrib1fv(index, b.value);
break;
default:
throw new Error('the length of a float constant value must be between 1 and 4!');
}
} else {
gl.bindBuffer(gl.ARRAY_BUFFER, b.buffer);
gl.enableVertexAttribArray(index);
gl.vertexAttribPointer(
index, b.numComponents || b.size, b.type || gl.FLOAT, b.normalize || false, b.stride || 0, b.offset || 0);
}
};
}
const numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
for (let ii = 0; ii < numAttribs; ++ii) {
const attribInfo = gl.getActiveAttrib(program, ii);
if (!attribInfo) {
break;
}
const index = gl.getAttribLocation(program, attribInfo.name);
attribSetters[attribInfo.name] = createAttribSetter(index);
}
return attribSetters;
}
/**
* Sets attributes and binds buffers (deprecated... use {@link module:webgl-utils.setBuffersAndAttributes})
*
* Example:
*
* let program = createProgramFromScripts(
* gl, ["some-vs", "some-fs"]);
*
* let attribSetters = createAttributeSetters(program);
*
* let positionBuffer = gl.createBuffer();
* let texcoordBuffer = gl.createBuffer();
*
* let attribs = {
* a_position: {buffer: positionBuffer, numComponents: 3},
* a_texcoord: {buffer: texcoordBuffer, numComponents: 2},
* };
*
* gl.useProgram(program);
*
* This will automatically bind the buffers AND set the
* attributes.
*
* setAttributes(attribSetters, attribs);
*
* Properties of attribs. For each attrib you can add
* properties:
*
* * type: the type of data in the buffer. Default = gl.FLOAT
* * normalize: whether or not to normalize the data. Default = false
* * stride: the stride. Default = 0
* * offset: offset into the buffer. Default = 0
*
* For example if you had 3 value float positions, 2 value
* float texcoord and 4 value uint8 colors you'd setup your
* attribs like this
*
* let attribs = {
* a_position: {buffer: positionBuffer, numComponents: 3},
* a_texcoord: {buffer: texcoordBuffer, numComponents: 2},
* a_color: {
* buffer: colorBuffer,
* numComponents: 4,
* type: gl.UNSIGNED_BYTE,
* normalize: true,
* },
* };
*
* @param {Object.<string, function>|model:webgl-utils.ProgramInfo} setters Attribute setters as returned from createAttributeSetters or a ProgramInfo as returned {@link module:webgl-utils.createProgramInfo}
* @param {Object.<string, module:webgl-utils.AttribInfo>} attribs AttribInfos mapped by attribute name.
* @memberOf module:webgl-utils
* @deprecated use {@link module:webgl-utils.setBuffersAndAttributes}
*/
function setAttributes(setters, attribs) {
setters = setters.attribSetters || setters;
Object.keys(attribs).forEach(function(name) {
const setter = setters[name];
if (setter) {
setter(attribs[name]);
}
});
}
/**
* Creates a vertex array object and then sets the attributes
* on it
*
* @param {WebGLRenderingContext} gl The WebGLRenderingContext
* to use.
* @param {Object.<string, function>} setters Attribute setters as returned from createAttributeSetters
* @param {Object.<string, module:webgl-utils.AttribInfo>} attribs AttribInfos mapped by attribute name.
* @param {WebGLBuffer} [indices] an optional ELEMENT_ARRAY_BUFFER of indices
*/
function createVAOAndSetAttributes(gl, setters, attribs, indices) {
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
setAttributes(setters, attribs);
if (indices) {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices);
}
// We unbind this because otherwise any change to ELEMENT_ARRAY_BUFFER
// like when creating buffers for other stuff will mess up this VAO's binding
gl.bindVertexArray(null);
return vao;
}
/**
* Creates a vertex array object and then sets the attributes
* on it
*
* @param {WebGLRenderingContext} gl The WebGLRenderingContext
* to use.
* @param {Object.<string, function>| module:webgl-utils.ProgramInfo} programInfo as returned from createProgramInfo or Attribute setters as returned from createAttributeSetters
* @param {module:webgl-utils:BufferInfo} bufferInfo BufferInfo as returned from createBufferInfoFromArrays etc...
* @param {WebGLBuffer} [indices] an optional ELEMENT_ARRAY_BUFFER of indices
*/
function createVAOFromBufferInfo(gl, programInfo, bufferInfo) {
return createVAOAndSetAttributes(gl, programInfo.attribSetters || programInfo, bufferInfo.attribs, bufferInfo.indices);
}
/**
* @typedef {Object} ProgramInfo
* @property {WebGLProgram} program A shader program
* @property {Object<string, function>} uniformSetters: object of setters as returned from createUniformSetters,
* @property {Object<string, function>} attribSetters: object of setters as returned from createAttribSetters,
* @memberOf module:webgl-utils
*/
/**
* Creates a ProgramInfo from 2 sources.
*
* A ProgramInfo contains
*
* programInfo = {
* program: WebGLProgram,
* uniformSetters: object of setters as returned from createUniformSetters,
* attribSetters: object of setters as returned from createAttribSetters,
* }
*
* @param {WebGLRenderingContext} gl The WebGLRenderingContext
* to use.
* @param {string[]} shaderSourcess Array of sources for the
* shaders or ids. The first is assumed to be the vertex shader,
* the second the fragment shader.
* @param {string[]} [opt_attribs] An array of attribs names. Locations will be assigned by index if not passed in
* @param {number[]} [opt_locations] The locations for the. A parallel array to opt_attribs letting you assign locations.
* @param {module:webgl-utils.ErrorCallback} opt_errorCallback callback for errors. By default it just prints an error to the console
* on error. If you want something else pass an callback. It's passed an error message.
* @return {module:webgl-utils.ProgramInfo} The created program.
* @memberOf module:webgl-utils
*/
function createProgramInfo(
gl, shaderSources, opt_attribs, opt_locations, opt_errorCallback) {
shaderSources = shaderSources.map(function(source) {
const script = document.getElementById(source);
return script ? script.text : source;
});
const program = webglUtils.createProgramFromSources(gl, shaderSources, opt_attribs, opt_locations, opt_errorCallback);
if (!program) {
return null;
}
const uniformSetters = createUniformSetters(gl, program);
const attribSetters = createAttributeSetters(gl, program);
return {
program: program,
uniformSetters: uniformSetters,
attribSetters: attribSetters,
};
}
/**
* Sets attributes and buffers including the `ELEMENT_ARRAY_BUFFER` if appropriate
*
* Example:
*
* let programInfo = createProgramInfo(
* gl, ["some-vs", "some-fs"]);
*
* let arrays = {
* position: { numComponents: 3, data: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], },
* texcoord: { numComponents: 2, data: [0, 0, 0, 1, 1, 0, 1, 1], },
* };
*
* let bufferInfo = createBufferInfoFromArrays(gl, arrays);
*
* gl.useProgram(programInfo.program);
*
* This will automatically bind the buffers AND set the
* attributes.
*
* setBuffersAndAttributes(programInfo.attribSetters, bufferInfo);
*
* For the example above it is equivilent to
*
* gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
* gl.enableVertexAttribArray(a_positionLocation);
* gl.vertexAttribPointer(a_positionLocation, 3, gl.FLOAT, false, 0, 0);
* gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
* gl.enableVertexAttribArray(a_texcoordLocation);
* gl.vertexAttribPointer(a_texcoordLocation, 4, gl.FLOAT, false, 0, 0);
*
* @param {WebGLRenderingContext} gl A WebGLRenderingContext.
* @param {Object.<string, function>} setters Attribute setters as returned from `createAttributeSetters`
* @param {module:webgl-utils.BufferInfo} buffers a BufferInfo as returned from `createBufferInfoFromArrays`.
* @memberOf module:webgl-utils
*/
function setBuffersAndAttributes(gl, setters, buffers) {
setAttributes(setters, buffers.attribs);
if (buffers.indices) {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
}
}
// Add your prefix here.
const browserPrefixes = [
'',
'MOZ_',
'OP_',
'WEBKIT_',
];
/**
* Given an extension name like WEBGL_compressed_texture_s3tc
* returns the supported version extension, like
* WEBKIT_WEBGL_compressed_teture_s3tc
* @param {string} name Name of extension to look for
* @return {WebGLExtension} The extension or undefined if not
* found.
* @memberOf module:webgl-utils
*/
function getExtensionWithKnownPrefixes(gl, name) {
for (let ii = 0; ii < browserPrefixes.length; ++ii) {
const prefixedName = browserPrefixes[ii] + name;
const ext = gl.getExtension(prefixedName);
if (ext) {
return ext;
}
}
return undefined;
}
/**
* Resize a canvas to match the size its displayed.
* @param {HTMLCanvasElement} canvas The canvas to resize.
* @param {number} [multiplier] amount to multiply by.
* Pass in window.devicePixelRatio for native pixels.
* @return {boolean} true if the canvas was resized.
* @memberOf module:webgl-utils
*/
function resizeCanvasToDisplaySize(canvas, multiplier) {
multiplier = multiplier || 1;
const width = canvas.clientWidth * multiplier | 0;
const height = canvas.clientHeight * multiplier | 0;
if (canvas.width !== width || canvas.height !== height) {
canvas.width = width;
canvas.height = height;
return true;
}
return false;
}
// Add `push` to a typed array. It just keeps a 'cursor'
// and allows use to `push` values into the array so we
// don't have to manually compute offsets
function augmentTypedArray(typedArray, numComponents) {
let cursor = 0;
typedArray.push = function() {
for (let ii = 0; ii < arguments.length; ++ii) {
const value = arguments[ii];
if (value instanceof Array || (value.buffer && value.buffer instanceof ArrayBuffer)) {
for (let jj = 0; jj < value.length; ++jj) {
typedArray[cursor++] = value[jj];
}
} else {
typedArray[cursor++] = value;
}
}
};
typedArray.reset = function(opt_index) {
cursor = opt_index || 0;
};
typedArray.numComponents = numComponents;
Object.defineProperty(typedArray, 'numElements', {
get: function() {
return this.length / this.numComponents | 0;
},
});
return typedArray;
}
/**
* creates a typed array with a `push` function attached
* so that you can easily *push* values.
*
* `push` can take multiple arguments. If an argument is an array each element
* of the array will be added to the typed array.
*
* Example:
*
* let array = createAugmentedTypedArray(3, 2); // creates a Float32Array with 6 values
* array.push(1, 2, 3);
* array.push([4, 5, 6]);
* // array now contains [1, 2, 3, 4, 5, 6]
*
* Also has `numComponents` and `numElements` properties.
*
* @param {number} numComponents number of components
* @param {number} numElements number of elements. The total size of the array will be `numComponents * numElements`.
* @param {constructor} opt_type A constructor for the type. Default = `Float32Array`.
* @return {ArrayBuffer} A typed array.
* @memberOf module:webgl-utils
*/
function createAugmentedTypedArray(numComponents, numElements, opt_type) {
const Type = opt_type || Float32Array;
return augmentTypedArray(new Type(numComponents * numElements), numComponents);
}
function createBufferFromTypedArray(gl, array, type, drawType) {
type = type || gl.ARRAY_BUFFER;
const buffer = gl.createBuffer();
gl.bindBuffer(type, buffer);
gl.bufferData(type, array, drawType || gl.STATIC_DRAW);
return buffer;
}
function allButIndices(name) {
return name !== 'indices';
}
function createMapping(obj) {
const mapping = {};
Object.keys(obj).filter(allButIndices).forEach(function(key) {
mapping['a_' + key] = key;
});
return mapping;
}
function getGLTypeForTypedArray(gl, typedArray) {
if (typedArray instanceof Int8Array) { return gl.BYTE; } // eslint-disable-line
if (typedArray instanceof Uint8Array) { return gl.UNSIGNED_BYTE; } // eslint-disable-line
if (typedArray instanceof Int16Array) { return gl.SHORT; } // eslint-disable-line
if (typedArray instanceof Uint16Array) { return gl.UNSIGNED_SHORT; } // eslint-disable-line
if (typedArray instanceof Int32Array) { return gl.INT; } // eslint-disable-line
if (typedArray instanceof Uint32Array) { return gl.UNSIGNED_INT; } // eslint-disable-line
if (typedArray instanceof Float32Array) { return gl.FLOAT; } // eslint-disable-line
throw 'unsupported typed array type';
}
// This is really just a guess. Though I can't really imagine using
// anything else? Maybe for some compression?
function getNormalizationForTypedArray(typedArray) {
if (typedArray instanceof Int8Array) { return true; } // eslint-disable-line
if (typedArray instanceof Uint8Array) { return true; } // eslint-disable-line
return false;
}
function isArrayBuffer(a) {
return a.buffer && a.buffer instanceof ArrayBuffer;
}
function guessNumComponentsFromName(name, length) {
let numComponents;
if (name.indexOf('coord') >= 0) {
numComponents = 2;
} else if (name.indexOf('color') >= 0) {
numComponents = 4;
} else {
numComponents = 3; // position, normals, indices ...
}
if (length % numComponents > 0) {
throw 'can not guess numComponents. You should specify it.';
}
return numComponents;
}
function makeTypedArray(array, name) {
if (isArrayBuffer(array)) {
return array;
}
if (array.data && isArrayBuffer(array.data)) {
return array.data;
}
if (Array.isArray(array)) {
array = {
data: array,
};
}
if (!array.numComponents) {
array.numComponents = guessNumComponentsFromName(name, array.length);
}
let type = array.type;
if (!type) {
if (name === 'indices') {
type = Uint16Array;
}
}
const typedArray = createAugmentedTypedArray(array.numComponents, array.data.length / array.numComponents | 0, type);
typedArray.push(array.data);
return typedArray;
}
/**
* @typedef {Object} AttribInfo
* @property {number} [numComponents] the number of components for this attribute.
* @property {number} [size] the number of components for this attribute.
* @property {number} [type] the type of the attribute (eg. `gl.FLOAT`, `gl.UNSIGNED_BYTE`, etc...) Default = `gl.FLOAT`
* @property {boolean} [normalized] whether or not to normalize the data. Default = false
* @property {number} [offset] offset into buffer in bytes. Default = 0
* @property {number} [stride] the stride in bytes per element. Default = 0
* @property {WebGLBuffer} buffer the buffer that contains the data for this attribute
* @memberOf module:webgl-utils
*/
/**
* Creates a set of attribute data and WebGLBuffers from set of arrays
*
* Given
*
* let arrays = {
* position: { numComponents: 3, data: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], },
* texcoord: { numComponents: 2, data: [0, 0, 0, 1, 1, 0, 1, 1], },
* normal: { numComponents: 3, data: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1], },
* color: { numComponents: 4, data: [255, 255, 255, 255, 255, 0, 0, 255, 0, 0, 255, 255], type: Uint8Array, },
* indices: { numComponents: 3, data: [0, 1, 2, 1, 2, 3], },
* };
*
* returns something like
*
* let attribs = {
* a_position: { numComponents: 3, type: gl.FLOAT, normalize: false, buffer: WebGLBuffer, },
* a_texcoord: { numComponents: 2, type: gl.FLOAT, normalize: false, buffer: WebGLBuffer, },
* a_normal: { numComponents: 3, type: gl.FLOAT, normalize: false, buffer: WebGLBuffer, },
* a_color: { numComponents: 4, type: gl.UNSIGNED_BYTE, normalize: true, buffer: WebGLBuffer, },
* };
*
* @param {WebGLRenderingContext} gl The webgl rendering context.
* @param {Object.<string, array|typedarray>} arrays The arrays
* @param {Object.<string, string>} [opt_mapping] mapping from attribute name to array name.
* if not specified defaults to "a_name" -> "name".
* @return {Object.<string, module:webgl-utils.AttribInfo>} the attribs
* @memberOf module:webgl-utils
*/
function createAttribsFromArrays(gl, arrays, opt_mapping) {
const mapping = opt_mapping || createMapping(arrays);
const attribs = {};
Object.keys(mapping).forEach(function(attribName) {
const bufferName = mapping[attribName];
const origArray = arrays[bufferName];
if (origArray.value) {
attribs[attribName] = {
value: origArray.value,
};
} else {
const array = makeTypedArray(origArray, bufferName);
attribs[attribName] = {
buffer: createBufferFromTypedArray(gl, array),
numComponents: origArray.numComponents || array.numComponents || guessNumComponentsFromName(bufferName),
type: getGLTypeForTypedArray(gl, array),
normalize: getNormalizationForTypedArray(array),
};
}
});
return attribs;
}
function getArray(array) {
return array.length ? array : array.data;
}
const texcoordRE = /coord|texture/i;
const colorRE = /color|colour/i;
function guessNumComponentsFromName(name, length) {
let numComponents;
if (texcoordRE.test(name)) {
numComponents = 2;
} else if (colorRE.test(name)) {
numComponents = 4;
} else {
numComponents = 3; // position, normals, indices ...
}
if (length % numComponents > 0) {
throw new Error(`Can not guess numComponents for attribute '${name}'. Tried ${numComponents} but ${length} values is not evenly divisible by ${numComponents}. You should specify it.`);
}
return numComponents;
}
function getNumComponents(array, arrayName) {
return array.numComponents || array.size || guessNumComponentsFromName(arrayName, getArray(array).length);
}
/**
* tries to get the number of elements from a set of arrays.
*/
const positionKeys = ['position', 'positions', 'a_position'];
function getNumElementsFromNonIndexedArrays(arrays) {
let key;
for (const k of positionKeys) {
if (k in arrays) {
key = k;
break;
}
}
key = key || Object.keys(arrays)[0];
const array = arrays[key];
const length = getArray(array).length;
const numComponents = getNumComponents(array, key);
const numElements = length / numComponents;
if (length % numComponents > 0) {
throw new Error(`numComponents ${numComponents} not correct for length ${length}`);
}
return numElements;
}
/**
* @typedef {Object} BufferInfo
* @property {number} numElements The number of elements to pass to `gl.drawArrays` or `gl.drawElements`.
* @property {WebGLBuffer} [indices] The indices `ELEMENT_ARRAY_BUFFER` if any indices exist.
* @property {Object.<string, module:webgl-utils.AttribInfo>} attribs The attribs approriate to call `setAttributes`
* @memberOf module:webgl-utils
*/
/**
* Creates a BufferInfo from an object of arrays.
*
* This can be passed to {@link module:webgl-utils.setBuffersAndAttributes} and to
* {@link module:webgl-utils:drawBufferInfo}.
*
* Given an object like
*
* let arrays = {
* position: { numComponents: 3, data: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], },
* texcoord: { numComponents: 2, data: [0, 0, 0, 1, 1, 0, 1, 1], },
* normal: { numComponents: 3, data: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1], },
* indices: { numComponents: 3, data: [0, 1, 2, 1, 2, 3], },
* };
*
* Creates an BufferInfo like this
*
* bufferInfo = {
* numElements: 4, // or whatever the number of elements is
* indices: WebGLBuffer, // this property will not exist if there are no indices
* attribs: {
* a_position: { buffer: WebGLBuffer, numComponents: 3, },
* a_normal: { buffer: WebGLBuffer, numComponents: 3, },
* a_texcoord: { buffer: WebGLBuffer, numComponents: 2, },
* },
* };
*
* The properties of arrays can be JavaScript arrays in which case the number of components
* will be guessed.
*
* let arrays = {
* position: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0],
* texcoord: [0, 0, 0, 1, 1, 0, 1, 1],
* normal: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1],
* indices: [0, 1, 2, 1, 2, 3],
* };
*
* They can also by TypedArrays
*
* let arrays = {
* position: new Float32Array([0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0]),
* texcoord: new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]),
* normal: new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]),
* indices: new Uint16Array([0, 1, 2, 1, 2, 3]),
* };
*
* Or augmentedTypedArrays
*
* let positions = createAugmentedTypedArray(3, 4);
* let texcoords = createAugmentedTypedArray(2, 4);
* let normals = createAugmentedTypedArray(3, 4);
* let indices = createAugmentedTypedArray(3, 2, Uint16Array);
*
* positions.push([0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0]);
* texcoords.push([0, 0, 0, 1, 1, 0, 1, 1]);
* normals.push([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
* indices.push([0, 1, 2, 1, 2, 3]);
*
* let arrays = {
* position: positions,
* texcoord: texcoords,
* normal: normals,
* indices: indices,
* };
*
* For the last example it is equivalent to
*
* let bufferInfo = {
* attribs: {
* a_position: { numComponents: 3, buffer: gl.createBuffer(), },
* a_texcoods: { numComponents: 2, buffer: gl.createBuffer(), },
* a_normals: { numComponents: 3, buffer: gl.createBuffer(), },
* },
* indices: gl.createBuffer(),
* numElements: 6,
* };
*
* gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.a_position.buffer);
* gl.bufferData(gl.ARRAY_BUFFER, arrays.position, gl.STATIC_DRAW);
* gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.a_texcoord.buffer);
* gl.bufferData(gl.ARRAY_BUFFER, arrays.texcoord, gl.STATIC_DRAW);
* gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.a_normal.buffer);
* gl.bufferData(gl.ARRAY_BUFFER, arrays.normal, gl.STATIC_DRAW);
* gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferInfo.indices);
* gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, arrays.indices, gl.STATIC_DRAW);
*
* @param {WebGLRenderingContext} gl A WebGLRenderingContext
* @param {Object.<string, array|object|typedarray>} arrays Your data
* @param {Object.<string, string>} [opt_mapping] an optional mapping of attribute to array name.
* If not passed in it's assumed the array names will be mapped to an attribute
* of the same name with "a_" prefixed to it. An other words.
*
* let arrays = {
* position: ...,
* texcoord: ...,
* normal: ...,
* indices: ...,
* };
*
* bufferInfo = createBufferInfoFromArrays(gl, arrays);
*
* Is the same as
*
* let arrays = {
* position: ...,
* texcoord: ...,
* normal: ...,
* indices: ...,
* };
*
* let mapping = {
* a_position: "position",
* a_texcoord: "texcoord",
* a_normal: "normal",
* };
*
* bufferInfo = createBufferInfoFromArrays(gl, arrays, mapping);
*
* @return {module:webgl-utils.BufferInfo} A BufferInfo
* @memberOf module:webgl-utils
*/
function createBufferInfoFromArrays(gl, arrays, opt_mapping) {
const bufferInfo = {
attribs: createAttribsFromArrays(gl, arrays, opt_mapping),
};
let indices = arrays.indices;
if (indices) {
indices = makeTypedArray(indices, 'indices');
bufferInfo.indices = createBufferFromTypedArray(gl, indices, gl.ELEMENT_ARRAY_BUFFER);
bufferInfo.numElements = indices.length;
} else {
bufferInfo.numElements = getNumElementsFromNonIndexedArrays(arrays);
}
return bufferInfo;
}
/**
* Creates buffers from typed arrays
*
* Given something like this
*
* let arrays = {
* positions: [1, 2, 3],
* normals: [0, 0, 1],
* }
*
* returns something like
*
* buffers = {
* positions: WebGLBuffer,
* normals: WebGLBuffer,
* }
*
* If the buffer is named 'indices' it will be made an ELEMENT_ARRAY_BUFFER.
*
* @param {WebGLRenderingContext} gl A WebGLRenderingContext.
* @param {Object<string, array|typedarray>} arrays
* @return {Object<string, WebGLBuffer>} returns an object with one WebGLBuffer per array
* @memberOf module:webgl-utils
*/
function createBuffersFromArrays(gl, arrays) {
const buffers = { };
Object.keys(arrays).forEach(function(key) {
const type = key === 'indices' ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
const array = makeTypedArray(arrays[key], name);
buffers[key] = createBufferFromTypedArray(gl, array, type);
});
// hrm
if (arrays.indices) {
buffers.numElements = arrays.indices.length;
} else if (arrays.position) {
buffers.numElements = arrays.position.length / 3;
}
return buffers;
}
/**
* Calls `gl.drawElements` or `gl.drawArrays`, whichever is appropriate
*
* normally you'd call `gl.drawElements` or `gl.drawArrays` yourself
* but calling this means if you switch from indexed data to non-indexed
* data you don't have to remember to update your draw call.
*
* @param {WebGLRenderingContext} gl A WebGLRenderingContext
* @param {module:webgl-utils.BufferInfo} bufferInfo as returned from createBufferInfoFromArrays
* @param {enum} [primitiveType] eg (gl.TRIANGLES, gl.LINES, gl.POINTS, gl.TRIANGLE_STRIP, ...)
* @param {number} [count] An optional count. Defaults to bufferInfo.numElements
* @param {number} [offset] An optional offset. Defaults to 0.
* @memberOf module:webgl-utils
*/
function drawBufferInfo(gl, bufferInfo, primitiveType, count, offset) {
const indices = bufferInfo.indices;
primitiveType = primitiveType === undefined ? gl.TRIANGLES : primitiveType;
const numElements = count === undefined ? bufferInfo.numElements : count;
offset = offset === undefined ? 0 : offset;
if (indices) {
gl.drawElements(primitiveType, numElements, gl.UNSIGNED_SHORT, offset);
} else {
gl.drawArrays(primitiveType, offset, numElements);
}
}
/**
* @typedef {Object} DrawObject
* @property {module:webgl-utils.ProgramInfo} programInfo A ProgramInfo as returned from createProgramInfo
* @property {module:webgl-utils.BufferInfo} bufferInfo A BufferInfo as returned from createBufferInfoFromArrays
* @property {Object<string, ?>} uniforms The values for the uniforms
* @memberOf module:webgl-utils
*/
/**
* Draws a list of objects
* @param {WebGLRenderingContext} gl A WebGLRenderingContext
* @param {DrawObject[]} objectsToDraw an array of objects to draw.
* @memberOf module:webgl-utils
*/
function drawObjectList(gl, objectsToDraw) {
let lastUsedProgramInfo = null;
let lastUsedBufferInfo = null;
objectsToDraw.forEach(function(object) {
const programInfo = object.programInfo;
const bufferInfo = object.bufferInfo;
let bindBuffers = false;
if (programInfo !== lastUsedProgramInfo) {
lastUsedProgramInfo = programInfo;
gl.useProgram(programInfo.program);
bindBuffers = true;
}
// Setup all the needed attributes.
if (bindBuffers || bufferInfo !== lastUsedBufferInfo) {
lastUsedBufferInfo = bufferInfo;
setBuffersAndAttributes(gl, programInfo.attribSetters, bufferInfo);
}
// Set the uniforms.
setUniforms(programInfo.uniformSetters, object.uniforms);
// Draw
drawBufferInfo(gl, bufferInfo);
});
}
function glEnumToString(gl, v) {
const results = [];
for (const key in gl) {
if (gl[key] === v) {
results.push(key);
}
}
return results.length
? results.join(' | ')
: `0x${v.toString(16)}`;
}
const isIE = /*@cc_on!@*/false || !!document.documentMode;
// Edge 20+
const isEdge = !isIE && !!window.StyleMedia;
if (isEdge) {
// Hack for Edge. Edge's WebGL implmentation is crap still and so they
// only respond to "experimental-webgl". I don't want to clutter the
// examples with that so his hack works around it
HTMLCanvasElement.prototype.getContext = function(origFn) {
return function() {
let args = arguments;
const type = args[0];
if (type === 'webgl') {
args = [].slice.call(arguments);
args[0] = 'experimental-webgl';
}
return origFn.apply(this, args);
};
}(HTMLCanvasElement.prototype.getContext);
}
return {
createAugmentedTypedArray: createAugmentedTypedArray,
createAttribsFromArrays: createAttribsFromArrays,
createBuffersFromArrays: createBuffersFromArrays,
createBufferInfoFromArrays: createBufferInfoFromArrays,
createAttributeSetters: createAttributeSetters,
createProgram: createProgram,
createProgramFromScripts: createProgramFromScripts,
createProgramFromSources: createProgramFromSources,
createProgramInfo: createProgramInfo,
createUniformSetters: createUniformSetters,
createVAOAndSetAttributes: createVAOAndSetAttributes,
createVAOFromBufferInfo: createVAOFromBufferInfo,
drawBufferInfo: drawBufferInfo,
drawObjectList: drawObjectList,
glEnumToString: glEnumToString,
getExtensionWithKnownPrefixes: getExtensionWithKnownPrefixes,
resizeCanvasToDisplaySize: resizeCanvasToDisplaySize,
setAttributes: setAttributes,
setBuffersAndAttributes: setBuffersAndAttributes,
setUniforms: setUniforms,
};
}));
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
////////////////// //////////////////
var socket = io.connect({ var socket = io.connect({
// transports: ['websocket'], //transports: ['websocket'],
path: "/web/socket", path: "/web/socket",
}); });
...@@ -56,7 +56,7 @@ socket.on("rtc-status", function(data) { ...@@ -56,7 +56,7 @@ socket.on("rtc-status", function(data) {
$("#image-skp_cmd-dm").text(data.dm.skp_cmd) $("#image-skp_cmd-dm").text(data.dm.skp_cmd)
$("#image-cloud_samples-cloud").text(data.cloud.cloud_samples) $("#image-cloud_samples-cloud").text(data.cloud.cloud_samples)
console.log(data.cred.data[40]) // console.log(data.cred.data[40])
/// In drawings.js /// In drawings.js
draw_image(data.cred, "cred") // cred image draw_image(data.cred, "cred") // cred image
......