Selaa lähdekoodia

Text 3D in l3d

Tom Spira 5 vuotta sitten
vanhempi
commit
0f6fac14ce
1 muutettua tiedostoa jossa 257 lisäystä ja 0 poistoa
  1. 257 0
      hrt/prefab/l3d/Text3D.hx

+ 257 - 0
hrt/prefab/l3d/Text3D.hx

@@ -0,0 +1,257 @@
+package hrt.prefab.l3d;
+
+import h2d.col.Point;
+
+class Text3DPrimitive extends h2d.TileGroup.TileLayerContent {
+
+	override public function add( x : Float, y : Float, r : Float, g : Float, b : Float, a : Float, t : h2d.Tile ) {
+		@:privateAccess {
+			var sx = x + t.dx;
+			var sy = y + t.dy;
+			tmp.push(sx);
+			tmp.push(sy);
+			tmp.push(1);
+			tmp.push(0);
+			tmp.push(0);
+			tmp.push(1);
+			tmp.push(t.u);
+			tmp.push(t.v);
+			tmp.push(sx + t.width);
+			tmp.push(sy);
+			tmp.push(1);
+			tmp.push(0);
+			tmp.push(0);
+			tmp.push(1);
+			tmp.push(t.u2);
+			tmp.push(t.v);
+			tmp.push(sx);
+			tmp.push(sy + t.height);
+			tmp.push(1);
+			tmp.push(0);
+			tmp.push(0);
+			tmp.push(1);
+			tmp.push(t.u);
+			tmp.push(t.v2);
+			tmp.push(sx + t.width);
+			tmp.push(sy + t.height);
+			tmp.push(1);
+			tmp.push(0);
+			tmp.push(0);
+			tmp.push(1);
+			tmp.push(t.u2);
+			tmp.push(t.v2);
+
+			var x = x + t.dx, y = y + t.dy;
+			if( x < xMin ) xMin = x;
+			if( y < yMin ) yMin = y;
+			x += t.width;
+			y += t.height;
+			if( x > xMax ) xMax = x;
+			if( y > yMax ) yMax = y;
+		}
+	}
+	
+	override public function render( engine : h3d.Engine ) {
+		if( tmp == null || tmp.length == 0) return;
+		super.render(engine);
+	}
+
+	override function getBounds() {
+		return h3d.col.Bounds.fromValues(xMin, yMin, 0, xMax, yMax, 0.1);
+	}
+
+	override public function getCollider() : h3d.col.Collider {
+		return getBounds();
+	}
+
+}
+
+class SignedDistanceField3D extends hxsl.Shader {
+
+	static var SRC = {
+
+		@param var alphaCutoff : Float = 0.5;
+		@param var smoothing : Float = 0.04166666666666666666666666666667; // 1/24
+		var pixelColor : Vec4;
+
+
+		function fragment() {			
+			pixelColor.a = smoothstep(alphaCutoff - smoothing, alphaCutoff + smoothing, pixelColor.a);
+		}
+	}
+
+}
+
+class Text3D extends Object3D {
+
+	var color : Int = 16777215;
+	var size : Int = 12;
+	var cutoff : Float = 0.5;
+	var smoothing : Float = 1 / 32;
+	var letterSpacing : Float = 0;
+	var align : Int = 0;
+	
+	var pathFont : String;
+
+	public var contentText : String = "Empty string";
+
+	public function new( ?parent ) {
+		super(parent);
+		type = "text3d";
+	}
+
+	override function load( obj : Dynamic ) {
+		super.load(obj);
+		this.color = obj.color;
+		this.size = obj.size;
+		this.cutoff = obj.cutoff;
+		this.smoothing = obj.smoothing;
+		this.pathFont = obj.pathFont;
+		this.contentText = obj.contentText;
+		this.align = obj.align;
+	}
+
+	#if editor
+
+	override function save() {
+		var obj : Dynamic = super.save();
+		obj.color = color;
+		obj.size = size;
+		obj.cutoff = cutoff;
+		obj.smoothing = smoothing;
+		obj.pathFont = pathFont;
+		obj.contentText = contentText;
+		obj.align = align;
+		return obj;
+	}
+
+	override function getHideProps() : HideProps {
+		return { icon : "font", name : "Text3D" };
+	}
+
+	override function edit( ctx : EditContext ) {
+		super.edit(ctx);
+		
+		var parameters = new hide.Element('<div class="group" name="Parameters"></div>');
+		
+		var gr = new hide.Element('<dl></dl>').appendTo(parameters);
+
+		new hide.Element('<dt>Font</dt>').appendTo(gr);
+		var element = new hide.Element('<dd></dd>').appendTo(gr);
+		var fileInput = new hide.Element('<input type="text" field="pathFont" style="width:165px" />').appendTo(element);
+
+		var tfile = new hide.comp.FileSelect(["fnt"], null, fileInput);
+		if (this.pathFont != null && this.pathFont.length > 0) tfile.path = this.pathFont;
+		tfile.onChange = function() {
+			this.pathFont = tfile.path;
+			updateInstance(ctx.getContext(this), "pathFont");
+		}
+        new hide.Element('<dt>Align</dt>').appendTo(gr);
+		var element = new hide.Element('<dd></dd>').appendTo(gr);
+		var leftAlign = new hide.Element('<input type="button" style="width: 50px" value="Left" /> ').appendTo(element);
+		var middleAlign = new hide.Element('<input type="button" style="width: 50px" value="Center" /> ').appendTo(element);
+		var rightAlign = new hide.Element('<input type="button" style="width: 50px" value="Right" /> ').appendTo(element);
+		leftAlign.on("click", function(e) {
+			align = 0;
+			leftAlign.attr("disabled", "true");
+			middleAlign.removeAttr("disabled");
+			rightAlign.removeAttr("disabled");
+			updateInstance(ctx.getContext(this), "align");
+		});
+		middleAlign.on("click", function(e) {
+			align = 1;
+			leftAlign.removeAttr("disabled");
+			middleAlign.attr("disabled", "true");
+			rightAlign.removeAttr("disabled");
+			updateInstance(ctx.getContext(this), "align");
+		});
+		rightAlign.on("click", function(e) {
+			align = 2;
+			leftAlign.removeAttr("disabled");
+			middleAlign.removeAttr("disabled");
+			rightAlign.attr("disabled", "true");
+			updateInstance(ctx.getContext(this), "align");
+		});
+
+		new hide.Element('<dt>Color</dt><dd><input type="color" field="color" /></dd>').appendTo(gr);
+		new hide.Element('<dt>Size</dt><dd><input type="range" min="1" max="50" step="1" field="size" /></dd>').appendTo(gr);
+		new hide.Element('<dt>Cutoff</dt><dd><input type="range" min="0" max="1" field="cutoff" /></dd>').appendTo(gr);
+		new hide.Element('<dt>Smoothing</dt><dd><input type="range" min="0" max="1" field="smoothing" /></dd>').appendTo(gr);
+		new hide.Element('<dt>Letter Spacing</dt><dd><input type="range" min="-5" max="5" field="letterSpacing" /></dd>').appendTo(gr);
+		
+		ctx.properties.add(parameters, this, function(pname) {
+			ctx.onChange(this, pname);
+		});
+
+		ctx.properties.add(new hide.Element('<div class="group" name="Responsive">
+			<dl>
+				<dt>Text</dt><dd><input type="text" field="contentText" /></dd>
+			</dl></div>'), this, function(pname) {
+			ctx.onChange(this, pname);
+		});
+	}
+
+	#end
+	
+	override function updateInstance( ctx : Context, ?propName : String) {
+		super.updateInstance(ctx, propName);
+		if (pathFont == null || pathFont.length == 0) {
+			return;
+		}
+		if (contentText == null || contentText.length == 0)
+			return;
+		var mesh : h3d.scene.Mesh = cast ctx.local3d;
+		var font = hxd.res.Loader.currentInstance.load(pathFont).to(hxd.res.BitmapFont);
+		var h2dFont = font.toSdfFont(size, Alpha, cutoff, smoothing);
+		var h2dText = (cast ctx.local2d : h2d.Text);
+		h2dText.font = h2dFont;
+		h2dText.letterSpacing = letterSpacing;
+		h2dText.text = contentText;
+		h2dText.smooth = true;
+        h2dText.textAlign = switch (align) {
+			case 1:
+				Center;
+			case 2:
+				Right;
+			default:
+				Left;
+		}
+		@:privateAccess h2dText.glyphs.content = (cast mesh.primitive : Text3DPrimitive);
+		@:privateAccess {
+			h2dText.initGlyphs(contentText);
+			h2dText.glyphs.setDefaultColor(color, 1);
+			mesh.primitive = h2dText.glyphs.content;
+			mesh.material.texture = h2dFont.tile.getTexture();
+			mesh.material.shadows = false;
+			mesh.material.mainPass.setPassName("overlay");
+			mesh.material.mainPass.depth(false, LessEqual);
+			
+			var shader = mesh.material.mainPass.getShader(SignedDistanceField3D);
+			if (shader != null) {
+				mesh.material.mainPass.removeShader(shader);
+			}
+			shader = new SignedDistanceField3D();
+			shader.alphaCutoff = cutoff;
+			shader.smoothing = smoothing;
+			mesh.material.mainPass.addShader(shader);
+			mesh.material.color = h3d.Vector.fromColor(color);
+			mesh.material.color.w = 1;
+		}
+	}
+
+	override function makeInstance(ctx:Context):Context {
+		ctx = ctx.clone(this);
+		var mesh = new h3d.scene.Mesh(new Text3DPrimitive(), ctx.local3d);
+		mesh.material.blendMode = Alpha;
+		ctx.local3d = mesh;
+		ctx.local3d.name = name;
+		var h2dText = new h2d.Text(hxd.res.DefaultFont.get(), ctx.local2d);
+		@:privateAccess h2dText.glyphs.content = new Text3DPrimitive();
+		ctx.local2d = h2dText;
+		ctx.local2d.name = name;
+		updateInstance(ctx);
+		return ctx;
+	}
+
+	static var _ = Library.register("text3d", Text3D);
+}