/* * print - versatile printing routines. $Id: print.js 111 2008-07-18 22:16:23Z nilton $ * * print(x, y, msg, type, alignH, alignV) - print a message * * @param {integer} x Print at X * @param {integer} y Print at Y * @param {string} msg Text to print * @param {string} type String with font effects, Multiple options are posible. Or one summed number. * 1 = 'S'hadow = print.fx.SHADOW (change print.color.shadow if you like) * 2 = 'O'utlined = print.fx.OUTLINED * 4 = 'B'old = print.fx.BOLD * 8 = 'U'nderlined = print.fx.UNDERLINE * 16 = 'I'talic = print.fx.ITALIC * 32 = 'W' Zoom X-axis = print.fx.ZOOMX * 64 = 'H' Zoom Y-axis = print.fx.ZOOMY * 128 = 'R' Rotate = print.fx.ROTATE * 256 = 'X' Skew X = print.fx.SKEWX * 512 = 'Y' Skew Y = print.fx.SKEWY * 1024 = '-' Strikethrough = print.fx.STRIKETHROUGH * 2048 = '=' double Strikethrough = print.fx.DOUBLESTRIKETHROUGH * 4096 = 'N' Nervous text = print.fx.NERVOUS (you can change the value of print.nervous=3 to make it shake harder) * * So Bold+Italic is: "BI", "IB", 20, print.fx.BOLD+print.fx.ITALIC or even "bi" * * @param {integer} alignH Horizontal Justification. -1/'left' (default), '0'/center', 1/'right' * @param {integer} alignV Vertical Justification. -1/'top' (default), 0/'center', 1/'bottom' * Alignment works like this: The (x,y) parameters given are by default at the top and left of the printed font. * To align something at the topright of the screen you set 'right' and 'top' (see examples below) * * the parameters x and y are optional. print() stores its last cursor position in print.pos.x and print.pos.y and uses those if no x and y are given. * It also stores where it started printing in print.X and print.Y, should you need it. * * Other functions: * * print.ln(x, y, msg, type, alignH, alignV) - same as print(x, y, msg+"\n", type, alignH, alignV) * print.addFont(font, fontname) - Add fonts we can then set with print.ml() and print.setFont(); * print.setAngle(radians) - To change the italic skew (default: Math.PI/10) * print.setVSpace(space) - To change the autoprint interline space (default: 2) * print.tint(color) - To change the colormask of the font (default: no colormask) * print.setZoom(zoomfactorX, zoomfactorY) - Zoom factor (you also need to tell print() to print.fx.ZOOMX / 'W' and/or print.fx.ZOOMY / 'H') * print.setVSpace(pixels) - Space between two lines (default: 2) when using "\n" or print.ln() * print.setItalicAngle(angle) - Angle for Italics (default: Math.PI / 10) * print.setAngle(angle) - Angle for rotation. (Dont forget to also set the 'R' effect in your print statement) * print.setSkew(skewXpixels, skewYpixels) - skew the image. * print.ml(x, y, msg, type, alignH, alignV) - similar to print(), but the string is markup language. * The following syntax is supported: *

Paragraph - double linebreak *
Linebreak (similar to \n for print() ) * <#ABCDEF> A font color, in hex. Examples: white = <#FFFFFF>, red = <#FF0000> * <@fontname> Changes font, you must load the font with print.addfont() first. * Headers n=1 to 5. Font effects are defined in the object print.Hfx, for example: print.HFX.TYPE[0] contains the type for

* <^n> superscript n=1 to 9, makes the font move up in steps of quarter of the font height. * <_n> subscript n=1 to 9, makes the font move down in steps of one quarter of the font height. *
  • unnumbered listitem * After this I stopped adding features... * note: align parameters are buggy and not fixable without a complete rewrite. * * Advanced: * print.setup() will create print.surface, a surface you can then re-use. * print.font the current font. * Most of the commands return print, so you can chain like so: print.setAngle(0.4).setVspace(1)(0,0)("This is my text\n.", "R"); * You might also want to look at Neologix's NTML * * examples: * print(0,0, "This is printed on the topleft in bold and italics\n", 'BI'); * print("This line is just below the first one and has a shadow.", 'S'); * print(" This is the continuation of the second line", 'S'); * print(GetScreenWidth()>>1,GetScreenHeight(), "This is plain text centered at the bottom", undefined, 0, 1); * print(GetScreenWidth(), 0, "This is text is right-justified at the top", undefined, 1, -1); * */ function print(x, y, msg, type, alignH, alignV){ // You can skip x and y: if(typeof x == 'string'){ alignV = type; alignH = msg; type = y; msg = x; y = undefined; x = undefined; } // If you want to set the print cursor, use an empty msg string. if (msg == "" || msg === undefined){ print.calcXY(x, y, print.font.getStringWidth(msg), print.font.getHeight(), alignH, alignV); return print; } // Replaced type.match(/S/) by numbers: if(typeof type == 'string'){ var i=type.length; var n=0; while(i--){ n += print.fx[type[i]]; } type = n; } var newline = msg[msg.length-1] == "\n"; if(newline) msg = msg.slice(0,-1); // multiline string... if(msg.match(/\n/)){ print(x,y, ""); var A = msg.split(/\n/); var i; for (i=0;i>1); y += Math.random()*print.nervous - (print.nervous>>1); } // Easy blit, if possible if(type < 16){ print.surface.blit(x,y); return print; } // Calculate the four corners of our image var x1 = x; var y1 = y; var x2 = x + print.W -1; var y2 = y ; var x3 = x2; var y3 = y + print.H -1; var x4 = x; var y4 = y3; if(type & print.fx.ZOOMX){ var factor = print.W*(print.zoomX-1); if(alignH !== undefined){ if(alignH == 1 || alignH == 'right'){ x1 -= factor; x4 -= factor; }else if (alignH == 0 || alignH == 'center'){ x1 -= factor>>1; x2 += factor>>1; x3 += factor>>1; x4 -= factor>>1; } }else{ x2 += factor; x3 += factor; } } if(type & print.fx.ZOOMY){ var factor = print.H*(print.zoomY-1); if(alignV !== undefined){ if(alignV == 1 || alignV == 'bottom'){ y1 -= factor; y2 -= factor; }else if (alignV == 0 || alignV == 'center'){ y1 -= factor>>1; y2 -= factor>>1; y3 += factor>>1; y4 += factor>>1; } }else{ y3 += factor; y4 += factor; } } if(type & print.fx.ITALIC){ print.calcSkew(); x1 += print.skew; x2 += print.skew; } if(type & print.fx.SKEWX){ x1 += print.skewX; x2 += print.skewX; } if(type & print.fx.SKEWY){ y2 += print.skewY; y3 += print.skewY; } if(type & print.fx.ROTATE){ var ox; var oy; if(alignV === undefined || alignV == -1 || alignV == 'top'){ if(alignH === undefined || alignH == -1 || alignH == 'left'){ ox = x1; oy = y1; }else if (alignH == 0 || alignH == 'center'){ ox = (x1+x2)>>1; oy = (y1+y2)>>1; }else{ // if(alignH == 1 || alignH == 'right'){ ox = x2; oy = y2; } }else if (alignV == 0 || alignV == 'center'){ if(alignH === undefined || alignH == -1 || alignH == 'left'){ ox = (x1+x4)>>1; oy = (y1+y4)>>1; }else if (alignH == 0 || alignH == 'center'){ ox = (x1+x2+x3+x4)>>2; oy = (y1+y2+y3+y4)>>2; }else{ // if(alignH == 1 || alignH == 'right'){ ox = (x2+x3)>>1; oy = (y2+y3)>>1; } }else{ // if(alignV == 1 || alignV == 'bottom'){ if(alignH === undefined || alignH == -1 || alignH == 'left'){ ox = x4; oy = y4; }else if (alignH == 0 || alignH == 'center'){ ox = (x4+x3)>>1; oy = (y4+y3)>>1; }else{ // if(alignH == 1 || alignH == 'right'){ ox = x3; oy = y3; } }; // 2D Rotation http://en.wikipedia.org/wiki/Rotation_(mathematics) and ??? // A point can be rotated around the origin <0,0> by running it through the following equations to get the new point : // x' = cos(theta)*x - sin(theta)*y // y' = sin(theta)*x + cos(theta)*y // where theta is the angle by which to rotate the point. // Why doesnt sphere have RotatePointX(origin_x, origin_y, x, y, angle) ? var Ca = Math.cos(print.angle); var Sa = Math.sin(print.angle); x1 = Ca*(x1-ox) - Sa*(y1-oy) + ox; y1 = Sa*(x1-ox) + Ca*(y1-oy) + oy; x2 = Ca*(x2-ox) - Sa*(y2-oy) + ox; y2 = Sa*(x2-ox) + Ca*(y2-oy) + oy; x3 = Ca*(x3-ox) - Sa*(y3-oy) + ox; y3 = Sa*(x3-ox) + Ca*(y3-oy) + oy; x4 = Ca*(x4-ox) - Sa*(y4-oy) + ox; y4 = Sa*(x4-ox) + Ca*(y4-oy) + oy; } // Print to screen print.surface.createImage().transformBlit( x1, y1, x2, y2, x3, y3, x4, y4); return print; } // Print Line. Same as printing the message with an "\n" at the end. print.ln = function(x, y, msg, type, alignH, alignV){ // You can skip x and y: if(typeof x == 'string'){ alignV = type; alignH = msg; type = y; msg = x; y = undefined; x = undefined; } return print(x, y, (msg||"")+"\n", type, alignH, alignV); } print.oldcolor = new Array(); // used in print.ml() print.oldfont = new Array(); // used in print.ml() print.oldsituation = new Array(); // used in print.ml() print.fonts = new Object(); // used in print.ml(), print.addFont() and print.setFont() // Add fonts we can then set with print.ml() and print.setFont(); print.addFont = function(fnt,name){ if(typeof fnt == 'string' && !print.fonts[name||fnt]) print.fonts[name||fnt] = LoadFont(fnt); else print.fonts[name||'_'] = fnt; } // Print Simple Markup Language. Caution: alignments not implemented correctly. print.ml = function(x, y, msg, type, alignH, alignV){ // You can skip x and y: if(typeof x == 'string'){ alignV = type; alignH = msg; type = y; msg = x; y = undefined; x = undefined; } print(x, y, ""); if(msg == "") return; msg = msg.replace("\n", ""); var TYPE = type || 0; var msgArr = msg.split("<"); var reverse = false; if(alignH==1){ msgArr.reverse(); reverse = true; } var tb, tbl, p, fx; for(tb=0, tbl = msgArr.length ; tb/)) ){ fx = msgArr[tb].slice(1,p); if(print.fx[fx]) TYPE ^= print.fx[fx]; else if(fx == 'p') print(x, print.Y, "\n\n"); else if(fx[0] == '#'){ print.color.none = print.oldcolor.pop(); print.font.setColorMask(print.color.none); } else if(fx[0] == '@'){ var colormask = print.font.getColorMask(); print.font = print.oldfont.pop(); print.font.setColorMask(colormask); } else if(fx.match(/h[12345]/)){ print.oldsituation.pop()(); TYPE = print.TYPE; var h = parseInt(fx[1]) -1; if(h<3) print(x, print.Y, "\n\n"); else print(x, print.Y, "\n"); } else if(fx == "^" || fx == "_") print.oldsituation.pop()(); msgArr[tb] = msgArr[tb].slice(p+1); } else if( -1<(p=msgArr[tb].search(/>/)) ){ fx = msgArr[tb].slice(0,p); if(print.fx[fx]) TYPE |= print.fx[fx]; else if(fx == 'p') print(x, print.Y, "\n\n"); else if(fx.match(/^br ?\/?/)) print(x, print.Y, "\n"); else if(fx[0] == '#'){ print.oldcolor.push(print.font.getColorMask()); print.font.setColorMask( CreateColor( parseInt(fx.slice(1,3), 16), parseInt(fx.slice(3,5), 16), parseInt(fx.slice(5,7), 16), fx.length>7 ? parseInt(fx.slice(7,9), 16) : 255 )); print.color.none = print.font.getColorMask(); } else if(fx[0] == '@'){ print.oldfont.push(print.font); print.setFont(fx.slice(1)); } else if (fx.match(/h[12345]/)){ print.oldsituation.push( Function("print.zoomX=" + print.zoomX + ";print.zoomY=" + print.zoomY + ";print.TYPE=" + TYPE)); var h = parseInt(fx[1]) -1; print.zoomX = print.Hfx.zoomX[h]; print.zoomY = print.Hfx.zoomY[h]; TYPE = print.Hfx.TYPE[h]; print(x, print.Y, "\n\n"); } else if (fx.match(/\^[1-9]/)){ print.oldsituation.push( Function("print.pos.y=" + print.pos.y) ); print.pos.y -= parseInt(fx[1]) * (print.font.getHeight()>>2); } else if (fx.match(/\_[1-9]/)){ print.oldsituation.push( Function("print.pos.y=" + print.pos.y) ); print.pos.y += parseInt(fx[1]) * (print.font.getHeight()>>2); } else if (fx == 'li'){ msgArr[tb] = msgArr[tb].replace(">", "> *"); msgArr[tb] += "\n"; } msgArr[tb] = msgArr[tb].slice(p+1); } // At least try fixing alignment a little... if(alignH == 1) print.pos.x = print.X; print(msgArr[tb], TYPE, alignH, alignV); } return print; } // Font effects. MAYBE: OVERSCORE, print.fx = { SHADOW:1, OUTLINED:2, BOLD:4, UNDERLINE:8, ITALIC:16, ZOOMX:32, ZOOMY:64, ROTATE:128, SKEWX:256, SKEWY:512, STRIKETHROUGH:1024, DOUBLESTRIKETHROUGH:2048, NERVOUS:4096, S:1, O:2, B:4, U:8, I:16, W:32, H:64, R:128, X:256, Y:512, '-':1024, '=':2048, N:4096, s:1, o:2, b:4, u:8, i:16, w:32, h:64, r:128, x:256, y:512, n:4096, } // Html h1..h5 effects print.Hfx = { zoomX:[2, 2, 1.5, 1.1, 1], zoomY:[2, 2, 1.5, 1.1, 1], TYPE:[ print.fx.BOLD + print.fx.OUTLINED + print.fx.ZOOMX + print.fx.ZOOMY, print.fx.BOLD + print.fx.ZOOMX + print.fx.ZOOMY, print.fx.BOLD + print.fx.ZOOMX + print.fx.ZOOMY, print.fx.BOLD, print.fx.BOLD ] } // How nervous is the text? print.nervous = 3; // Set the zoom factor print.zoomX = 1; print.zoomY = 1; print.setZoom = function(zoomX, zoomY){ if(zoomX!==undefined) print.zoomX = zoomX; if(zoomY!==undefined) print.zoomY = zoomY; return print; } // Internal function. Define our origin x,y depending on the alignments print.calcXY = function(x, y, W, H , alignH, alignV, newline){ // Define x and y if(x === undefined) x = print.pos.x; if(y === undefined) y = print.pos.y; // Save next x and y if(newline){ print.pos.x = x; print.pos.y = y + H + print.vspace; }else{ print.pos.x = x + (W||0); print.pos.y = y; } // Prepare vertical and horizontal alignment if(alignH !== undefined){ if(alignH == 1 || alignH == 'right') x -= W; else if (alignH == 0 || alignH == 'center') x -= W>>1; } if(alignV !== undefined){ if(alignV == 1 || alignV == 'bottom') y -= H; else if (alignV == 0 || alignV == 'center') y -= H>>1; } print.X = x; print.Y = y; return print; } // Width and Height of our canvas (created in print.setup) print.H = 0; print.W = 0; // Internal function. Create our surface, which we can blit. print.setup = function(msg, type, alignH, alignV){ // If we just calculated this same print statement, use the cached version if(print.previous == type+';'+msg) return; // calculate surface canvas size var cx = print.font.getStringWidth(msg); var cy = print.font.getHeight(); var dx = 0; var dy = 0; if(type & print.fx.OUTLINED){ cx+=2; cy+=2; dx+=2; dy+=2; } if(type & print.fx.SHADOW){ cx+=2; cy+=2; } if(type & print.fx.BOLD){ ++cx; ++dx; } // Create a canvas to print our font to print.createSurface(cx, cy); print.W = cx; print.H = cy; // Underlined if(type & print.fx.UNDERLINE) print.surface.line(dx, cy-1, dx+cx, cy-1, print.color.none); if(type & print.fx.UNDERLINE & print.fx.SHADOW) print.surface.line(dx+1, cy, dx+cx+1, cy, print.color.shadow); // Strikethrough if(type & print.fx.STRIKETHROUGH) print.surface.line(dx, dy+(cy>>1), dx+cx, dy+(cy>>1), print.color.none); if(type & print.fx.DOUBLESTRIKETHROUGH){ print.surface.line(dx, dy+(cy>>1)-1, dx+cx, dy+(cy>>1)-1, print.color.none); print.surface.line(dx, dy+(cy>>1)+1, dx+cx, dy+(cy>>1)+1, print.color.none); } // Shadow if(type & print.fx.SHADOW){ print.font.setColorMask(print.color.shadow); var i = dx+1; do{ print.surface.drawText(print.font, i, dy+1, msg); }while(--i); } dx=0; dy=0; // Outline if(type & print.fx.OUTLINED){ print.font.setColorMask(print.color.outline); var i,j; for(i=0;i<3;++i){ for(j=0;j<3;++j){ print.surface.drawText(print.font, i, j, msg); } } dx=1; dy=1; } // Draw our 'plain' text: print.font.setColorMask(print.color.none); print.surface.drawText(print.font, dx, dy, msg); // Bold if(type & print.fx.BOLD) print.surface.drawText(print.font, dx+1, dy, msg); // Set Cache print.previous = type+';'+msg; return print; } // Remember the cursor position print.pos = { x:0, y:0 } // Colors print.color = { shadow: CreateColor(55,55,55, 155), outline: CreateColor(32,32,32, 200), mark: CreateColor(255,255,0, 255), none: CreateColor(255,255,255, 255), transparent: CreateColor(0,0,0, 0) } // Set your font colormask print.tint = function(color){ print.color.none = color; print.font.setColorMask(color); return print; } // Default font is defined for you print.font = GetSystemFont(); print.fonts['systemfont'] = print.font; // Change your font print.setFont = function(fnt){ if(fnt === undefined) fnt = 'systemfont'; if(typeof fnt == 'string') fnt = print.fonts[fnt] || LoadFont(fnt); print.font = fnt; return print; } // Add fonts we can then set with print.ml() and print.setFont(); print.addFont = function(fnt,name){ if(typeof fnt == 'string' && !print.fonts[name||fnt]) print.fonts[name||fnt] = LoadFont(fnt); else print.fonts[name||'_'] = fnt; } // Space between two lines (in pixels) print.vspace = 2; print.setVSpace = function(vs){ print.vspace = vs; return print; } // Internal function. Creates a canvas where we can print our text and font effects. print.previous= ""; print.surface = undefined; print.createSurface = function(w, h){ return print.surface = CreateSurface(w, h, print.color.transparent); } // Angle for Italics, default: print.italicAngle = Math.PI / 10; print.setItalicAngle = function(italicAngle){ print.italicAngle = italicAngle; return print; } // Internal Function. Skew for Italic angle (depends on font height) print.skew = 0; print.calcSkew = function(italicAngle){ if(italicAngle) print.italicAngle = italicAngle; return print.skew = print.font.getHeight() * Math.tan(print.italicAngle); } // Angle for Rotation, default: print.angle = 0; print.setAngle = function(Angle){ print.angle = Angle; return print; } // Skew pixels print.skewX = 0; print.skewY = 0; print.setSkew = function(skewX, skewY){ if(skewX !== undefined) print.skewX = skewX; if(skewY !== undefined) print.skewY = skewY; return print; }