BBC BASIC for Windows
Programming >> Graphics and Games >> Angled Text
http://bb4w.conforums.com/index.cgi?board=graphics&action=display&num=1491966882

Angled Text
Post by KenDown on Apr 12th, 2017, 03:14am

I'm not sure where to put this, so if a moderator wants to move it, that's fine.

Someone, somewhere, posted a method of drawing angled text (was it Richard in the Help?) which I have been using for a while, so imagine my horror to discover that it didn't handle non-ASCII text - ie. UTF-8 text. It took me a while to sort it out, but here's the result. (Note, it is a funciton rather than a proc as that fits my program better. It can be easily turned into a proc.)

REM Draws text at the specified angle and colour
DEFFNangled(font$,height%,weight%,text$,angle,X%,Y%,col%)
LOCALfont%,oldfont%,L%
DIMU%LOCAL1024:U%=(U%+1)AND-2
SYS"CreateFont",height%,0,angle*10,angle*10,weight%,0,0,0,0,0,0,0,0,font$TOfont%
SYS"SelectObject",@memhdc%,font%TOoldfont%
SYS"SetTextColor",@memhdc%,&1000000+col%
SYS"SetBkColor",@memhdc%,&1000000+@vdu%?71
SYS"SetBkMode",@memhdc%,1
SYS"MultiByteToWideChar",&FDE9,0,text$,LENtext$,0,0TOL%
SYS"MultiByteToWideChar",&FDE9,0,text$,LENtext$,U%,L%
SYS"TextOutW",@memhdc%,X%,Y%,$U%,L%
SYS"SetBkMode",@memhdc%,2
SYS"InvalidateRect",@hwnd%,0,0
SYS"SelectObject",@memhdc%,oldfont%
SYS"DeleteObject",font%
=0

Many thanks to whoever posted the original code. I couldn't have done it on my own!
Re: Angled Text
Post by hellomike on Apr 13th, 2017, 07:37am

Hi Ken,

The code indeed crashes. The reason is that you pass $U% to "TextOutW" and not U%.
This way the SYS looks for the string located at the address that is in the first bytes of U%, not in U% itself.

Hope this helps.

Mike
Re: Angled Text
Post by KenDown on Apr 13th, 2017, 4:21pm

That's an interesting comment, given that it is working perfectly with $U%.

However, following your remarks I removed the $ and somewhat to my surprise it continues to work with U%. Surely, if it wants the address of U% it would require something like ^U%?


Re: Angled Text
Post by hellomike on Apr 14th, 2017, 09:51am

I was confused because I assumed you started this thread because your code wasn't working.
And now I'm still confused because the code you posted crashes the interpreter for me, caused by (as far as I can see) using $U% instead of U%.

In the 2nd SYS "MultiByteToWideChar" in your code, you correctly pass the address (stored in U%), pointing to the memory where the wide string is to be placed.
Following, SYS "TextOutW" needs an address where the wide string can be found in the same manner. So, also U%.

$U% doesn't contain an address. Also note that after the 2nd SYS "MultiByteToWideChar", U% now points to a wide (two bytes per character) string, NOT to a &0D terminated one-byte character string, so $U% will give unpredictable result.

The notation without the '$' in the SYS call is the correct one. See for example the BB4W wiki, article http://bb4w.wikispaces.com/Unicode+filenames.

Using assembly language, I checked what value was passed by using $U% as a SYS parameter. And it is a value in or near the stack, so near the value of HIMEM.

Re: Angled Text
Post by KenDown on Apr 14th, 2017, 1:35pm

No, I posted it because a) I was rather pleased with myself for sorting it out without bleating for help, and b) I thought someone else might find it useful.

As it turns out, you have kindly corrected my code, but it is curious that it worked fine for me with $U% but crashes for you. Anyway, I have changed my code to the correct version, so again, thanks.
Re: Angled Text
Post by marsFS on Nov 2nd, 2017, 9:51pm

This is great!

Just thought I'd post the code along with the fix you mentioned and a little demo in case someone needs an example of how to use.
Code:
      MODE 22

      ON ERROR: OSCLI "REFRESH ON":END

      an%=0
      c%=1
      a$="WOW! Rotating text :-)"

      *REFRESH OFF

      REPEAT
  
        an%+=1: IF an%>=360 THEN
          an%=an%-360
          c%+=1: IF c%=16 THEN c%=1
        ENDIF
  
        CLG
        a%=FNangled("Arial",40,2,a$,an%,512,384,c%)
  
        *REFRESH
        WAIT 1
      UNTIL FALSE
      END

      REM Draws text at the specified angle and colour
      DEFFNangled(font$,height%,weight%,text$,angle,X%,Y%,col%)
      LOCALfont%,oldfont%,L%
      DIMU%LOCAL1024:U%=(U%+1)AND-2
      SYS"CreateFont",height%,0,angle*10,angle*10,weight%,0,0,0,0,0,0,0,0,font$TOfont%
      SYS"SelectObject",@memhdc%,font%TOoldfont%
      SYS"SetTextColor",@memhdc%,&1000000+col%
      SYS"SetBkColor",@memhdc%,&1000000+@vdu%?71
      SYS"SetBkMode",@memhdc%,1
      SYS"MultiByteToWideChar",&FDE9,0,text$,LENtext$,0,0TOL%
      SYS"MultiByteToWideChar",&FDE9,0,text$,LENtext$,U%,L%
      SYS"TextOutW",@memhdc%,X%,Y%,U%,L%
      SYS"SetBkMode",@memhdc%,2
      SYS"InvalidateRect",@hwnd%,0,0
      SYS"SelectObject",@memhdc%,oldfont%
      SYS"DeleteObject",font%
      =0
 

Re: Angled Text
Post by KenDown on Nov 3rd, 2017, 04:35am

Excellent. And it works just as well if you have

a$="Пастор Кендал Даун"

Which of course was the problem all along.

Once again, thanks to all those who helped.
Re: Angled Text
Post by KenDown on Nov 3rd, 2017, 04:39am

All we need now is some clever clogs to come up with a way of rotating around the centre of the line of text and we'll really have something that will knock people's eyes out!
Re: Angled Text
Post by KenDown on Nov 3rd, 2017, 07:28am

The other thing, of course, is that if you want to save a fraction of a second, you can DIM the U% in your intialisation, rather than DIMming it again every time the routine is called. Just leave the LOCAL out of the line and put it elsewhere.
Re: Angled Text
Post by DDRM on Nov 3rd, 2017, 5:12pm

You mean like this?
Code:
      MODE 22

      ON ERROR: OSCLI "REFRESH ON":END

      an%=0
      c%=1
      a$="WOW! Rotating text :-)"
      w%=FNstringwidth(a$)

      *REFRESH OFF

      REPEAT
  
        an%+=1: IF an%>=360 THEN
          an%=an%-360
          c%+=1: IF c%=16 THEN c%=1
        ENDIF
  
        CLG
        dx%=w%*COSRAD(an%)+@vdu%!220*COSRAD(an%-90)
        dy%=w%*SINRAD(an%)+@vdu%!220*SINRAD(an%-90)
        a%=FNangled("Arial",40,2,a$,an%,512-dx%,384+dy%,c%)
        PLOT 69,1024,768 :REM Centre of rotation, in BB4W graphics units
        *REFRESH
        WAIT 1
      UNTIL FALSE
      END

      REM Draws text at the specified angle and colour
      DEFFNangled(font$,height%,weight%,text$,angle,X%,Y%,col%)
      LOCALfont%,oldfont%,L%
      DIMU%LOCAL1024:U%=(U%+1)AND-2
      SYS"CreateFont",height%,0,angle*10,angle*10,weight%,0,0,0,0,0,0,0,0,font$TOfont%
      SYS"SelectObject",@memhdc%,font%TOoldfont%
      SYS"SetTextColor",@memhdc%,&1000000+col%
      SYS"SetBkColor",@memhdc%,&1000000+@vdu%?71
      SYS"SetBkMode",@memhdc%,1
      SYS"MultiByteToWideChar",&FDE9,0,text$,LENtext$,0,0TOL%
      SYS"MultiByteToWideChar",&FDE9,0,text$,LENtext$,U%,L%
      SYS"TextOutW",@memhdc%,X%,Y%,U%,L%
      SYS"SetBkMode",@memhdc%,2
      SYS"InvalidateRect",@hwnd%,0,0
      SYS"SelectObject",@memhdc%,oldfont%
      SYS"DeleteObject",font%
      =0
      :
      DEF FNstringwidth(a$)
      LOCAL @vdu.m.c&, @vdu.l.x%, @vdu.l.y%, ?444
      VDU 5,23,16,0|30,11,23,16,64|10,10
      PRINT a$;
      @vdu.l.y% = GET(0,0) : REM SDL thread sync.
      = @vdu.l.x%
 

The function at the bottom is something of Richard's to find the actual length at which a string will print, in pixels. I've just used it to offset the start point for the string plotting.

It needs an additional small correction to allow for the height of the characters, which is 90 degrees out of phase.

:-)

D
Re: Angled Text
Post by KenDown on Nov 23rd, 2017, 01:25am

Yes, very clever. For some reason it jumps every 90 degrees and I can't work out why. However it is still clever.
Re: Angled Text
Post by DDRM on Nov 23rd, 2017, 07:56am

Not sure I know why, either. It seems less prominent if you change all the references to an% to an, and then make the start angle 0.1. There's a little bit of wobble going on all the time.

I suspect it's because the possible plot positions are integers, and there is a sudden transition from one to the next which is most noticeable when the line is horizontal or vertical (because the whole line shifts, rather than just some of the pixels making up the characters. I haven't done any maths to test that idea though.

Maybe if you used GDIP (which allows sub-pixel locations) it would be better? Unfortunately, GDIPLib doesn't contain text output functions...

Best wishes,

D
Re: Angled Text
Post by KenDown on Nov 23rd, 2017, 2:00pm

I'm not referring to the slight back-and-forth jiggling which, as you say, is due to the pixel positioning.

Rather the rotating seems to jump every 90 degrees, which it doesn't do (or not that I've noticed) in my routine where the line of text rotated around its start point rather than its middle point. As the two routines use the same mathematics, it's odd.
Re: Angled Text
Post by marsFS on Nov 23rd, 2017, 11:55pm

Seems to be when at 0, 90, 180 and 270 degrees

I added a pixel plot using the same coordinates which doesn't jump around so I can only assume the SYS call is fudging the angle when plotting the angled text.

If it were an issue and knowing that it happens for fixed angles you maybe be able to add an offset to x or y to mask the issue?






Re: Angled Text
Post by DDRM on Nov 24th, 2017, 5:13pm

I've been playing with this a bit more. It's funny, because at least on my machine it doesn't jump EVERY time, despite all the parameters being integers. I get the impression it gets worse with time, too.

I actually think it might be a rendering conflict. There is a "InvalidateRect" call in the function, AND I've got a *REFRESH which is doing something similar. If I disable the *REFRESH OFF and the *REFRESH it seems to happen less (though the text flickers appallingly).

D
Re: Angled Text
Post by KenDown on Nov 24th, 2017, 8:10pm

That's a thought. Of course in theory the two calls do different things, but it seems to work just as well when the InvalidateRect is REMed out.

Mind you, it has slowed down enormously after a few minutes and the "jumps" are really noticeable.

It's all a mystery!