TextOut y value

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: TextOut y value

Post by mattallen37 »

It sort of works, but it is buggy. Run this program to see what I mean:

Code: Select all

task main(){
  RectOut(0, 0, 100, 64, DRAW_OPT_FILL_SHAPE);
  TextOut(0, LCD_LINE2, "Hi.");
  TextOut(0, LCD_LINE5+1, "Hi.");
  TextOut(50, LCD_LINE5-1, "Hi.");
  while(true);
}
It wouldn't be so bad if the rest of the pixels were clear, instead of white, but as it is, it whites out anything in the background for both sets of bytes used (if it doesn't fit in a 1 byte row).
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: TextOut y value

Post by mattallen37 »

Also run this:

Code: Select all

task main(){
  RectOut(0, 0, 100, 64, DRAW_OPT_FILL_SHAPE);
  TextOut(0, LCD_LINE2, "Hi.", DRAW_OPT_INVERT);
  TextOut(0, LCD_LINE5+1, "Hi.", DRAW_OPT_LOGICAL_XOR|DRAW_OPT_INVERT);
  TextOut(50, LCD_LINE5-1, "Hi.", DRAW_OPT_INVERT);
  while(true);
}
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: TextOut y value

Post by afanofosc »

Not quite yet - as I said, it may be buggy still. It does let you draw to any Y value but it is not currently correctly overlaying the bits that overlap the line below/above one of the 8 standard lines. Basically, it is (currently) wiping out the existing text on two lines if the Y value is not a multiple of 8. Once it is working correctly it should only affect the number of bits in each line that it actually overlaps.

Basically, I need someone smart to help me figure out how to do this right. I have an unsigned word (16 bits) that contains the current pixels of the two affected lines, for instance line 0 at the top of the LCD and line 1 just below it. Each line has a strip of 8 vertical pixels at X = 0. So a vertical line at X=0 from Y=48 to Y=63 (16 pixels long) would be a2 == 1111111111111111 in my unsigned word (i.e., all bits set). Then I have 8 bits of the first vertical line of a 6 pixel wide character. For example, an M which would fill all 8 bits with 1s, i.e., a == 11111111. What I want to do is overlay the character data on top of the 16 bit word containing the existing pixel values without changing at all the pixel values of the bits that aren't touched by this new text. So, for example, if I was drawing this character at Y=52 it should not affect the lowest 4 pixels or the highest for pixels. That means, I think, that I should create a mask = ~(0x00FF << offset); where offset == 4 in this example. Which I think would be mask == 1111000000001111. Then I want to shift my character data up into the mask window, i.e., (UWORD)a << offset which should give me an unsigned word == 0000111111110000. So how do I combine my original data (a2) with my mask and my new data (a)?

Basically replace this code with a correct version:

Code: Select all


          switch (LogicalMode)
          {
            case DRAW_LOGICAL_OR:
              a2 |= (UWORD)a << offset;
              break;
            case DRAW_LOGICAL_AND:
              a2 &= (UWORD)a << offset;
              break;
            case DRAW_LOGICAL_XOR:
              a2 ^= (UWORD)a << offset;
              break;
            case DRAW_LOGICAL_COPY:
            default:
              a2 = (UWORD)a << offset;
              break;
          }
I've only tested the default mode which is logical copy and as written you can see that it is wiping out the bits in a2 that it should leave untouched. In any case I've got a bad head cold and can't think straight about this even when I'm not affected by cold medicine. It seems like some simple combination of AND, OR, XOR and NOT will do the trick but I'm drawing a blank.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: TextOut y value

Post by HaWe »

is there a speed issue either writing built-in fonts or grafic ric fonts?
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: TextOut y value

Post by mattallen37 »

Okay, that's about what I thought was happening. I'm going to read through your post a time or two more to try to fully understand what is going on. I agree about using a mask.
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: TextOut y value

Post by afanofosc »

I've got it working now. I just had to look and see how the copy bits code worked for overlaying bits from a sprite onto the existing screen pixels. In the end I iterate through the 8 bits in the source byte and appropriate lay them down one at a time onto the 16 bit destination. Doc's 9 line program works now as does Matt's two sample programs. Grab the latest test release firmware image.
uplow.nxc
(739 Bytes) Downloaded 224 times
John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: TextOut y value

Post by mattallen37 »

So, coming into this piece of code, a2 is set to a value representing the current 16 vertical pixels' states, and at the end, the current pixels' states are set to the value of a2?

Also, in your example, I think you meant the first vertical byte of M to be 0b1111,1110 (assuming the top is msb), not 0b1111,1111.

Here I will be speaking of using an OR, and I will only be talking about the left most pixels of each character (X==0).

Write a M to LCD_LINE2
from top to bottom, the bits (in the left most column) should be set to

0000,0000,1111,1110,0000,0000,0000,0000,00...

Write a M to LCD_LINE1-1
from top to bottom, the bits (in the left most column) should be set to

0111,1111,1111,1110,0000,0000,0000,0000,00...

because you take the top 16 bits which was 0000,0000,1111,1110, and you OR it with 0111,1111,0000,0000. However, you need to give the last 0 of the current character higher preference than the first 1 of the last character. Ideally, it would look like this: 0111,1111,0111,1110, where bit 7 (of 0-15) is a 0, not a 1.

Since all NXT ASCII characters are 6x8 pixels (even if some of them are white), it is important to clear out an 8 bit vertical area before we OR it with the new character.

Something like this: a2 &= ~((UWORD)0x00FF<<offset) would clear out the area we need to use, and then something like this: a2 |= (UWORD)a<<offset would put the correct pixels into the correct place. Or, combined, it would be a2 = (a2 & ~((UWORD)0x00FF<<offset))|((UWORD)a<<offset)

Edit: I see now you figured out a way before me ;)
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
schodet
Posts: 139
Joined: 29 Sep 2010, 11:21
Contact:

Re: TextOut y value

Post by schodet »

How about :

Code: Select all

mask = ~(0x00ff << offset);
font = (UWORD) a << offset;

switch (LogicalMode)
{
    case DRAW_LOGICAL_OR:
        a2 |= font;
        break;
    case DRAW_LOGICAL_AND:
        a2 &= font | mask;
        break;
    case DRAW_LOGICAL_XOR:
        a2 ^= font;
        break;
    case DRAW_LOGICAL_COPY:
    default:
        a2 = (a2 & mask) | font;
        break;
}
Sadly, I could not test without the rest of the code.

EDIT: fixed indent.
LEGO things http://ni.fr.eu.org/lego/ - NXT Improved Firmware (GCC) http://nxt-firmware.ni.fr.eu.org/ - Other robots http://apbteam.org
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: TextOut y value

Post by afanofosc »

Nicolas, your code appears to work great. It's pretty obvious once the code is right in front of you. :-) If someone would like to run some timing tests to compare text drawing before this feature to the current speed I'd be interested to see the results. It should be a bit slower but probably only just a tiny bit, maybe not even noticeable. My approach which was iterating one bit at a time through the font data was probably worse than this code - again it's hard to say whether it would be noticeably slower or not. Definitely less code, which is great.

Here's the full function:

Code: Select all

void cCmdDrawString(UBYTE *pString, ULONG X, ULONG Y, UBYTE InvertMode, UBYTE LogicalMode, UBYTE FillMode)    //JJR
{
  UBYTE   *pSource;
  UBYTE   *pDestination1;
  UBYTE   *pDestination2;
  UBYTE   a;
  FONT    *pFont;
  ULONG   FontWidth;
  ULONG   Items;
  ULONG   Item;
  SLONG   Line;
  UBYTE   offset;
  UWORD   a2;
  UWORD   mask;
  UWORD   font;

  //Get current font information
  pFont = pMapDisplay->pFont;
  Items = pFont->ItemsX * pFont->ItemsY;

  //Invert Y coordinate to match display buffer
  Y = TRANSLATE_Y(Y);
  Line = (Y & 0xF8) / 8; // truncates down to nearest multiple of 8
  offset = (Y-7) % 8; // how many bits is the content shifted?
  if (offset)
    Line--;
    
  mask = ~(0x00ff << offset);

  //If text line is out of bounds, do nothing.
  if (Line >= TEXTLINES)
    return;

  //Calculate pointer to first byte of drawing destination
  if (Line >= TEXTLINE_1)
    pDestination1 = &(DISP_BUFFER_P[Line * DISPLAY_WIDTH + X]);
  else
    pDestination1 = NULL;
  if (offset && (Line < TEXTLINE_8))
    pDestination2 = &(DISP_BUFFER_P[(Line+1) * DISPLAY_WIDTH + X]);
  else
    pDestination2 = NULL;

  // bail out early if neither destination is valid
  if (pDestination1 == NULL && pDestination2 == NULL)
    return;

  while (*pString)
  {
    FontWidth = pFont->ItemPixelsX;
    //Calculate X coordinate of the right edge of this character.
    //If it will extend past the right edge, clip the string.
    X += FontWidth;
    if (X > DISPLAY_WIDTH) // JCH: was >= This clipped text that ended at pixel 99
      break;

    //If Item is defined by the font, display it.  Else, ignore it.
    Item = *pString - ' ';
    if (Item < Items)
    {
      pSource      = (UBYTE*)&(pFont->Data[Item * FontWidth]);
      while (FontWidth--)
      {
//JJR

          //Fetch a byte from the source bitmap:
          //If fill mode is on, pretend the source bitmap is solid:
          if (FillMode==DRAW_SHAPE_FILLED)
            a = 0xff;
          else
            a = *pSource;
            
          //Implement bitmap invert mode:
          if (InvertMode==DRAW_BITMAP_INVERT) a = ~a;

          // grab data from 1 or 2 lines 
          a2 = (pDestination2 ? ((UWORD)(*pDestination2) << 8) : 0x0000) |
               (pDestination1 ? (UWORD)(*pDestination1) : 0x0000);

          font = (UWORD) a << offset;
          
          switch (LogicalMode)
          {
              case DRAW_LOGICAL_OR:
                  a2 |= font;
                  break;
              case DRAW_LOGICAL_AND:
                  a2 &= font | mask;
                  break;
              case DRAW_LOGICAL_XOR:
                  a2 ^= font;
                  break;
              case DRAW_LOGICAL_COPY:
              default:
                  a2 = (a2 & mask) | font;
                  break;
          }
//JJR
        if (pDestination1) {
          *pDestination1 = (UBYTE)(a2 & 0xFF);
          pDestination1++;
        }
        if (pDestination2) {
          *pDestination2 = ((UBYTE)(a2>>8) & 0xFF);
          pDestination2++;
        }
        pSource++;
      }
    }
    pString++;
  }
}
If you have any ideas what I might be doing wrong with my JMPABSVAR opcode (and almost certainly the BRCMPABSVAR and BRTSTABSVAR opcodes) I'd be grateful for the assistance there as well. I'll check in the code later on tonight so you can have a look at it, if you are interested.

I think my compiler is generating the right value for the absolute address to jump to (which I am trying to convert into a relative jump offset) but I wind up getting a ERR_INSTR file abort.

Thanks for your help!

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
mspall
Posts: 15
Joined: 31 Oct 2011, 19:29

Re: TextOut y value

Post by mspall »

I ran tests using this code:

Code: Select all

task main()
{
  unsigned int i, s, f, diff;
  s = CurrentTick();
  for(i=0; i<1000; i++){
    TextOut(0,LCD_LINE1,"Cicero scripsit:");
    TextOut(0,LCD_LINE2,"Neque porro quisquam");
    TextOut(0,LCD_LINE3,"est, qui dolorem");
    TextOut(0,LCD_LINE4,"ipsum,quia dolor sit");
    TextOut(0,LCD_LINE5,"amet, consectetur,");
    TextOut(0,LCD_LINE6,"adipisci con velit-");
    TextOut(0,LCD_LINE7,"Sed Cicero");
    TextOut(0,LCD_LINE8,"erat iniuriam:");

    TextOut(0,LCD_LINE1,"Neque porro quisquam");
    TextOut(0,LCD_LINE2,"est, qui dolorem");
    TextOut(0,LCD_LINE3,"ipsum,quia dolor sit");
    TextOut(0,LCD_LINE4,"amet, consectetur,");
    TextOut(0,LCD_LINE5,"adipisci con velit-");
    TextOut(0,LCD_LINE6,"Sed Cicero");
    TextOut(0,LCD_LINE7,"erat iniuriam:");
    TextOut(0,LCD_LINE8,"Redundant est!");
  }
  f = CurrentTick();
  diff = f - s;
  ClearScreen();
  NumOut(0,LCD_LINE1,diff);
  while(true);
}
and the last three firmwares. These are the average timings in ticks (n = 5):
lms_arm_nbcnxc_131_20111019_1659.rfw 5507
lms_arm_nbcnxc_132_20120205_1737.rfw 6872
lms_arm_nbcnxc_132_20120206_1512.rfw 17231

lms_arm_nbcnxc_132_20120205_1737.rfw takes 1.25 times as long as the first firmware.
lms_arm_nbcnxc_132_20120206_1512.rfw takes 3.13 times as long as the first firmware.
Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests