Monthly Archives: September 2014

& and @!

Quick update since I’m on the move and don’t have access to the source code.

My final experiment last night was sort of successful. I allocated an array using ARRAY CREATE and on the handle that was returned I used the @ operator, so I did MOVE32_32( @handle, variable ) and the content of the variable was something like 0x00032ac30.

Then I did MOVE32_32( &variable, var2 ) and var2 was set to 0x0201.

So that seems great but the reason why I’m not yet happy is because I then tried to set the contents of the array with ARRAY WRITE_CONTENT and after that my experiment fell apart and I could no longer use the & operator, not even when I reverted back to the exact same code I had used when it worked the first time.

So in conclusion, this seems like it might work but I’m also having trouble taming it.

No love for the address?

I’ve been looking more into the & operator, which seems pretty great. But it doesn’t seem to be fully supported.

When reading through the code that decode parameters, and looking at the comments, the code seems to fully decode the address, but the comment have completely emitted the information.

So basically, the compiler builds a stream of bytes form the LMS code. The byte stream is super simple. It is a byte that represent the opcode, and then a bunch of bytes representing potential parameters. If we look at the byte code for:

MOVE32_32( 1145324612, MyVar1 )

It can compile into:

3A834444444440

If we split it up into opcode and parameters it becomes this:

0x3a,         // Opcode for MOVE32_32
0x83,         // Information for first parameter.  Binary: 1000 0011
0x44444444,   // Constant for 1145324612
0x40,         // Information for second parameter. Binary: 0100 0000

So the opcode is 0x3a, and if we look at the native code for MOVE32_32 we see this:

void      cMove32to32(void)
{
  DATA32  Tmp;

  Tmp  =  *(DATA32*)PrimParPointer();
  *(DATA32*)PrimParPointer()  =  Tmp;
}

That code contain two calls to PrimParPointer, and what that does is first look at the information for the parameter, and then either fetch a constant, fetch a local or global variable. The bitfield is explained as a comment for PrimParPointer and looks like this:

/*! \page parameterencoding Parameter Encoding
 *
 *  Parameter types and values for primitives, system calls and subroutine calls are encoded in the callers byte code stream as follows:
 *
 *  opADD8 (ParCode1, ParCode2, ParCodeN)
 * \verbatim
Bits  76543210
      --------
      0Ttxxxxx    short format
      ||||||||
      |0||||||    constant
      ||||||||
      ||0vvvvv    positive value
      ||1vvvvv    negative value
      |||
      |1|         variable
      | |
      | 0iiiii    local index
      | 1iiiii    global index
      |
      1ttt-bbb    long format
       ||| |||
       0|| |||    constant
       ||| |||
       |0| |||    value
       |1| |||    label
       ||| |||
       1|| |||    variable
        || |||
        0| |||    local
        1| |||    global
         | |||
         0 |||    value
         1 |||    handle
           |||
           000    Zero terminated string  (subject to change)
           001    1 bytes to follow       (subject to change)
           010    2 bytes to follow       (subject to change)
           011    4 bytes to follow       (subject to change)
           100    Zero terminated string  \endverbatim
 *
 */

So if we again look at our parameters. First the first parameter:

Binary: 1000 0011

According to the comment it is in long format, it is a constant, it is a value and it contains four bytes. The PrimParPointer will the go on to read those 4 bytes from the byte stream, which are as we saw earlier

0x44444444

The second parameter information is then:

Binary: 0100 0000

So according to the comment that means it is in short format, it is a variable, and the variable index is 0.

So that’s it, that is how the parameter encoding works. Those of you with a keen eye may have noticed that in the long format there is one bit that isn’t explained. Bit 3. (If you follow their naming of the bits) Bit 4 explain if it is a handle or not, but bit 3 is left out.

So I went back to look at the code that is generated for this:

MOVE32_32( &MyVar1, MyVar2 )

And the generated byte code is:

0x3A,  // Opcode for MOVE32_32
0xC9,  // First parameter information.  Binary: 1100 1001
0x00,  // ??
0x44,  // Second parameter information. Binary: 0100 0100

The encoding of the parameter information when doing & seems to be perfectly fine, and the code in PrimParPointer seems to be perfectly valid too. It looks like this:

    if (Data & PRIMPAR_HANDLE)
    {
      VMInstance.Handle  =  *(HANDLER*)Result;
      cMemoryArraryPointer(VMInstance.ProgramId,VMInstance.Handle,&Result);
    }
    else
    {
      if (Data & PRIMPAR_ADDR)
      {
        Result  =  (void*)*(DATA32*)Result;
        VMInstance.Value  =  (DATA32)Result;
      }
    }

So it seems like the @ operator (handle) will return the pointer to an address based on a handle used when calling ARRAY( CREATEx, … ) and the & operator (address) will type case the Result (which is a pointer) and dereference that address to get a new address, which it returns.

I’m confused..

In any case, that 0x00 that snuck in straight after the 0xc9 seems misplaced, but other than that it seems like addresses may work. I will remove the 0x00 and see what the VM think about that.

&?

Yesterday I played around with using & to get the address of a variable. In assembler.logo there is a function called get-adr that is called when you do & on a variable.

However, the VM got stuck in an infinite loop when doing this super simple test:

vmthread  MAIN
{
	DATA32 MyVar
	DATA32 MyAddress
	MOVE32_32( &MyVar, MyAdress )
}

So I looked at all the existing LMS files that shipped with the LMS2012 and none of them used the & operator. I’ve done some simple tests to just look at the compiled RBF file when doing & and see if I get any wiser. After that I’ll look into @ and see if that is anything I could use.

Array anxiety

Today I was going to create an array into which I would write handles to all existing game objects in the scene. So So I created all the functions I needed to create the array, find a free slot, add and remove game objects into the array, and a debug function to verify consistency.

What I found with the debug function was really strange though!

So I created the array, filled it with -1 (to indicate unused array entries) and printed the array. All entries came out -1, as expected.

Then I wrote the number 3 into the first entry of the array. I was expecting that all the other entries in the array would remain untouched, so I expected them all to be -1. But when I printed the entries they had all been set to 0. Very strange!

So I did an experiment. I only wrote the number 6 into the sixth entry in the array. The result was that entry 0-5 had kept their values, so they were -1. The sixth entry had the value 6. All the following entries had the value 0.

I started suspecting that WRITE_CONTENT would fill the rest of the array with garbage so my next experiment was to first write the value 7 into index 7, and value 6 into index 6. As expected the array was -1 up to entry 5, entry 6 had the value 6 and all following entries was 0. I was onto something.

However, my next test would confuse me. My next test sequence was:
Write value 6 into entry 6
Write value 5 into entry 5
Write value 7 into entry 7
Because my theory was that WRITE_CONTENT was writing trailing zeroes whenever I wrote something to the array I expected the array to look like:
-1
-1
-1
-1
-1
5
0
7
0..

But instead the array was:
-1
-1
-1
-1
-1
5
6
7
0..

So now it looked like the array worked properly.

I went back to writing 6 to 6 and 5 to 5, and it didn’t work.

I had a few ideas of what it could be but none of them fitted and I couldn’t really find a pattern to what was going on. My next test sequence was
Write 0 to entry 0
Write 6 to entry 6
Write 5 to entry 5
Write 7 to entry 7

The result looked like this:
1
-1
-1
-1
33
5
6
7
0..

Now a completely random (to me) value had appeared in the array. 33.

It was a this point I gave up and started looking at the source. I’m generally too lazy to look at the source, but sometimes things just doesn’t make sense I don’t have any choice. So this is the source:

    case WRITE_CONTENT :
    {
      PrgId           =  *(DATA16*)PrimParPointer();
      TmpHandle       =  *(DATA16*)PrimParPointer();
      Index           =  *(DATA32*)PrimParPointer();
      Bytes           =  *(DATA32*)PrimParPointer();
      pDData8         =  (DATA8*)PrimParPointer();

      DspStat         =  FAILBREAK;

#ifdef DEBUG
      printf("ARRAY WRITE_CONTENT CP=%d PP=%d\r\n",TmpPrgId,PrgId);
#endif

      if (PrgId == (PRGID)CURRENT_SLOT)
      {
        PrgId         =  TmpPrgId;
      }

      if (cMemoryGetPointer(PrgId,TmpHandle,&pTmp) == OK)
      {
        ElementSize   =  (DATA32)(*(DESCR*)pTmp).ElementSize;
        if (ElementSize)
        {
          Elements      =  (Index + Bytes + (ElementSize - 1)) / ElementSize;
          ISize         =  Elements * ElementSize;

          pTmp          =  cMemoryResize(PrgId,TmpHandle,Elements);
          if (pTmp != NULL)
          {
            if ((Index >= 0) && (pDData8 != NULL))
            {
              pData8      =  (DATA8*)pTmp;
              Data32      =  0;

              while ((Data32 < Bytes) && (Index < ISize))
              {
                pData8[Index]   =  pDData8[Data32];
                Data32++;
                Index++;
              }
              DspStat     =  NOBREAK;
            }
          }
        }
      }
    }
    break;

The keen of you will notice there is a cMemoryResize() call in there. I was naïvely assuming it would only resize the array if Elements was too great to fit all the data to be written to the array, but I looked into it just to be safe.

void*     cMemoryResize(PRGID PrgId,HANDLER TmpHandle,DATA32 Elements)
{
  DATA32  Size;
  void    *pTmp = NULL;


  if (cMemoryGetPointer(PrgId,TmpHandle,&pTmp) == OK)
  {
    Size    =  Elements * (*(DESCR*)pTmp).ElementSize + sizeof(DESCR);
    pTmp    =  cMemoryReallocate(PrgId,TmpHandle,(GBINDEX)Size);
    if (pTmp != NULL)
    {
      (*(DESCR*)pTmp).Elements  =  Elements;
    }

#ifdef DEBUG
    printf("  Resize P=%1u H=%1u T=%1u S=%8lu A=%8p\r\n",(unsigned int)PrgId,(unsigned int)TmpHandle,(unsigned int)MemoryInstance.pPoolList[PrgId][TmpHandle].Type,(unsigned long)MemoryInstance.pPoolList[PrgId][TmpHandle].Size,MemoryInstance.pPoolList[PrgId][TmpHandle].pPool);
#endif
  }
  if (pTmp != NULL)
  {
    pTmp  =  (*(DESCR*)pTmp).pArray;
  }

  return (pTmp);
}

As you can see it always go to cMemoryRealloc() so let’s have a look at that

void*     cMemoryReallocate(PRGID PrgId,HANDLER Handle,GBINDEX Size)
{
  void    *pTmp;

  pTmp  =  NULL;
  if ((PrgId < MAX_PROGRAMS) && (Handle >= 0) && (Handle < MAX_HANDLES))
  {
    if ((Size > 0) && (Size <= MAX_ARRAY_SIZE))
    {
      if (cMemoryRealloc(MemoryInstance.pPoolList[PrgId][Handle].pPool,&pTmp,(DATA32)Size) == OK)
      {
        MemoryInstance.pPoolList[PrgId][Handle].pPool  =  pTmp;
        MemoryInstance.pPoolList[PrgId][Handle].Size   =  Size;
      }
      else
      {
        pTmp  =  NULL;
        printf("cMemoryReallocate out of memory\r\n");
      }
    }
  }
#ifdef DEBUG
  if (pTmp != NULL)
  {
    printf("  Reallocate  P=%1u H=%1u     S=%8lu A=%8p\r\n",(unsigned int)PrgId,(unsigned int)Handle,(unsigned long)Size,MemoryInstance.pPoolList[PrgId][Handle].pPool);
  }
  else
  {
    printf("  Reallocate error P=%1u H=%1u S=%8lu\r\n",(unsigned int)PrgId,(unsigned int)Handle,(unsigned long)Size);
  }
#endif

  return (pTmp);
}

This in turn is also just doing some sanity checks before entering cMemoryRealloc()

RESULT    cMemoryRealloc(void *pOldMemory,void **ppMemory,DATA32 Size)
{
  RESULT  Result = FAIL;

  *ppMemory  =  realloc(pOldMemory,(size_t)Size);
  if (*ppMemory != NULL)
  {
    Result  =  OK;
  }

  return (Result);
}

As you can see cMemoryRealloc always go to stdlib realloc.

Soo, if I’m not missing anything, WRITE_CONTENT will ALWAYS reallocate the array, and use the realloc() call to move data from the old block to the new. So that explains a lot.

I don’t have a plan for how to handle arrays yet, but it seems like arbitrarily writing into an array isn’t supported by the VM. I will have to dig in deeper to see if there are any work arounds, but it seems like writing to an array isn’t as straight forward as I would have hoped.

I’m still not on top of the LMS syntax but I have the @ and & in mind. Perhaps they can be of help here. Maybe I don’t have to use the bulky READ_CONTENT and WRITE_CONTENT, maybe those are just for writing big amounts of data into an array. I still think I need to use arrays to allocate memory though.

Trying out handles and addresses will be my next project!

Using arrays

For my little game I will be using arrays to represent game objects. I figured I want some sort of object oriented game where I could create a Game Object and use functions to manipulate it.

Since I’m looking to do a top down adventure game I want to build rooms and in each room I want to have objects like enemies, pickups, the player etc. So to do I want to easily be able to manage a bunch of different game objects.

I want something like this (pseudo code)

hGameObject = GameObject_Create()
GameObject_SetPosition( hGameObject, 0, 0 )
GameObject_Render( hGameObject )

Since LMS doesn’t have the concept of complex data structures I figured I could do something like that using arrays. So my principle is simple. A game object is an array of 16 bit values. Each value represent a handle to a component. A component can hold different kinds of data, depending on what the component is.

For example a component can be the world position of the game object, it can be a sprite to be rendered, it may be AI information, it could be an inventory etc. This type of component based game objects is common in the world of making games, and if you’re used to Unity you will immediately recognize what I’m going for. I’ve even borrowed the component names when it makes sense. I’m just that used to Unity. :)

So I created an array like so:

ARRAY( CREATE16, NUM_COMPONENTS, hGameObject )

And I created my first component, the Transform component, and added it to my game object like so:

HANDLE  hTransform
ARRAY( CREATE16, 2, hTransform )
ARRAY( WRITE_CONTENT, -1, hTransform, 0, 2, 0 )
ARRAY( WRITE_CONTENT, -1, hTransform, 1, 2, 0 )
ARRAY( WRITE_CONTENT, -1, hGameObject, 0, 2, hTransform )

This was all fine and dandy. So I added my second component, the sprite.

ARRAY( WRITE_CONTENT, -1, hGameObject, 1, 2, hSprite )

The code was spread out in different functions but all in all it looked (something like) this:

subcall GameObject_Create
{
  IN_16   hSprite       // The sprite that the game object should use for rendering
  OUT_16  hGameObject   // The handle this function will create

  // Create root array that will hold handles to all components
  ARRAY( CREATE16, NUM_COMPONENTS, hGameObject )

  // Add transform
  HANDLE  hTransform
  ARRAY( CREATE16, 2, hTransform )
  ARRAY( WRITE_CONTENT, -1, hTransform, 0, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hTransform, 1, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hGameObject, 0, 2, hTransform )

  // Add sprite
  ARRAY( WRITE_CONTENT, -1, hGameObject, 1, 2, hSprite )
}

But now the angst begun.

When I read the handle of the transform array I got strange results. I had written 4 to index 0, and when I read I got 772 back. At first I believed the problem was because I wrote 4 in one function and read it back in another function.

After some investigation it turned out that the index for READ_CONTENT and WRITE_CONTENT was the array offset in bytes, not the index based on the size of the array elements. I thought that if I asked to read from index 1 in an array with 16 bit elements the byte offset would be translated to 2, but alas it was not! And to my embarrassment it even say in the code that the index is in bytes, not in elements.

 *  - CMD = READ_CONTENT
 *    -   \param  (DATA16)  PRGID     - Program slot number (must be running) (see \ref prgid)\n
 *    -   \param  (HANDLER) HANDLE    - Array handle\n
 *    -   \param  (DATA32)  INDEX     - Index to first byte to read\n
 *    -   \param  (DATA32)  BYTES     - Number of bytes to read\n
 *    -   \return (DATA8)   ARRAY     - First byte of array to receive data\n
 *
 *\n
 *  - CMD = WRITE_CONTENT
 *    -   \param  (DATA16)  PRGID     - Program slot number (must be running) (see \ref prgid)\n
 *    -   \param  (HANDLER) HANDLE    - Array handle\n
 *    -   \param  (DATA32)  INDEX     - Index to first byte to write\n
 *    -   \param  (DATA32)  BYTES     - Number of bytes to write\n
 *    -   \param  (DATA8)   ARRAY     - First byte of array to deliver data\n

So to get it to work I had to write the code like this:

subcall GameObject_Create
{
  IN_16   hSprite       // The sprite that the game object should use for rendering
  OUT_16  hGameObject   // The handle this function will create

  // Create root array that will hold handles to all components
  ARRAY( CREATE16, NUM_COMPONENTS, hGameObject )

  // Add transform
  HANDLE  hTransform
  ARRAY( CREATE16, 2, hTransform )
  ARRAY( WRITE_CONTENT, -1, hTransform, 0, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hTransform, 2, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hGameObject, 0, 2, hTransform )

  // Add sprite
  ARRAY( WRITE_CONTENT, -1, hGameObject, 2, 2, hSprite )
}

That way it worked beautifully. On top of that I also have constants that define the read and write offset of transform. So the whole game object code currently look like this:

/**************************************************************************************************
*
*   Game object functions
*
* Game objects will have a component like structore
* A game object will basically be an array of arrays
* It will be decided what goes in each array
* For example, the first array may contain the transform information such as position
* The second array may contan sprite data, so a reference to a loaded sprite.
*   (Assuming multiple game object may reference the same sprite)
* The third array may contain animation data, such as current frame, time in current frame
* Each array will be defined individually
*
* So, we will create an array of 16 bit values.
* GAMEOBJECT = new DATA16[];
*
* The we will create each "component"
* GAMEOBJECT[ 0 ] = new DATA32[];
*
* The we can populate each component with data
* GAMEOBJECT[ 0 ][ 0 ] = position_x;
*
* The indices will have constants, to make it easier to remember the contents
* GAMEOBJECT[ Transform ][ world_x ] = position_x;
*
* If we would see the multidimensional array as a JSON it would look like this:
* GAMEOBJECT =
* {
*   Transform =     // index 0
*   {               //
*     world_x,      //   index 0
*     world_y       //   index 1
*   },              //
*   Sprite =        // index 1
*   {               //
*     Reference to  //
*     loaded sprite //
*   },
*   Animation =     // index 2
*   {               //
*     frame_time,   //    index 0
*     current_frame //    index 1
*   }
* }
*
**************************************************************************************************/
define COMPONENT_TRANSFORM          0
define COMPONENT_SPRITE             2
define COMPONENT_ANIMATION          4
define NUM_COMPONENTS               3

subcall GameObject_Create
{
  IN_16   hSprite       // The sprite that the game object should use for rendering
  OUT_16  hGameObject   // The handle this function will create

  // Create root array that will hold handles to all components
  ARRAY( CREATE16, NUM_COMPONENTS, hGameObject )

  // Create each component
  CALL( GameObject_AddComponent_Transform, hGameObject )
  CALL( GameObject_AddComponent_Sprite, hGameObject, hSprite )
}

subcall GameObject_AddComponent_Transform
{
  IN_16   hGameObject

  HANDLE  hTransform
  ARRAY( CREATE16, 2, hTransform )
  ARRAY( WRITE_CONTENT, -1, hTransform, TRANSFORM_X, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hTransform, TRANSFORM_Y, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hGameObject, COMPONENT_TRANSFORM, 2, hTransform )
}

subcall GameObject_AddComponent_Sprite
{
  IN_16   hGameObject
  IN_16   hSprite

  ARRAY( WRITE_CONTENT, -1, hGameObject, COMPONENT_SPRITE, 2, hSprite )
}

subcall GameObject_GetComponent
{
  IN_16   hGameObject
  IN_32   ComponentIndex
  OUT_16  hComponent

  ARRAY( READ_CONTENT, -1, hGameObject, ComponentIndex, 2, hComponent )
}

/**************************************************************************************************
*
*   Transform functions
*
**************************************************************************************************/
define TRANSFORM_X      0
define TRANSFORM_Y      2
subcall Transform_SetPosition
{
  IN_16     hGameObject
  IN_16     PositionX
  IN_16     PositionY

  HANDLE  hTransform
  CALL( GameObject_GetComponent, hGameObject, COMPONENT_TRANSFORM, hTransform )
  ARRAY( WRITE_CONTENT, -1, hTransform, TRANSFORM_X, 2, PositionX )
  ARRAY( WRITE_CONTENT, -1, hTransform, TRANSFORM_Y, 2, PositionY )

  DATA16 temp
  ARRAY( READ_CONTENT, -1, hTransform, TRANSFORM_X, 2, temp )
  CALL( WriteLog16, 'org  pos x: ', PositionX )
  CALL( WriteLog16, 'read pos x: ', temp )
}

subcall Transform_GetPosition
{
  IN_16     hGameObject
  OUT_16    PositionX
  OUT_16    PositionY

  HANDLE  hTransform
  CALL( GameObject_GetComponent, hGameObject, COMPONENT_TRANSFORM, hTransform )
  ARRAY( READ_CONTENT, -1, hTransform, TRANSFORM_X, 2, PositionX )
  ARRAY( READ_CONTENT, -1, hTransform, TRANSFORM_Y, 2, PositionY )
}

And you can use the game object code like this:

  HANDLE hSprite
  CALL( Sprite_Create, 'spritetest.spr', hSprite )

  HANDLE hHero
  CALL( GameObject_Create, hSprite, hHero )
  CALL( Transform_SetPosition, hHero, 32760, 32761 )

(And here is the code to load and render sprites. The new and improved version)

/**************************************************************************************************
*
*   Graphics functions
*
**************************************************************************************************/
subcall Sprite_Create
{
  IN_S    FileName     128
  OUT_16  SpriteHandle

  HANDLE hFile
  DATA32 FileSize32

  FILE( OPEN_READ, FileName, hFile, FileSize32 )
  ARRAY( CREATE8, FileSize32, SpriteHandle )
  CALL( File_ReadToArray, hFile, SpriteHandle, FileSize32 )
  FILE( CLOSE, hFile )
}

subcall Sprite_Draw
{
  IN_16   SpriteDataHandle
  IN_16   ScreenX
  IN_16   ScreenY

  DATA8   SpriteWidth
  DATA8   SpriteHeight
  DATA32  ReadOfs
  DATA16  WriteX
  DATA16  WriteY
  DATA16  MaxX
  DATA16  MaxY
  DATA8   ReadPixel
  DATA8   WritePixel

  // Read sprite dimensions
  ARRAY( READ_CONTENT, -1, SpriteDataHandle, 0, 1, SpriteWidth )
  ARRAY( READ_CONTENT, -1, SpriteDataHandle, 1, 1, SpriteHeight )

  // Setup
  MOVE8_16( SpriteWidth, MaxX )
  ADD16( MaxX, ScreenX, MaxX )

  MOVE8_16( SpriteHeight, MaxY )
  ADD16( MaxY, ScreenY, MaxY )

  // The whole thing
  MOVE32_32( 2, ReadOfs )
  MOVE16_16( ScreenY, WriteY )

Loop_Y:
  MOVE16_16( ScreenX, WriteX )

Loop_X:
  ARRAY( READ_CONTENT, -1, SpriteDataHandle, ReadOfs, 1, ReadPixel )
  JR_EQ8( ReadPixel, 0, DoneDrawing )   // Don't do any drawing at all
  JR_EQ8( ReadPixel, 1, DrawBlack )
  MOVE8_8( BG_COLOR, WritePixel )       // Set WritePixel to White
  JR( Draw )

DrawBlack:
  MOVE8_8( FG_COLOR, WritePixel )       // Set WritePixel to Black

Draw:
  UI_DRAW( PIXEL, WritePixel, WriteX, WriteY )

DoneDrawing:
  ADD32( ReadOfs, 1, ReadOfs )
  ADD16( WriteX, 1, WriteX )
  JR_LT16( WriteX, MaxX, Loop_X )

  ADD16( WriteY, 1, WriteY )
  JR_LT16( WriteY, MaxY, Loop_Y )
}

So the lesson of the day is, when you are reading from and writing to arrays, the index is in bytes, not in elements.

Sprites to the people!

I’ve done quite a lot of programming today, and I’ve got to say the new tool that automatically compile and download to the Brick is awesome! I’ve also made it so it automatically starts the downloaded program, so it is a real time saver!

In any case, besides modifying the tool so it also starts the downloaded app, I’ve also made an image converted that can output sprites with transparency, and I’ve made a function that read the sprite and draws it on screen on the Brick.

Look!sprites

As you can see there’s a character sprite that are drawn in two different places in this example, and it has three colors. Black, white and transparent.

This is the code to load the sprite:

  HANDLE hFile
  DATA32 FileSize32
  DATA8 BombWidth
  DATA8 BombHeight

  HANDLE BombData
  FILE( OPEN_READ, 'spritetest.spr', hFile, FileSize32 )
  FILE( READ_BYTES, hFile, 1, BombWidth )
  FILE( READ_BYTES, hFile, 1, BombHeight )
  SUB32( FileSize32, 2, FileSize32 )
  ARRAY( CREATE8, FileSize32, BombData )
  CALL( File_ReadToArray, hFile, BombData, FileSize32 )
  FILE( CLOSE, hFile )
subcall File_ReadToArray
{
  IN_16   FileHandle
  IN_16   ArrayHandle
  IN_32   BytesToRead

  DATA8   TempData
  DATA32  WriteIndex

  MOVE32_32( 0, WriteIndex )

Loop:
  FILE( READ_BYTES, FileHandle, 1, TempData )
  ARRAY( WRITE_CONTENT, -1, ArrayHandle, WriteIndex, 1, TempData )
  ADD32( WriteIndex, 1, WriteIndex )
  JR_LT32( WriteIndex, BytesToRead, Loop )
}

As you can see I’ve created a helper function that take a file handle and load it into an array. I am planning on making a function that accept a filename and return an array handle to completely wrap it up, but in this case I want to read the width and height of the image before reading the rest into an array.

I was also planning on reading the width and height as 16 bit values so a sprite can be bigger than 127 but then I figured I want to have a function that is something like ReadSprite, and it would return a single handle for me to use, and ten I could use that handle with a function like DrawSprite, and the handle would hold both width, height and pixel data.

If I try to do that I would create two arrays. One array would be with three 16 bit numbers, and the first number would be width, second number would be height, and third number would be a handle to an 8 bit array that holds the pixel data. Kinda like a little object. :)

Anyways, here is the code that draws the sprite:

subcall DrawSprite
{
  IN_8    SpriteWidth
  IN_8    SpriteHeight
  IN_16   SpriteDataHandle
  IN_16   ScreenX
  IN_16   ScreenY

  DATA32  ReadOfs
  DATA16  WriteX
  DATA16  WriteY
  DATA16  MaxX
  DATA16  MaxY
  DATA8   ReadPixel
  DATA8   WritePixel

  // Setup
  MOVE8_16( SpriteWidth, MaxX )
  ADD16( MaxX, ScreenX, MaxX )

  MOVE8_16( SpriteHeight, MaxY )
  ADD16( MaxY, ScreenY, MaxY )

  // The whole thing
  MOVE32_32( 0, ReadOfs )
  MOVE16_16( ScreenY, WriteY )

Loop_Y:
  MOVE16_16( ScreenX, WriteX )

Loop_X:
  ARRAY( READ_CONTENT, -1, SpriteDataHandle, ReadOfs, 1, ReadPixel )
  JR_EQ8( ReadPixel, 0, DoneDrawing )   // Don't do any drawing at all
  JR_EQ8( ReadPixel, 1, DrawBlack )
  MOVE8_8( BG_COLOR, WritePixel )       // Set WritePixel to White
  JR( Draw )

DrawBlack:
  MOVE8_8( FG_COLOR, WritePixel )       // Set WritePixel to Black

Draw:
  UI_DRAW( PIXEL, WritePixel, WriteX, WriteY )

DoneDrawing:
  ADD32( ReadOfs, 1, ReadOfs )
  ADD16( WriteX, 1, WriteX )
  JR_LT16( WriteX, MaxX, Loop_X )

  ADD16( WriteY, 1, WriteY )
  JR_LT16( WriteY, MaxY, Loop_Y )
}

Back on track

The idea for this blog was to write about using the LMS programming language on the EV3 Brick and to have a test project to go along with it but the last couple of updates have been about building the DC adapter. It is finally done so I can resume the LMS experimenting. Wohoo!

So I know how to draw RGF files to screen, but RGF files doesn’t allow any transparency. So I’m going to create my own image format that allow transparency. The format will be very simple and adapted for using with the LMS2012 VM.

The first 16 bytes will hold the width of the image, the next 16 bits the height, and every byte from there on will represent a pixel in the image. That’ll be easy enough to parse and draw on the VM.

Even though the EV3 is a 300MHz ARM based Linux computer I am worried about performances, especially since each draw pixel is writing to a bit mask, so I will be looking into the UI STORE command that will store a copy of the screen into a buffer for later use. My plan is to draw up the background for a room, but with only the static elements, and store that into a buffer.

I was considering adding animation to the background too. The VM support up to 3 stored buffers, so it will need to be 3 frames of animation tops. Bit of an odd number to use for animations, but we’ll see. If the Brick is fast enough maybe I don’t have to store each background frame.

Anyways, off to write a sprite converter.

Toodles!

That workflow

So I’ve been mainly using the LabVIEW Mindstorms tool to transfer my compiled apps from my computer to the Brick, but a while ago I found the MonoBrick C# library. It looked and worked great. I could use it to browse the files on my device over Bluetooth, but because it required Bluetooth I didn’t feel comfortable having the Brick running for extended periods of time while I was trying to wrap my head around Xamarin and MonoBrick.

But now that I’ve fixed the DC adapter I don’t mind having that beautiful Brick of mine running all day long, so today I’ve actually fixed a tool that greatly improves my workflow.

It looks like this!filesync2

 

There are two important parts to this tool.

1. It starts compilation of LMS files to RBF files, or conversion of an image to an RGF file
2. It download the compiled RBF or converted RGF to the Brick using MonoBrick

So before I had to first go to my shell and start java to compile, and then to go the Mindstorms tool to transfer the file, and there where a lot of switching apps, typing and click. Now there is only one app switch and one click, and my program will compile the program and download the compiled app, if the compilation was successful, onto the Brick.

So iterating on things have gone from super cumbersome to super smooth!

I intend to add another important part to the tool, and that is to automatically download and display the log from the Brick, but that’s for later.

If anyone is interested I’d be more than happy to send this program to you. It is written in C# for OSX, so I assume it would be quite tricky to port to Windows, but if anyone is interested then by all means, contact me and we can sort something out!

The final adapter

I had grand plans for my DC adapter. I was going to make a carving out of wood onto which I would attach metal plates that would connect with the Brick where the batteries should really connect, and then I could simply insert and remove the wooden carving and the metal plates would slip into place.

But that didn’t happen.

Instead I ended up going with a refined version of my initial prototype, two paper clips that I soldered into two wires. So that’s what I’ve been doing today. For a bit my desk looked like this:
bild 1-2

 

After some rude words and frustration I ended up with a Brick that look like this from the backside!bild-9

And from the front it looks like this.bild 2-2

 

So now I’ve solved my battery problem for a while and I don’t have to worry about having Bluetooth or Wifi drain my batteries. Yay!

I have absolutely no idea if this is good for the Brick in the long run though, but the battery indicator is showing something that looks about right, and it is still running after a few hours, so I’m assuming it is ok.