Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 78 additions & 15 deletions h2d/Text.hx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ class Text extends Drawable {
Allow line break.
**/
public var lineBreak(default,set) : Bool = true;
/**
Allow word wrapping.
**/
public var wordWrap(default,set) : Bool = true;
/**
Highlight RGB color. Alpha value is ignored.
**/
public var highlightColor : Int = 0xFFFFFF;
/**
Tag for indicating highlighted text.
**/
public var highlightTag : String = "";

var glyphs : TileGroup;
var needsRebuild : Bool;
Expand Down Expand Up @@ -201,6 +213,13 @@ class Text extends Drawable {
return b;
}

function set_wordWrap(b) {
if( wordWrap == b ) return b;
wordWrap = b;
rebuild();
return b;
}

override function constraintSize(width:Float, height:Float) {
constraintWidth = width;
updateConstraint();
Expand Down Expand Up @@ -329,20 +348,49 @@ class Text extends Drawable {
var lines = [], restPos = 0;
var x = leftMargin;
var wLastSep = 0.;
for( i in 0...text.length ) {
var skipCount = 0;

final nonBreakingSpaceTag = ' ';
final textSize = if( StringTools.contains(text, nonBreakingSpaceTag) ) {
StringTools.replace(text, nonBreakingSpaceTag, ' ').length;
} else {
text.length;
};
for( i in 0...textSize ) {
var cc = StringTools.fastCodeAt(text, i);
var remaining = text.substr(i);

if( skipCount > 0 ) {
skipCount--;
continue;
}

if( highlightTag != null && highlightTag != "" && StringTools.startsWith(remaining, highlightTag) ) {
skipCount = highlightTag.length - 1;
continue;
}

var isNonBreakingSpace = StringTools.startsWith(remaining, nonBreakingSpaceTag);
if( isNonBreakingSpace ) {
var nbspTagSize = nonBreakingSpaceTag.length;
var preceding = text.substr(0, i + nbspTagSize);
var exceedingNbsp = remaining.substr(nbspTagSize);
text = StringTools.replace(preceding, nonBreakingSpaceTag, ' ') + exceedingNbsp;
cc = ' '.code;
}

var e = font.getChar(cc);
var newline = cc == '\n'.code;
var esize = e.width + e.getKerningOffset(prevChar);
var isComplement = (i < text.length - 1 && font.charset.isComplementChar(StringTools.fastCodeAt(text, i + 1)));
if( font.charset.isBreakChar(cc) && !isComplement ) {
var isComplement = (i < textSize - 1 && font.charset.isComplementChar(StringTools.fastCodeAt(text, i + 1)));
if( font.charset.isBreakChar(cc) && !isNonBreakingSpace && !isComplement ) {
if( lines.length == 0 && leftMargin > 0 && x > maxWidth ) {
lines.push("");
if ( sizes != null ) sizes.push(leftMargin);
x -= leftMargin;
}
var size = x + esize + letterSpacing; /* TODO : no letter spacing */
var k = i + 1, max = text.length;
var k = i + 1, max = textSize;
var prevChar = cc;
var breakFound = false;
while( size <= maxWidth && k < max ) {
Expand All @@ -354,8 +402,8 @@ class Text extends Drawable {
var e = font.getChar(cc);
size += e.width + letterSpacing + e.getKerningOffset(prevChar);
prevChar = cc;
if ( font.charset.isBreakChar(cc) ) {
if ( k >= text.length )
if ( font.charset.isBreakChar(cc) && !isNonBreakingSpace ) {
if ( k >= textSize )
break;
var nc = StringTools.fastCodeAt(text, k);
if ( !font.charset.isComplementChar(nc) ) break;
Expand All @@ -373,10 +421,11 @@ class Text extends Drawable {
}
else wLastSep = size;
}
else if( (x + esize + letterSpacing) - wLastSep > maxWidth && lineBreak ) {
else if( wordWrap && (x + esize + letterSpacing) - wLastSep > (maxWidth - esize) ) {
newline = true;
lines.push(text.substr(restPos, i - restPos));
restPos = font.charset.isSpace(cc) ? i + 1 : i;
restPos = i;
x -= esize + letterSpacing;
}
if( e != null && cc != '\n'.code )
x += esize + letterSpacing;
Expand All @@ -388,13 +437,13 @@ class Text extends Drawable {
} else
prevChar = cc;
}
if( restPos < text.length ) {
if( restPos < textSize ) {
if( lines.length == 0 && leftMargin > 0 && x + afterData - letterSpacing > maxWidth ) {
lines.push("");
if ( sizes != null ) sizes.push(leftMargin);
x -= leftMargin;
}
lines.push(text.substr(restPos, text.length - restPos));
lines.push(text.substr(restPos, textSize - restPos));
if ( sizes != null ) sizes.push(x);
}
return lines.join("\n");
Expand Down Expand Up @@ -437,9 +486,26 @@ class Text extends Drawable {
var colors = colorSegments;
var colorsPos = 0;
if( colors != null && colors.length == 0 ) colors = null;
if( rebuild ) glyphs.setDefaultColor(0xFFFFFF);
if( rebuild ) glyphs.setDefaultColor(textColor);
var isHighlight = false;
var skipCount = 0;
for( i in 0...t.length ) {
var cc = StringTools.fastCodeAt(t, i);
var remaining = t.substr(i);

if( skipCount > 0 ) {
skipCount--;
continue;
}

if( highlightTag != null && highlightTag != "" && StringTools.startsWith(remaining, highlightTag) ) {
isHighlight = !isHighlight;
if( rebuild && colors == null )
glyphs.setDefaultColor(isHighlight ? highlightColor : textColor);
skipCount = highlightTag.length - 1;
continue;
}

var e = font.getChar(cc);
var offs = e.getKerningOffset(prevChar);
var esize = e.width + offs;
Expand Down Expand Up @@ -522,16 +588,13 @@ class Text extends Drawable {
function set_textColor(c) {
if( this.textColor == c ) return c;
this.textColor = c;
var a = color.w;
color.setColor(c);
color.w = a;
rebuild();
return c;
}

/**
Set the text color segments. This is an Array containing a pair of (position,color).
Each time the text display will reach the given position, the color will be set.
The segment color is multiplied by the global textColor.
**/
public function setColorSegments( arr ) {
colorSegments = arr;
Expand Down
63 changes: 35 additions & 28 deletions h3d/impl/GlDriver.hx
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ class GlDriver extends Driver {
case GL.RGB10_A2: GL.RGBA;
case GL.RED, GL.R8, GL.R16F, GL.R32F, 0x822A: GL.RED;
case GL.RG, GL.RG8, GL.RG16F, GL.RG32F, 0x822C: GL.RG;
case GL.RGB16F, GL.RGB32F, 0x8054, 0x8E8F, 0x8D64: GL.RGB;
case GL.RGB16F, GL.RGB32F, 0x8054, 0x8E8F, 0x8D64, 0x9274: GL.RGB;
case 0x805B,
0x83F1, // DXT1
0x83F2, // DXT3
Expand All @@ -1050,7 +1050,7 @@ class GlDriver extends Driver {
case R8, RG8, RGB8, R16F, RG16F, RGB16F, R32F, RG32F, RGB32F, RG11B10UF, RGB10A2: #if js glES >= 3 #else true #end;
case S3TC(n): n <= maxCompressedTexturesSupport;
case ASTC(10): #if js textureSupport != null && textureSupport.astc #else true #end;
case ETC(0): #if js textureSupport != null && textureSupport.etc1 #else true #end;
case ETC(0): #if js textureSupport != null && (textureSupport.etc1 || textureSupport.etc2) #else true #end;
case ETC(1), ETC(2): #if js textureSupport != null && textureSupport.etc2 #else true #end;
default: false;
}
Expand Down Expand Up @@ -1142,32 +1142,39 @@ class GlDriver extends Driver {
case RG11B10UF:
tt.internalFmt = GL.R11F_G11F_B10F;
tt.pixelFmt = GL.UNSIGNED_INT_10F_11F_11F_REV;
case S3TC(n) if( n <= maxCompressedTexturesSupport ):
if( t.width&3 != 0 || t.height&3 != 0 )
throw "Compressed texture "+t+" has size "+t.width+"x"+t.height+" - must be a multiple of 4";
switch( n ) {
case 1: tt.internalFmt = 0x83F1; // COMPRESSED_RGBA_S3TC_DXT1_EXT
case 2: tt.internalFmt = 0x83F2; // COMPRESSED_RGBA_S3TC_DXT3_EXT
case 3: tt.internalFmt = 0x83F3; // COMPRESSED_RGBA_S3TC_DXT5_EXT
case 6: tt.internalFmt = 0x8E8F; // COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT
case 7: tt.internalFmt = 0x8E8C; // COMPRESSED_RGBA_BPTC_UNORM
default: throw "Unsupported texture format "+t.format;
}
case ASTC(n):
if( t.width&3 != 0 || t.height&3 != 0 )
throw "Compressed texture "+t+" has size "+t.width+"x"+t.height+" - must be a multiple of 4";
switch( n ) {
case 10: tt.internalFmt = 0x93B0; // COMPRESSED_RGBA_ASTC_4x4_KHR
default: throw "Unsupported texture format "+t.format;
}
case ETC(n):
if( t.width&3 != 0 || t.height&3 != 0 )
throw "Compressed texture "+t+" has size "+t.width+"x"+t.height+" - must be a multiple of 4";
switch( n ) {
case 0: tt.internalFmt = 0x8D64; // ETC1
case 1, 2: tt.internalFmt = 0x9278; // ETC2 RGBA8
default: throw "Unsupported texture format "+t.format;
}
case S3TC(n) if( n <= maxCompressedTexturesSupport ):
if( t.width&3 != 0 || t.height&3 != 0 )
throw "Compressed texture "+t+" has size "+t.width+"x"+t.height+" - must be a multiple of 4";
switch( n ) {
case 1: tt.internalFmt = 0x83F1; // COMPRESSED_RGBA_S3TC_DXT1_EXT
case 2: tt.internalFmt = 0x83F2; // COMPRESSED_RGBA_S3TC_DXT3_EXT
case 3: tt.internalFmt = 0x83F3; // COMPRESSED_RGBA_S3TC_DXT5_EXT
case 6: tt.internalFmt = 0x8E8F; // COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT
case 7: tt.internalFmt = 0x8E8C; // COMPRESSED_RGBA_BPTC_UNORM
default: throw "Unsupported texture format "+t.format;
}
case ASTC(n):
if( t.width&3 != 0 || t.height&3 != 0 )
throw "Compressed texture "+t+" has size "+t.width+"x"+t.height+" - must be a multiple of 4";
switch( n ) {
case 10: tt.internalFmt = 0x93B0; // COMPRESSED_RGBA_ASTC_4x4_KHR
default: throw "Unsupported texture format "+t.format;
}
case ETC(n):
if( t.width&3 != 0 || t.height&3 != 0 )
throw "Compressed texture "+t+" has size "+t.width+"x"+t.height+" - must be a multiple of 4";
switch( n ) {
case 0:
#if js
// WEBGL_compressed_texture_etc1 is not available in WebGL2; use ETC2 RGB8 fallback.
if( textureSupport != null && !textureSupport.etc1 && textureSupport.etc2 )
tt.internalFmt = 0x9274; // ETC2 RGB8
else
#end
tt.internalFmt = 0x8D64; // ETC1
case 1, 2: tt.internalFmt = 0x9278; // ETC2 RGBA8
default: throw "Unsupported texture format "+t.format;
}
default:
throw "Unsupported texture format "+t.format;
}
Expand Down
2 changes: 1 addition & 1 deletion haxelib.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"url": "http://heaps.io",
"license": "BSD",
"description": "The GPU Game Framework",
"version": "2.1.13",
"version": "2.1.14",
"releasenote": "See CHANGELOG.md",
"contributors": [
"ncannasse"
Expand Down
6 changes: 2 additions & 4 deletions hxd/res/Ktx2.hx
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,6 @@ class Ktx2Decoder {
final workerScript = '
let config;
let transcoderPending;
let formatInfo;
let BasisModule;
// Inject the basis transcoder script into the workers context
${_transcoderScript}
Expand All @@ -474,10 +473,9 @@ class Ktx2Decoder {
init(message.transcoderBinary);
break;
case "transcode":
formatInfo = message.formatInfo;
transcoderPending.then(function() {
try {
const { faces, buffers, width, height, hasAlpha, format, type, dfdFlags } = transcode( message.buffer );
const { faces, buffers, width, height, hasAlpha, format, type, dfdFlags } = transcode( message.buffer, message.formatInfo );
self.postMessage( { type: "transcode", id: message.id, data: { faces, width, height, hasAlpha, format, type, dfdFlags } }, buffers );
} catch (error) {
self.postMessage({ type: "error", id: message.id, error: error.message });
Expand Down Expand Up @@ -514,7 +512,7 @@ class Ktx2Decoder {
return result;
}

function transcode(buffer) {
function transcode(buffer, formatInfo) {
let ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer));
function cleanup() {
ktx2File.close();
Expand Down
26 changes: 25 additions & 1 deletion hxsl/Dce.hx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class Dce {
var channelVars : Array<TVar>;
var markAsKeep : Bool;
var checkBranchesFun : TExpr -> Void;
var fragDepthId = Tools.allocVarId();

public function new() {
checkBranchesFun = this.checkBranches; // prevent recreation of instance closure
Expand Down Expand Up @@ -204,6 +205,27 @@ class Dce {
link(v, writeTo);
case TSwiz({ e : TVar(v) }, swiz):
link(v, writeTo, swizBits(swiz));
case TBinop(op, { e : TGlobal(FragDepth) }, e2 ):
var v:TVar = {
id: fragDepthId,
name: "FragDepth",
type: TFloat,
kind: Global,
};
var v = get(v);
switch( op ) {
case OpAssign:
// Last assign will always clear all other dependencies.
v.adeps = [];
v.deps.clear();
case OpAssignOp(_):
default:
return;
}
v.keep = 15;
writeTo.push(v, 15);
check(e2, writeTo, isAffected);
writeTo.pop();
case TBinop(OpAssign | OpAssignOp(_), { e : TVar(v) }, e):
var v = get(v);
writeTo.push(v,15);
Expand Down Expand Up @@ -344,6 +366,8 @@ class Dce {
count++;
}
return { e : TBlock(out), p : e.p, t : e.t };
case TBinop(OpAssign | OpAssignOp(_), { e : TGlobal(FragDepth) }, { e : TVar(v) }) if( get(v).used == 0 ):
return { e : TConst(CNull), t : e.t, p : e.p };
case TVarDecl(v,e2) | TBinop(OpAssign | OpAssignOp(_), { e : (TVar(v) | TSwiz( { e : TVar(v) }, _) | TArray( { e : TVar(v) }, _)) }, e2) if( get(v).used == 0 ):
return (e2 != null && e2.hasSideEffect()) ? mapExpr(e2, false) : { e : TConst(CNull), t : e.t, p : e.p };
case TBinop(OpAssign | OpAssignOp(_), { e : TSwiz( { e : TVar(v) }, swiz) }, e2) if( get(v).used & swizBits(swiz) == 0 ):
Expand Down Expand Up @@ -399,4 +423,4 @@ class Dce {
}
}

}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hacksawstudios/heaps",
"version": "2.1.13",
"version": "2.1.14",
"description": "_High Performance Game Framework_",
"main": "index.js",
"devDependencies": {
Expand Down
Loading