### Author Topic: Polyvector Question  (Read 2342 times)

#### fuzzy70

• Community Developer
• Prof. Inline
• Posts: 828
• Look left, Look right, LOOK OUT!!
##### Polyvector Question
« on: 2012-Mar-13 »
I have finally got round to playing with the POLYVECTOR command and have a couple of questions. Here is a snippet of my current code
Code: (glbasic) [Select]
`// csz=character size in pixels, pchar=the character to plot, colour[]= array of coloursFOR y=0 TO 24 FOR x=0 TO 39 STARTPOLY 0   POLYVECTOR   (x*csz)*2,       (y*csz)*2,       pchar*csz,      0,   colour[2]   POLYVECTOR   (x*csz)*2,      ((y*csz)+csz)*2,  pchar*csz,      csz, colour[2]   POLYVECTOR  ((x*csz)+csz)*2, ((y*csz)+csz)*2, (pchar*csz)+csz, csz, colour[2]   POLYVECTOR  ((x*csz)+csz)*2,  (y*csz)*2,      (pchar*csz)+csz, 0,   colour[2] ENDPOLY NEXTNEXT`
Imagine a text display of 40x25 chars setup as an array DISPLAY[40][25] (ignoring the fact that the above code will just print the same char at the moment). The characters are stored as an image strip 2048px x 8px & the colours are stored in the colour array as I wanted different coloured text without having to create a bitmap font for each colour. After I got my head around the texture co-ords to find the right char the above code works fine, now for the questions

• Is the above method the best/right way to do it with polyvectors, i.e using polymode 0
• If not would using mode 2 (strip) be a better way of doing it & if so can POLYNEWSTRIP be used in a loop otherwise I would end up with 40 blocks of polyvector code per line
[li]
[/li][/list]

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

#### Slydog

• Prof. Inline
• Posts: 932
• KodeSource
##### Re: Polyvector Question
« Reply #1 on: 2012-Mar-13 »
I use the 'strip' mode using a constant I defined:
Code: (glbasic) [Select]
`CONSTANT POLYMODE_STRIP = 2`
I simplified my POLYVECTOR code by using a common function:
Code: (glbasic) [Select]
`FUNCTION Poly_Draw: xy AS TXyXy, uv AS TXyXy, colour% POLYNEWSTRIP POLYVECTOR xy.x1, xy.y1, uv.x1, uv.y1, colour // TL POLYVECTOR xy.x1, xy.y2, uv.x1, uv.y2, colour // BL POLYVECTOR xy.x2, xy.y1, uv.x2, uv.y1, colour // TR POLYVECTOR xy.x2, xy.y2, uv.x2, uv.y2, colour // BRENDFUNCTION// It uses this TYPE:TYPE TXyXy x1% y1% x2% y2% FUNCTION Set: x1%, y1%, x2%, y2% self.x1 = x1 self.y1 = y1 self.x2 = x2 self.y2 = y2 ENDFUNCTIONENDTYPE`
Then, just start with a "STARTPOLY sprite_id, POLYMODE_STRIP" before calling the 'POLY_DRAW()' function for each polygon sharing this sprite id.

Also, I would start and end a new polygon pair for each letter / character.  That way you can control the letter spacing.  Having one long strip of polyvectors may use less memory / processing, but offers you no spacing options.

I would create my font file in a square multiple of two size file.  Since fonts are twice as high as tall, and by only using the 1st 128 characters, this will give you a square file.  Then indexing each character should be easy by its ASCII value.
The square image is also required / recommended if you are planing to target certain portable devices.

Or better yet, use the font tools and libraries found on this forum for defining where each letter is in the font file, and using these values in your POLYVECTOR routines.
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

#### fuzzy70

• Community Developer
• Prof. Inline
• Posts: 828
• Look left, Look right, LOOK OUT!!
##### Re: Polyvector Question
« Reply #2 on: 2012-Mar-13 »
Thanks Slydog,

Sorry for this question but I must be having a bad day for things "sinking in"  . Using characters as my example, Am I right in assuming you are using the TYPE to store where each char is located in the sprite, or are you using the type to store what polyvectors need to be drawn. Again sorry if it's a dumb question, I think I got out of bed the wrong side today as even simple things are not going to plan

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

#### Slydog

• Prof. Inline
• Posts: 932
• KodeSource
##### Re: Polyvector Question
« Reply #3 on: 2012-Mar-13 »
Actually, I use that TYPE in a lot of places.
But yes, I use it to store each character's x,y location in the sprite file (as long as its width and height in the 2nd x,y pair).
I read this in from a pre-generated text file.  This allows for proportional fonts too, with no 'width' hard coding.

Also, text tends to be static, so when I call my 'print' routine, I calculate each character's location on the screen for that string, and store it into a character / string array, using that TYPE.  This makes each frame's text displaying very simple as everything is pre-calculated.  I only have to update the locations each frame for dynamic strings such as score and time.

This saves me processing time by not figuring each character's position out each frame, especially for more demanding algorithms such as right justify, center, or full justify, plus line wrapping, etc.

My font library is quite complicated for this reason, as I was going for speed, not simplicity.
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

#### fuzzy70

• Community Developer
• Prof. Inline
• Posts: 828
• Look left, Look right, LOOK OUT!!
##### Re: Polyvector Question
« Reply #4 on: 2012-Mar-13 »
Thanks again, that makes perfect sense now

I will have a play around with that later as like I said earlier things are not going good today  . For example, I spent 30mins trying to figure out why on earth my chars had a black background until I noticed that I had forgotten to save them with a blank alpha background

Think I will go & watch a film & come back to this later when hopefully my brain is in gear.

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

#### Slydog

• Prof. Inline
• Posts: 932
• KodeSource
##### Re: Polyvector Question
« Reply #5 on: 2012-Mar-13 »
If you're interested, I use 'Bitmap Font Generator':
http://www.angelcode.com/products/bmfont/

It lets you define a sprite file, plus saves each character's location to a file.
There is a better one on these forums that is similar to the 'DiNGSFont' creator built into GLBasic, but i was already done my routines before that came out.  (I'm not sure if the new one creates a character location text file).

If you're curious about my font library, here it is:
(As is it wont work as it relies on a ton of my other libraries, but it may give you an idea of what needs to be done to create your own library.)
Oh, and it doesn't use my TXyXy, but two types TPoint (just x,y), and TSize (w,h).  I must later calculate a TXyXy variable for using my Poly_Draw() function).

I load the BMFont text file in the TGlyph.New() routine, if you want to see how I parse it out.
Warning, this has been rewritten a few times and code is getting very messy.
Code: (glbasic) [Select]
`CONSTANT FONT_TEXTURE_QTY_X = 16 // How many glyphs horizontally in textureCONSTANT FONT_TEXTURE_QTY_Y = 8 // How many glyphs vertically in textureCONSTANT FONT_TITLE = 0CONSTANT FONT_BODY = 1CONSTANT FONT_MISC = 2CONSTANT FONT_TOTAL = 2GLOBAL FONT_PATH\$ = "Graphics/Fonts/" // Path to 'Fonts' folderGLOBAL _text_offset AS TPointTYPE TGlyphChar xy AS TPoint // x,y position of character in font texture size AS TSize // Size (w,h) of characterENDTYPETYPE TGlyph id% // Font ID (and the sprite that holds this font texture) sprite_size  AS TSize // Width / Height of font texture spacing% height% // General height of a font character chars[] AS TGlyphChar FUNCTION New%: fn\$, height%, spacing%, space_size% //LOCAL fh% // File Handle LOCAL font AS TGlyph // Temporary 'TGlyph' type LOCAL ascii% // Ascii value of current character LOCAL line\$ // Current line data from '.fnt' file LOCAL pos AS TPoint LOCAL size AS TSize LOCAL file AS TFile fn\$ = FONT_PATH\$ + fn\$ //LOG(">Font_New: " + fn\$ + ", id:" + font_id)//clear prev sprite self.id = Sprite_Load(fn\$ + ".png") // Load font texture sprite //LOG("font.id: " + font.id) self.spacing = spacing // Default spacing between characters self.height = height // Default character height Sprite_GetSize(self.id, self.sprite_size) // Get font texture width, height size.w = self.sprite_size.w / FONT_TEXTURE_QTY_X size.h = self.sprite_size.h / FONT_TEXTURE_QTY_Y DIM self.chars[ASC_MAX + 1] // Initialize character array // -------------------------------------------------------------------- // PARSE ".DAT" FILE // -------------------------------------------------------------------- IF NOT file.Open(FILE_MODE_READ, fn\$ + ".dat") // Open font's '.fnt' file LOG(">FON:{TGlyph.New%     } *** Error Opening Glyph File: [" + fn\$ + ".dat" + "] ***") RETURN FALSE // Exit and return 'FALSE' if can't open ENDIF // Read and parse character data from file REPEAT line\$ = file.GetLine\$() IF file.eof THEN BREAK // End of file IF LEN(line\$) <= 0 THEN CONTINUE // Skip blank lines ascii = ASC(MID\$(line\$, 0, 1)) // Ascii value IF (ascii < 0) OR (ascii > ASC_MAX) THEN CONTINUE // Ascii value is out of range, skip to next line self.chars[ascii].xy.x = MID\$(line\$,  2, 3) // [X Position] INC self.chars[ascii].xy.x, MOD(ascii, FONT_TEXTURE_QTY_X) * size.w self.chars[ascii].xy.y = MID\$(line\$,  6, 3) // [Y Position] INC self.chars[ascii].xy.y, INTEGER(ascii / FONT_TEXTURE_QTY_X) * size.h self.chars[ascii].size.w = MID\$(line\$,  10, 3) // [Width] self.chars[ascii].size.h = MID\$(line\$,  14, 3) // [Height] UNTIL file.eof file.Close() self.chars[32].xy.x = 0 self.chars[32].size.w = space_size //Debug_Font(font) RETURN TRUE // Font added successfully ENDFUNCTIONENDTYPEGLOBAL _glyphs[] AS TGlyph // FONT_TITLETYPE TTextStyle font_id% justify% = JUSTIFY_CENTER spacing% // Padding between each character margin AS TXyXy colour AS TPolyColour FUNCTION Copyasd%: style AS TTextStyle self.font_id = style.font_id self.spacing = style.spacing self.justify = style.justify self.margin.Set(style.margin.x1, style.margin.x2, style.margin.y1, style.margin.y2) self.colour.Set(style.colour.TL, style.colour.TR, style.colour.BL, style.colour.BR) ENDFUNCTION FUNCTION SetMargin%: left%, top%, right%, bottom% self.margin.Set(left, top, right, bottom) ENDFUNCTION FUNCTION SetColour%: rgb_tl%, rgb_tr%=-1, rgb_bl%=-1, rgb_br%=-1 self.colour.Set(rgb_tl, rgb_tr, rgb_bl, rgb_br) ENDFUNCTION FUNCTION Clear%: self.font_id = BLANK self.margin.Set(BLANK, BLANK, BLANK, BLANK) self.justify = JUSTIFY_CENTER self.spacing = 0 self.colour.Clear() ENDFUNCTIONENDTYPETYPE TTextLine ascii%[] xy AS TPointENDTYPETYPE TText enabled% string\$ style AS TTextStyle lines[] AS TTextLine pos AS TXyWh justify% FUNCTION New%: string\$, style AS TTextStyle, pos AS TXyWh, colour AS TPolyColour, justify%=BLANK, spacing%=BLANK self.enabled = TRUE self.string\$ = string\$ self.pos.Set(pos.x, pos.y, pos.w, pos.h) self.style = style IF colour.TL <> BLANK THEN self.style.colour = colour // Override default style IF justify <> BLANK THEN self.style.justify = justify // Override default style IF spacing <> BLANK THEN self.style.spacing = spacing // Override default style self.AsciiSet(string\$) ENDFUNCTION FUNCTION Clear%: self.enabled = FALSE self.string\$ = "" self.style.Clear() DIM self.lines[0] ENDFUNCTION FUNCTION Update: enabled%, string_new\$, colour_new AS TPolyColour, x_new%=BLANK, y_new%=BLANK self.enabled = enabled // Update 'ENABLED' IF string_new\$ <> "" THEN self.AsciiSet(string_new\$) // New 'STRING'? IF (x_new <> BLANK) THEN self.pos.x = x_new // New 'X POS'? IF (y_new <> BLANK) THEN self.pos.y = y_new // New 'Y POS'? IF (colour_new.TL <> BLANK) THEN self.style.colour = colour_new // New 'COLOUR'? ENDFUNCTION FUNCTION Draw: colour AS TPolyColour LOCAL fx% LOCAL lx%, ax% LOCAL y_pos% LOCAL cursor AS TPoints LOCAL uv AS TPoints cursor.xy1.Set(self.pos.x, 0) // Start drawing from this x,y point IF (colour=BLANK_POLY_COLOUR) THEN colour = self.style.colour // Step thru each line in text message FOR lx = 0 TO BOUNDS(self.lines[], 0) - 1 cursor.xy1.x = self.pos.x + self.lines[lx].xy.x + _text_offset.x y_pos = self.pos.y + self.lines[lx].xy.y + _text_offset.y // Step thru each ascii character in the current line FOR ax = 0 TO BOUNDS(self.lines[lx].ascii[], 0) - 1 LOCAL cx% cx = self.lines[lx].ascii[ax] cursor.xy1.y = y_pos cursor.xy2.y = cursor.xy1.y + _glyphs[self.style.font_id].chars[cx].size.h cursor.xy2.x = cursor.xy1.x + _glyphs[self.style.font_id].chars[cx].size.w uv.xy1 = _glyphs[self.style.font_id].chars[cx].xy uv.xy2 = uv.xy1 INC uv.xy2.x, _glyphs[self.style.font_id].chars[cx].size.w INC uv.xy2.y, _glyphs[self.style.font_id].chars[cx].size.h Poly_Draw_Gradient(cursor, uv, colour) INC cursor.xy1.x, _glyphs[self.style.font_id].chars[cx].size.w + self.style.spacing NEXT NEXT ENDFUNCTION // Fill 'ascii[]' array from 'string\$' FUNCTION AsciiSet: string\$ LOCAL sx%, ax%, bx% LOCAL ascii% LOCAL ascii_word% LOCAL line AS TTextLine LOCAL word_width% = 0 LOCAL line_width% = 0 LOCAL b_newline% = TRUE LOCAL y_pos% DIM self.lines[0] y_pos = self.style.margin.y1 FOR sx = 0 TO LEN(string\$) // Add current line to list? IF b_newline = TRUE IF line_width > 0 DEC line_width, self.style.spacing ENDIF SELECT self.style.justify CASE JUSTIFY_LEFT line.xy.x = self.style.margin.x1 CASE JUSTIFY_CENTER IF self.pos.w > 0 line.xy.x = (self.pos.w - line_width) / 2 ELSE line.xy.x = -(line_width / 2) ENDIF CASE JUSTIFY_RIGHT IF self.pos.w > 0 line.xy.x = self.pos.w - line_width - self.style.margin.x2 ELSE line.xy.x = -line_width ENDIF ENDSELECT line.xy.y = y_pos IF line_width > 0 DIMPUSH self.lines[], line INC y_pos, _glyphs[self.style.font_id].height ENDIF IF sx = LEN(string\$) THEN BREAK DIM line.ascii[0] ax = 0 line_width = 0 b_newline = FALSE ENDIF ascii% = ASC(MID\$(string\$, sx, 1)) ascii = self.AsciiValidate(ascii, self.style.font_id) // Validate ASCII value // New Line Ascii? IF ascii = ASC_NEWLINE b_newline = TRUE CONTINUE ENDIF REDIM line.ascii[ax+1] IF (self.pos.w > 0) AND (ascii = 32) // Calculate width of next 'word' word_width = 0 FOR bx = sx + 1 TO LEN(string\$) - 1 ascii_word = ASC(MID\$(string\$, bx, 1)) ascii_word = self.AsciiValidate(ascii_word, self.style.font_id) // Validate ASCII value IF ascii_word <> 32 INC word_width, _glyphs[self.style.font_id].chars[ascii_word].size.w // Only add text spacing if NOT last character IF bx < LEN(string\$) - 1 THEN INC word_width, self.style.spacing ENDIF IF (ascii_word = 32) OR (ascii_word = ASC_NEWLINE) THEN BREAK // End of word? NEXT // Is the next word too wide? IF (line_width + word_width) > self.pos.w - self.style.margin.x2 - self.style.margin.x1 b_newline = TRUE CONTINUE ENDIF ENDIF line.ascii[ax] = ascii INC ax INC line_width, _glyphs[self.style.font_id].chars[ascii].size.w + self.style.spacing // If last character, finish off last line IF sx = LEN(string\$) - 1 THEN b_newline = TRUE NEXT ENDFUNCTION FUNCTION AsciiValidate%: ascii%, font_id% IF font_id >= FONT_TOTAL THEN RETURN ALIAS font AS _glyphs[font_id] IF (ascii >= ASC_A) AND (ascii <= ASC_Z) AND (font.chars[ascii].size.w <= 0) THEN INC ascii, (ASC_a - ASC_A) // If a CAPTIAL letter, and no ascii defined for that, use a SMALL CASE version IF (ascii >= ASC_a) AND (ascii <= ASC_z) AND (font.chars[ascii].size.w <= 0) THEN DEC ascii, (ASC_a - ASC_A) // If a SMALL letter, and no ascii defined for that, use a CAPITIAL version IF font.chars[ascii].size.w <= 0 THEN ascii = 32 // Ascii not defined in font?  -> Default to 'space' IF ascii > ASC_MAX THEN ascii = 32 // Aascii value out of range?  -> Default to 'space' RETURN ascii ENDFUNCTIONENDTYPEGLOBAL _font_active%FUNCTION Font_Load%: font_ix%, fn\$, height%, spacing%, space_size% IF font_ix >= FONT_TOTAL THEN RETURN _glyphs[font_ix].New(fn\$, height, spacing, space_size)ENDFUNCTIONFUNCTION Font_PrintStart%: font_ix% _font_active = font_ix% ALPHAMODE -1.0 STARTPOLY _glyphs[font_ix].id, POLYMODE_STRIPENDFUNCTIONFUNCTION Font_PrintEnd%: _font_active = BLANKENDFUNCTIONFUNCTION Font_TextOffset: offset AS TPoint _text_offset = offsetENDFUNCTIONFUNCTION Font_Initialize: DIM _glyphs[FONT_TOTAL]ENDFUNCTION`
 Nope!  I use a weird type called TPoints that is just two TPoint variables: (along with a different Draw_Poly to handle gradients.  Boy do I have to tidy up my code and remove some TYPEs and make more consistent!)
Code: (glbasic) [Select]
`TYPE TPoint x% y% FUNCTION Set%: x%, y% self.x = x self.y = y ENDFUNCTION FUNCTION Clear%: self.x = 0 self.y = 0 ENDFUNCTION FUNCTION Add%: xy1 AS TPoint, xy2 AS TPoint self.x = xy1.x + xy2.x self.y = xy1.y + xy2.x ENDFUNCTION FUNCTION Dump\$: width%=3 //LOCAL rv\$ RETURN "[" + FormatInt\$(self.x, width) + "," + FormatInt\$(self.y, width) + "]" //RETURN rv\$ ENDFUNCTIONENDTYPETYPE TPoints xy1 AS TPoint xy2 AS TPointENDTYPEFUNCTION Poly_Draw_Gradient: xy_px AS TPoints, xy_uv AS TPoints, colours AS TPolyColour POLYNEWSTRIP POLYVECTOR xy_px.xy1.x, xy_px.xy1.y, xy_uv.xy1.x, xy_uv.xy1.y, colours.TL // TL POLYVECTOR xy_px.xy1.x, xy_px.xy2.y, xy_uv.xy1.x, xy_uv.xy2.y, colours.BL // BL POLYVECTOR xy_px.xy2.x, xy_px.xy1.y, xy_uv.xy2.x, xy_uv.xy1.y, colours.TR // TR POLYVECTOR xy_px.xy2.x, xy_px.xy2.y, xy_uv.xy2.x, xy_uv.xy2.y, colours.BR // BRENDFUNCTION`
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

#### fuzzy70

• Community Developer
• Prof. Inline
• Posts: 828
• Look left, Look right, LOOK OUT!!
##### Re: Polyvector Question
« Reply #6 on: 2012-Mar-13 »
Yet again thanks for the tips & the code

I have downloaded the bmfont program & will give that a play, also there is a texture generator on that site that looks like it might be interesting so downloaded that as well  , am a firm believer of "unless you try as many tools as you can, how do you know what ones best for you or has a feature that you need"

I do use the "Updated" font program that was posted in the forum occasionally instead of the standard one & I have numerous font programs.

One problem I am having (which is not a fault of any of the programs) is creating small fonts which are scaled correctly, for example if I want a font that's 8x8 pixels some chars do not scale correctly. I know that is a small size but it happens on a lot of fonts & the size which each font looks "pixel perfect" as such varies. It is mainly due to the nature of scalable fonts I think rather than the programs & to be fair small sizes are where bitmap fonts excel over scalable ones. I got round the problem by using my Amiga font to Sprite program seeing as 95%+ of Amiga fonts are bitmap type (that & the fact that I have 100's of them).

BTW the reason for the small fonts is for a little project I am toying with which again stems from the Amiga. The other day I fired up my Amiga emulator & loaded up Pinball Fantasies, a game which I lost many an hour to when it came out  . While playing it I noticed the dot matrix style scoreboard (same as on real pinball tables tbh) & thought that it would be fun to create my own. At the moment it is still in it's early stages but you can setup up the pixel size (i.e 2x2px with a 1px gap) & the colours as 1 TYPE, another TYPE creates the matrix itself & its size as well as displaying it. I am currently working on the routine to convert a font sprite sheet chars into a dot matrix font as converting them on the fly takes to much time.

The planned features are as follows
• A print command that works the same as the GLB one but for the display
• Animated sprites on the display (again converted in advance)
• Scrolling, both text and/or a graphic
• As many displays as you want & all independent of each other, using an array of types to cycle through them
• Pretty much anything you can do on a dot matrix display

I am using separate TYPE's at the moment but some will be integrated with the goal of making it as simple as possible to use. It is still very much a work in progress & as I am still learning more about GLB I am finding better ways of doing it.

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)