armory/Sources/armory/trait/internal/DebugConsole.hx

503 lines
13 KiB
Haxe
Raw Normal View History

2016-07-21 17:45:39 +02:00
package armory.trait.internal;
import iron.math.Math;
2016-07-21 17:45:39 +02:00
import iron.Trait;
2017-11-12 21:56:01 +01:00
#if arm_debug
2016-07-22 23:25:07 +02:00
import kha.Scheduler;
2016-08-25 00:26:01 +02:00
import iron.object.CameraObject;
2016-12-05 01:54:01 +01:00
import iron.object.MeshObject;
2017-02-28 13:48:19 +01:00
import zui.Zui;
import zui.Id;
2016-07-21 17:45:39 +02:00
#end
#if arm_debug
2017-08-23 22:53:39 +02:00
@:access(zui.Zui)
@:access(armory.logicnode.LogicNode)
#end
2017-05-06 00:22:15 +02:00
class DebugConsole extends Trait {
2016-07-21 17:45:39 +02:00
2017-11-12 21:56:01 +01:00
#if (!arm_debug)
2016-10-15 20:19:09 +02:00
public function new() { super(); }
2016-07-21 17:45:39 +02:00
#else
2018-10-11 11:30:39 +02:00
public var visible = true;
2017-02-28 13:48:19 +01:00
var ui:Zui;
2018-08-29 09:59:23 +02:00
var scaleFactor = 1.0;
2016-07-21 17:45:39 +02:00
2016-10-15 20:19:09 +02:00
var lastTime = 0.0;
var frameTime = 0.0;
var totalTime = 0.0;
var frames = 0;
2016-07-22 23:25:07 +02:00
2017-02-28 13:48:19 +01:00
var frameTimeAvg = 0.0;
var frameTimeAvgMin = 0.0;
var frameTimeAvgMax = 0.0;
2017-05-13 10:44:17 +02:00
var renderPathTime = 0.0;
var renderPathTimeAvg = 0.0;
2017-02-28 13:48:19 +01:00
var updateTime = 0.0;
var updateTimeAvg = 0.0;
2017-05-13 10:44:17 +02:00
var animTime = 0.0;
var animTimeAvg = 0.0;
2017-02-28 13:48:19 +01:00
var physTime = 0.0;
var physTimeAvg = 0.0;
2018-06-20 14:57:37 +02:00
var graph:kha.Image = null;
var graphA:kha.Image = null;
var graphB:kha.Image = null;
2018-08-28 13:52:53 +02:00
var benchmark = false;
2018-08-22 12:23:33 +02:00
var benchFrames = 0;
var benchTime = 0.0;
2018-06-20 14:57:37 +02:00
var selectedObject:iron.object.Object;
var selectedType = "";
static var lrow = [1/2, 1/2];
static var row4 = [1/4, 1/4, 1/4, 1/4];
2016-07-22 23:25:07 +02:00
2018-06-14 22:50:11 +02:00
public static var f = 1.0;
public static var watchNodes:Array<armory.logicnode.LogicNode> = [];
2018-06-14 22:50:11 +02:00
2018-08-29 09:59:23 +02:00
public function new(scaleFactor = 1.0) {
2016-10-15 20:19:09 +02:00
super();
2016-07-21 17:45:39 +02:00
2018-08-29 09:59:23 +02:00
this.scaleFactor = scaleFactor;
2018-11-04 11:02:29 +01:00
iron.data.Data.getFont('font_default.ttf', function(font:kha.Font) {
2017-05-12 21:49:42 +02:00
var theme = Reflect.copy(zui.Themes.dark);
theme.WINDOW_BG_COL = 0xee111111;
2018-08-29 09:59:23 +02:00
ui = new Zui({scaleFactor: scaleFactor, font: font, theme: theme});
2016-10-15 20:19:09 +02:00
notifyOnRender2D(render2D);
notifyOnUpdate(update);
2018-06-02 19:00:36 +02:00
if (haxeTrace == null) {
haxeTrace = haxe.Log.trace;
haxe.Log.trace = consoleTrace;
}
2018-02-18 19:28:47 +01:00
// Toggle console
kha.input.Keyboard.get().notify(null, null, function(char: String) {
2018-10-11 11:30:39 +02:00
if (char == "~") visible = !visible;
2018-06-14 22:50:11 +02:00
else if (char == "[") f -= 0.1;
else if (char == "]") f += 0.1;
2018-02-18 19:28:47 +01:00
});
2016-10-15 20:19:09 +02:00
});
}
2016-07-21 17:45:39 +02:00
2018-06-20 14:57:37 +02:00
var debugDrawSet = false;
function selectObject(o:iron.object.Object) {
selectedObject = o;
if (!debugDrawSet) {
debugDrawSet = true;
armory.trait.internal.DebugDraw.notifyOnRender(function(draw:armory.trait.internal.DebugDraw) {
if (selectedObject != null) draw.bounds(selectedObject.transform);
});
}
}
function updateGraph() {
if (graph == null) {
graphA = kha.Image.createRenderTarget(280, 33);
graphB = kha.Image.createRenderTarget(280, 33);
graph = graphA;
}
else graph = graph == graphA ? graphB : graphA;
var graphPrev = graph == graphA ? graphB : graphA;
graph.g2.begin(true, 0x00000000);
graph.g2.color = 0xffffffff;
graph.g2.drawImage(graphPrev, -3, 0);
var avg = Math.round(frameTimeAvg * 1000);
var miss = avg > 16.7 ? (avg - 16.7) / 16.7 : 0.0;
graph.g2.color = kha.Color.fromFloats(miss, 1 - miss, 0, 1.0);
graph.g2.fillRect(280 - 3, 33 - avg, 3, avg);
graph.g2.color = 0xff000000;
graph.g2.fillRect(280 - 3, 33 - 17, 3, 1);
graph.g2.end();
}
2018-06-02 19:00:36 +02:00
static var haxeTrace:Dynamic->haxe.PosInfos->Void = null;
2018-06-20 14:57:37 +02:00
static var lastTraces:Array<String> = [''];
2017-05-06 00:22:15 +02:00
static function consoleTrace(v:Dynamic, ?inf:haxe.PosInfos) {
2018-06-20 14:57:37 +02:00
lastTraces.unshift(Std.string(v));
if (lastTraces.length > 10) lastTraces.pop();
2017-05-06 00:22:15 +02:00
haxeTrace(v, inf);
2018-03-06 22:05:36 +01:00
}
2017-05-06 00:22:15 +02:00
2016-10-15 20:19:09 +02:00
function render2D(g:kha.graphics2.Graphics) {
2018-10-11 11:30:39 +02:00
if (!visible) return;
2017-03-11 01:50:47 +01:00
var hwin = Id.handle();
2018-06-20 14:57:37 +02:00
var htab = Id.handle({position: 0});
2018-08-29 09:59:23 +02:00
var ww = Std.int(280 * scaleFactor);
var wx = iron.App.w() - ww;
2018-08-22 12:23:33 +02:00
var wy = 0;
var wh = iron.App.h();
var bindG = ui.windowDirty(hwin, wx, wy, ww, wh) || hwin.redraws > 0;
if (bindG) g.end();
ui.begin(g);
if (ui.window(hwin, wx, wy, ww, wh, true)) {
2017-08-22 23:34:53 +02:00
if (ui.tab(htab, '')) {}
2018-06-20 14:57:37 +02:00
if (ui.tab(htab, 'Scene')) {
if (ui.panel(Id.handle({selected: true}), "Outliner")) {
ui.indent();
var i = 0;
function drawList(h:zui.Zui.Handle, o:iron.object.Object) {
if (o.name.charAt(0) == '.') return; // Hidden
var b = false;
if (selectedObject == o) {
ui.g.color = 0xff205d9c;
2018-08-29 09:59:23 +02:00
ui.g.fillRect(0, ui._y, ui._windowW, ui.ELEMENT_H());
2018-06-20 14:57:37 +02:00
ui.g.color = 0xffffffff;
}
if (o.children.length > 0) {
2018-06-28 11:34:56 +02:00
ui.row([1/13, 12/13]);
b = ui.panel(h.nest(i, {selected: true}), "", 0, true);
ui.text(o.name);
2018-06-20 14:57:37 +02:00
}
else {
ui._x += 18; // Sign offset
ui.text(o.name);
ui._x -= 18;
}
if (ui.isReleased) {
selectObject(o);
}
i++;
if (b) {
for (c in o.children) {
ui.indent();
drawList(h, c);
ui.unindent();
}
}
2017-08-22 23:34:53 +02:00
}
2018-06-20 14:57:37 +02:00
for (c in iron.Scene.active.root.children) {
drawList(Id.handle(), c);
2017-08-22 23:34:53 +02:00
}
2018-06-20 14:57:37 +02:00
ui.unindent();
}
if (selectedObject == null) selectedType = "";
if (ui.panel(Id.handle({selected: true}), 'Properties $selectedType')) {
ui.indent();
if (selectedObject != null) {
var h = Id.handle();
h.selected = selectedObject.visible;
selectedObject.visible = ui.check(h, "Visible");
var loc = selectedObject.transform.loc;
var scale = selectedObject.transform.scale;
var rot = selectedObject.transform.rot.getEuler();
rot.mult(180 / 3.141592);
var f = 0.0;
ui.row(row4);
ui.text("Location");
h = Id.handle();
h.text = Math.roundfp(loc.x) + "";
f = Std.parseFloat(ui.textInput(h, "X"));
if (ui.changed) loc.x = f;
h = Id.handle();
h.text = Math.roundfp(loc.y) + "";
f = Std.parseFloat(ui.textInput(h, "Y"));
if (ui.changed) loc.y = f;
h = Id.handle();
h.text = Math.roundfp(loc.z) + "";
f = Std.parseFloat(ui.textInput(h, "Z"));
if (ui.changed) loc.z = f;
ui.row(row4);
ui.text("Rotation");
h = Id.handle();
h.text = Math.roundfp(rot.x) + "";
f = Std.parseFloat(ui.textInput(h, "X"));
var changed = false;
if (ui.changed) { changed = true; rot.x = f; }
h = Id.handle();
h.text = Math.roundfp(rot.y) + "";
f = Std.parseFloat(ui.textInput(h, "Y"));
if (ui.changed) { changed = true; rot.y = f; }
h = Id.handle();
h.text = Math.roundfp(rot.z) + "";
f = Std.parseFloat(ui.textInput(h, "Z"));
if (ui.changed) { changed = true; rot.z = f; }
if (changed && selectedObject.name != "Scene") {
rot.mult(3.141592 / 180);
selectedObject.transform.rot.fromEuler(rot.x, rot.y, rot.z);
selectedObject.transform.buildMatrix();
2018-06-20 15:02:01 +02:00
#if arm_physics
2018-06-20 14:57:37 +02:00
var rb = selectedObject.getTrait(armory.trait.physics.RigidBody);
if (rb != null) rb.syncTransform();
2018-06-20 15:02:01 +02:00
#end
2018-06-20 14:57:37 +02:00
}
ui.row(row4);
ui.text("Scale");
h = Id.handle();
h.text = Math.roundfp(scale.x) + "";
f = Std.parseFloat(ui.textInput(h, "X"));
if (ui.changed) scale.x = f;
h = Id.handle();
h.text = Math.roundfp(scale.y) + "";
f = Std.parseFloat(ui.textInput(h, "Y"));
if (ui.changed) scale.y = f;
h = Id.handle();
h.text = Math.roundfp(scale.z) + "";
f = Std.parseFloat(ui.textInput(h, "Z"));
if (ui.changed) scale.z = f;
selectedObject.transform.dirty = true;
2018-06-28 11:34:56 +02:00
if (selectedObject.traits.length > 0) {
ui.text("Traits:");
for (t in selectedObject.traits) {
ui.text(Type.getClassName(Type.getClass(t)));
}
}
2018-06-20 14:57:37 +02:00
if (selectedObject.name == "Scene") {
selectedType = "(Scene)";
2018-10-01 11:45:43 +02:00
var p = iron.Scene.active.world.probe;
2018-06-20 14:57:37 +02:00
p.raw.strength = ui.slider(Id.handle({value: p.raw.strength}), "Env Strength", 0.0, 5.0, true);
}
else if (Std.is(selectedObject, iron.object.LightObject)) {
selectedType = "(Light)";
var light = cast(selectedObject, iron.object.LightObject);
light.data.raw.strength = ui.slider(Id.handle({value: light.data.raw.strength / 10}), "Strength", 0.0, 5.0, true) * 10;
2018-06-20 14:57:37 +02:00
}
else if (Std.is(selectedObject, iron.object.CameraObject)) {
selectedType = "(Camera)";
var scene = iron.Scene.active;
var cam = scene.cameras[0];
var fovHandle = Id.handle({value: Std.int(cam.data.raw.fov * 100) / 100});
cam.data.raw.fov = ui.slider(fovHandle, "FoV", 0.3, 2.0, true);
if (ui.changed) {
cam.buildProjection();
}
}
else {
selectedType = "(Object)";
2017-08-22 23:34:53 +02:00
}
}
2018-06-20 14:57:37 +02:00
ui.unindent();
2017-08-22 23:34:53 +02:00
}
}
2017-05-12 21:49:42 +02:00
var avg = Math.round(frameTimeAvg * 10000) / 10;
var fpsAvg = avg > 0 ? Math.round(1000 / avg) : 0;
2017-08-22 23:34:53 +02:00
if (ui.tab(htab, '$avg ms')) {
2018-06-20 14:57:37 +02:00
if (ui.panel(Id.handle({selected: true}), 'Performance')) {
if (graph != null) ui.image(graph);
ui.indent();
ui.row(lrow);
ui.text('Frame');
ui.text('$avg ms / $fpsAvg fps', Align.Right);
ui.row(lrow);
ui.text('Render-path');
ui.text(Math.round(renderPathTimeAvg * 10000) / 10 + " ms", Align.Right);
ui.row(lrow);
ui.text('Script');
ui.text(Math.round((updateTimeAvg - physTimeAvg - animTimeAvg) * 10000) / 10 + " ms", Align.Right);
ui.row(lrow);
ui.text('Animation');
ui.text(Math.round(animTimeAvg * 10000) / 10 + " ms", Align.Right);
ui.row(lrow);
ui.text('Physics');
ui.text(Math.round(physTimeAvg * 10000) / 10 + " ms", Align.Right);
ui.unindent();
}
if (ui.panel(Id.handle({selected: false}), 'Draw')) {
ui.indent();
ui.row(lrow);
var numMeshes = iron.Scene.active.meshes.length;
ui.text("Meshes");
ui.text(numMeshes + "", Align.Right);
ui.row(lrow);
ui.text('Draw calls');
ui.text(iron.RenderPath.drawCalls + "", Align.Right);
ui.row(lrow);
ui.text('Tris mesh');
ui.text(iron.RenderPath.numTrisMesh + "", Align.Right);
ui.row(lrow);
ui.text('Tris shadow');
ui.text(iron.RenderPath.numTrisShadow + "", Align.Right);
#if arm_batch
ui.row(lrow);
ui.text('Batch calls');
ui.text(iron.RenderPath.batchCalls + "", Align.Right);
ui.row(lrow);
ui.text('Batch buckets');
ui.text(iron.RenderPath.batchBuckets + "", Align.Right);
#end
ui.row(lrow);
ui.text('Culled'); // Assumes shadow context for all meshes
ui.text(iron.RenderPath.culled + ' / ' + numMeshes * 2, Align.Right);
#if arm_stream
ui.row(lrow);
var total = iron.Scene.active.sceneStream.sceneTotal();
ui.text('Streamed');
ui.text('$numMeshes / $total', Align.Right);
#end
ui.unindent();
}
if (ui.panel(Id.handle({selected: false}), 'Render Targets')) {
ui.indent();
ui.imageInvertY = true;
for (rt in iron.RenderPath.active.renderTargets) {
ui.text(rt.raw.name);
if (rt.image != null && !rt.is3D) {
ui.image(rt.image);
}
}
ui.imageInvertY = false;
ui.unindent();
}
if (ui.panel(Id.handle({selected: false}), 'Cached Materials')) {
ui.indent();
for (c in iron.data.Data.cachedMaterials) {
ui.text(c.name);
}
ui.unindent();
}
if (ui.panel(Id.handle({selected: false}), 'Cached Shaders')) {
ui.indent();
for (c in iron.data.Data.cachedShaders) {
ui.text(c.name);
}
ui.unindent();
}
// if (ui.panel(Id.handle({selected: false}), 'Cached Textures')) {
// ui.indent();
// for (c in iron.data.Data.cachedImages) {
// ui.image(c);
// }
// ui.unindent();
// }
}
if (ui.tab(htab, lastTraces[0] == '' ? 'Console' : lastTraces[0].substr(0, 20))) {
#if js
if (ui.panel(Id.handle({selected: false}), 'Script')) {
ui.indent();
var t = ui.textInput(Id.handle());
if (ui.button("Run")) {
2018-06-28 11:34:56 +02:00
try { trace("> " + t); js.Lib.eval(t); }
2018-06-20 14:57:37 +02:00
catch(e:Dynamic) { trace(e); }
}
ui.unindent();
}
2017-05-14 22:23:47 +02:00
#end
2018-06-20 14:57:37 +02:00
if (ui.panel(Id.handle({selected: true}), 'Log')) {
ui.indent();
if (ui.button("Clear")) {
lastTraces[0] = '';
lastTraces.splice(1, lastTraces.length - 1);
}
for (t in lastTraces) ui.text(t);
ui.unindent();
2017-11-22 21:17:36 +01:00
}
2017-02-28 13:48:19 +01:00
}
2018-06-20 14:57:37 +02:00
if (watchNodes.length > 0 && ui.tab(htab, "Watch")) {
for (n in watchNodes) {
2018-06-29 08:40:56 +02:00
ui.text(n.tree.object.name + '.' + n.tree.name + '.' + n.name + ' = ' + n.get(0));
}
}
2018-06-28 11:34:56 +02:00
2017-02-28 13:48:19 +01:00
ui.separator();
}
2018-08-22 12:23:33 +02:00
ui.end(bindG);
if (bindG) g.begin(false);
2017-02-28 13:48:19 +01:00
2016-10-15 20:19:09 +02:00
totalTime += frameTime;
2017-05-13 10:44:17 +02:00
renderPathTime += iron.App.renderPathTime;
2016-10-15 20:19:09 +02:00
frames++;
if (totalTime > 1.0) {
2017-03-11 01:50:47 +01:00
hwin.redraws = 1;
2016-10-15 20:19:09 +02:00
var t = totalTime / frames;
// Second frame
if (frameTimeAvg > 0) {
if (t < frameTimeAvgMin || frameTimeAvgMin == 0) frameTimeAvgMin = t;
if (t > frameTimeAvgMax || frameTimeAvgMax == 0) frameTimeAvgMax = t;
}
2016-08-07 23:12:14 +02:00
2016-10-15 20:19:09 +02:00
frameTimeAvg = t;
2018-08-22 12:23:33 +02:00
if (benchmark) {
benchFrames++;
if (benchFrames > 10) benchTime += t;
if (benchFrames == 20) trace(Std.int((benchTime / 10) * 1000000) / 1000); // ms
}
2017-05-13 10:44:17 +02:00
renderPathTimeAvg = renderPathTime / frames;
2016-10-15 20:19:09 +02:00
updateTimeAvg = updateTime / frames;
2017-05-13 10:44:17 +02:00
animTimeAvg = animTime / frames;
2016-10-15 20:19:09 +02:00
physTimeAvg = physTime / frames;
totalTime = 0;
2017-05-13 10:44:17 +02:00
renderPathTime = 0;
2016-10-15 20:19:09 +02:00
updateTime = 0;
2017-05-13 10:44:17 +02:00
animTime = 0;
2016-10-15 20:19:09 +02:00
physTime = 0;
frames = 0;
2018-06-20 14:57:37 +02:00
if (htab.position == 2) updateGraph(); // Profile tab selected
2016-10-15 20:19:09 +02:00
}
frameTime = Scheduler.realTime() - lastTime;
lastTime = Scheduler.realTime();
}
2016-08-04 22:38:56 +02:00
2016-10-15 20:19:09 +02:00
function update() {
2017-08-23 22:53:39 +02:00
armory.trait.WalkNavigation.enabled = !(ui.isScrolling || (ui.currentWindow != null && ui.currentWindow.dragging));
2016-10-15 20:19:09 +02:00
updateTime += iron.App.updateTime;
2017-09-07 11:44:45 +02:00
animTime += iron.object.Animation.animationTime;
2016-10-15 20:19:09 +02:00
#if arm_physics
2017-09-30 00:32:06 +02:00
physTime += armory.trait.physics.PhysicsWorld.physTime;
2016-10-15 20:19:09 +02:00
#end
}
2016-07-21 17:45:39 +02:00
#end
}