using System; using UnityEngine; using UnityEngine.UI; using sam; public class ProductVariableHistorgramFallback : MonoBehaviour { public float heightFraction; ScrollRect scrollRect; RectTransform scrollContent; PointVariableSubsession pvls; Canvas canvas; Material mat; ProductData data; int varIndex; ProductProfile profile; ProductVariable prodvar; float minval; float maxval; Texture2D texture; Texture2D colorTexture; int numSeconds; int numSamples; int texWidth = 64; int texHeight; int panelW; // width of panel in pixels int panelH; // height of panel in pixels int hpw; // half panel width (rounded down) float scrollFraction = 0.0f; // current scroll position (0 to 1) int offsetInseconds = 0; float gridSpacing; void Awake() { pvls = GetComponentInParent(); canvas = GetComponentInParent(); mat = GetComponent().material; scrollRect = GetComponentInParent(); scrollContent = scrollRect.content; scrollRect.onValueChanged.AddListener(OnTimeLineScrolled); } public void OnProductSelected(ProductData pdata) { data = pdata; profile = data.profile; numSeconds = 1 + (int)(data.actualEndTime - data.actualStartTime).TotalSeconds; texHeight = (int)((numSeconds + texWidth - 1) / texWidth) + 2; numSamples = texWidth * texHeight; Debug.Log($"numSeconds: {numSeconds} texHeight: {texHeight} numSamples: {numSamples}"); texture = new Texture2D(texWidth, texHeight, TextureFormat.Alpha8, false); texture.filterMode = FilterMode.Point; texture.wrapMode = TextureWrapMode.Clamp; mat.mainTexture = texture; colorTexture = new Texture2D(texWidth, texHeight, TextureFormat.RGBA32, false); colorTexture.filterMode = FilterMode.Point; colorTexture.wrapMode = TextureWrapMode.Clamp; mat.SetTexture("_ColorTex", colorTexture); } public void OnVariableSelected(int vi) { //Debug.Log($"var-index:{vi} profile:{profile} prodvar:{profile.variables[varIndex]} "); try { varIndex = vi; prodvar = profile.variables[varIndex]; //minval = (float)(prodvar.MinAsDouble() * prodvar.scale); //maxval = (float)(prodvar.MaxAsDouble() * prodvar.scale); minval = (float)prodvar.scaledMinValue; maxval = (float)prodvar.scaledMaxValue; //Debug.Log($"minval: {prodvar.scaledMinValue} maxval:{prodvar.scaledMaxValue} scale:{prodvar.scale} "); if (maxval < minval) { Debug.Log("Swapping min and max values"); float tmp = minval; minval = maxval; maxval = tmp; } float valrange = maxval - minval; //int numFloats = numSamples * 4; //int numSeconds = numSamples - 2; //float[] buf = new float[numFloats]; //for (int i = 0; i < numFloats; i++) // buf[i] = 0.0f; //float[] buf = new float[numSamples]; //for (int i = 0; i < numSamples; i++) // buf[i] = 0.0f; byte[] ibuf = new byte[numSamples]; for (int i = 0; i < numSamples; i++) ibuf[i] = 0; //int numColFloats = numSamples * 4; //float[] colbuf = new float[numColFloats]; Color32[] colbuf = new Color32[numSamples]; for (int i = 0; i < numSamples; i++) colbuf[i] = new Color32(0, 0, 0, 0); foreach (var dp in data.dataPoints) { int s = (int)(dp.time - data.actualStartTime).TotalSeconds; if (s < 0) { Debug.LogWarning($"DataPoint timestamp preceeds file startTime by {-s} seconds (numSamps={numSamples})"); //Debug.Log($"datapoint time: {dp.time} file.startTIme: {data.actualStartTime}"); continue; } else if (s >= numSeconds) { Debug.LogWarning($"DataPoint timestamp is after file endTime by {s - numSeconds + 1} seconds (numSamps={numSamples})"); //Debug.Log($"datapoint time: {dp.time} file.endTIme: {data.actualEndTime}"); continue; } float fv = (dp.variables[varIndex] - minval) / valrange; ushort u16 = (ushort)(fv * ushort.MaxValue); byte msb = (byte)(u16 >> 8); byte lsb = (byte)(u16 & 255); ibuf[s + texWidth] = msb; Color col = pvls.GetDataPointColor(dp); col.a = ((float)lsb) / 255.0f; colbuf[s + texWidth] = col; } gameObject.SetActive(false); //texture.SetPixelData(buf, 0); texture.SetPixelData(ibuf, 0); texture.Apply(); mat.mainTexture = texture; colorTexture.SetPixelData(colbuf, 0); colorTexture.Apply(); mat.SetTexture("_ColorTex", colorTexture); OnScreenSizeChanged(); ComputeGridSpacing(); gameObject.SetActive(true); scrollRect.normalizedPosition = new Vector2(scrollFraction, 0.0f); OnTimeLineScrolled(scrollRect.normalizedPosition); } catch(Exception e) { Debug.Log("ProductVariableHistorgram.OnVariableSelected caught exception: " + e); } } void ComputeGridSpacing() { // select an appropriate value for gridSpacing based on MinVal and MaxVal if (prodvar.gridStep > 0.0f) { gridSpacing = prodvar.gridStep; } else { double valrange = maxval - minval; gridSpacing = (float)Math.Pow(10.0, (int)Math.Floor(Math.Log10(valrange))); } } void RecomputeScrollableSize() { float cs = canvas.transform.localScale.x; float tw = (numSamples + Screen.width) / cs; scrollContent.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, tw); } public void OnScreenSizeChanged() { //RectTransform rt = scrollRect.GetComponent(); //Rect r = RectTransformUtility.PixelAdjustRect(rt, canvas); //Debug.Log($"ScreenWidth={Screen.width} RectWidth={r.width * rt.lossyScale.x}"); panelW = Screen.width; panelH = (int)(((float)Screen.height) * heightFraction); hpw = panelW / 2; RecomputeScrollableSize(); ComputeGridSpacing(); UpdateUniforms(); } public void OnTimeLineScrolled(Vector2 scrollPos) { scrollFraction = scrollPos.x; //int offsetInseconds = (int)(scrollFraction * (numSamples - 4)); offsetInseconds = (int)(scrollFraction * (numSeconds-1)); //Debug.Log($"scrollFraction: {scrollFraction} offsetInseconds:{offsetInseconds}"); DateTime t = data.actualStartTime.AddSeconds(offsetInseconds); pvls.SelectTimeStamp(t); UpdateUniforms(); } void UpdateUniforms() { // histCoordx //float left = ((float)(-hpw + texWidth -1)); //float right = ((float)(numSeconds - 1 - hpw + texWidth)); //float histCoordxMIN = Mathf.LerpUnclamped(left, right, scrollFraction); float histCoordxMIN = offsetInseconds - hpw + texWidth; float histCoordxMAX = histCoordxMIN + (float)panelW; // barCoordx float barcoordxMIN = -hpw; float barcoordxMAX = panelW - hpw; // gridcoordy float unitsPerPixel = ((float)(maxval - minval)) / panelH; int pxSpacing = (int)Math.Round(gridSpacing / unitsPerPixel); mat.SetInt("_gridSpacing", pxSpacing); int gridOffset = (int)((gridSpacing - (minval % gridSpacing)) / unitsPerPixel); float gridcoordyMIN = pxSpacing - gridOffset - 1; while (gridcoordyMIN < 0.0) gridcoordyMIN += pxSpacing; float gridcoordyMAX = gridcoordyMIN + panelH; mat.SetVector("_minCoords", new Vector4(histCoordxMIN, 0.5f, barcoordxMIN, gridcoordyMIN)); mat.SetVector("_maxCoords", new Vector4(histCoordxMAX, 0.5f, barcoordxMAX, gridcoordyMAX)); } }