[Tool]FemtoIDE

Size information, as in, the size of the map? Is that of any use without the map itself?

I do not have studied the details of the map generation from tmx-file, but just thought if having at least some javascript file as a default (created during importing a tmx file) would be a good idea.

Fixed this bug in tilemap.js:

    int read${layer.name.replace(/[^a-zA-Z0-9_]/g, '')}(int tileX, int tileY){
        pointer addr = this.data + ${4+num*(1+map.width*2*map.height)} + tileY*${map.width*2} + tileX*2;
        return (((int)LDRB(addr)&1)<<8) + LDRB(addr+1);
    }

There was
this.data + ${3
instead of
this.data + ${4

1 Like

Femto v0.1.0: Compiler errors are much better now :+1:

2 Likes

This doesn’t sound right… does that work on more than one layer?

Edit: I don’t have anything to test this with right now, but it should probably be this instead:
pointer addr = this.data + ${3+(num*(1+map.width*2*map.height)||1)} + tileY*${map.width*2} + tileX*2;

(note the ||1)

1 Like

The next version of FemtoIDE will bring initial support for PokittoCookies in Java.

For now, cookies can store any primitive type (char, int, long, float, boolean) but nothing that extends Object (classes including String and Array).

For those who are on the bleeding edge, here’s an example of it in use:

import femto.mode.Direct;
import femto.Game;
import femto.State;
import femto.input.Button;
import femto.palette.Psygnosia;
import femto.font.TIC80;

class Score extends femto.Cookie {
    Score(){
        super();
        begin("test"); // name of the cookie, up to 8 chars
    }
    int score; // properties you want to save
}

class Main extends State {
    static final var save = new Score(); // previous value is automatically restored
    static final var screen = new Direct(TIC80.font()); // the screenmode we want to draw with

    public static void main(String[] args){
        Game.run( TIC80.font(), new Main() );
    }
    
    void init(){
        screen.clear(0);
    }

    void update(){
        if( Button.A.justPressed() ){
            save.score = Math.random(0, 1000); // update the score
            save.saveCookie(); // save it to eeprom
        }

        screen.setTextPosition( 0, 0 );
        screen.textColor++;
        screen.println("Score: "+save.score); // print the current score
    }
    
}
4 Likes

Any way to change the default path of the projects folder? I use more than one computer to dev (one being a VPC) but would like to point them both to the same shared path on my nas/dropbox and when I tried making a shortcut path, the IDE didn’t pick it up.

1 Like

Look for projectsPath in your config.js and change the value to the path you want.

2 Likes

PSA - until further notice, do not use new to initialize non-static properties. Like this:

class Fridge {
  float temperature = 15.0f;
  Bacon bacon = new Bacon(); // BAD!
}

Do this instead:

class Fridge {
  float temperature = 15.0f; // OK!
  Bacon bacon;
  Fridge(){ bacon = new Bacon(); } // OK!
}
Details...

Basically, when you initialize a property, it creates a constructor like this:

Fridge::Fridge() : bacon(new Bacon()) { }

The problem happens if the new triggers the garbage collector before bacon is initialized. It’s a dangling pointer at that moment. The GC will see the (possibly non-zero) pointer and try to access it.

Ideally, it would generate this instead:

Fridge::Fridge() : bacon(nullptr) { bacon = new Bacon(); }

Another option would be to zero memory inside new.

1 Like
Rambling...

The former should be equivalent to bacon.ctor(new Bacon()), which should call (the equivalent of) either Bacon*::Bacon*(Bacon * &&) or Bacon*::Bacon*(const Bacon * &).

The latter should be equivalent to bacon.operator=(new Bacon()), which should call (the equivalent of) either Bacon*::operator=(Bacon * &&) or Bacon*::operator=(const Bacon * &).

Either way new Bacon() should have a type of Bacon * &&.

The only thing I can think that would make a difference is that the former is technically direct initialisation (6) and the later is technically copy initialisation (1).
But even then I would have thought it would still be creating a temporary before assigning.

Is it not possible to make the allocator temporarily treat the pointer whose new triggered the GC as having an extra reference until the sweep is finished?

E.g.

void * operator new(std::size_t size)
{
	void * pointer = allocate(size);
	if(needSweep())
	{
		addRef(pointer);
		sweep();
		removeRef(pointer);
	}
	return pointer;
}

That said, does:

// Java land
class Fridge
{
	Bacon bacon = new Bacon();
}

Actually translate to this?

// C++ land
class Fridge
{
	__ref__<Bacon> bacon = new Bacon();
};

It translates to this, simplified:

class Fridge
{
	Bacon *bacon = new Bacon();
};

__ref__ is only used for static variables. Properties and local variables use actual pointers.

The problem isn’t in the form of initialization (copy vs assign) but the fact that the Fridge class has an invalid pointer (bacon) during a sweep.

1 Like

Oh I see, I got confused between bacon and new Bacon().

Presumably that means:

// Java land
class Fridge
{
	Bacon bacon;
	Fridge() { bacon = new Bacon(); }
}

Translates to:

// C++ land
class Fridge
{
	Bacon bacon = nullptr;
	Fridge() { bacon = new Bacon(); }
};

(I’m presuming that because I think Java would require that bacon were null before the body of Fridge() begins, but it’s been quite some time since I’ve used Java for any extended period.)

In which case I think the only thing you can do is to change how the default assignment of a member variable in Java is translated to C++ (which would mean more work for the parser/translator).

Unless there’s some way you could ‘hide’ the mid-construction Fridge object from the system during initialisation, and then 'reveal it once it’s fully constructed, but that also sounds like a lot of work, and is possibly the more awkard option.

1 Like

Correct.

Yep, that was the first option I mentioned (initialize with null then put the actual initialization expression in the beginning of all constructors).

I’ll try the other option first, since it has potential to take up less flash space:

void *operator new(size_t size)  {
    auto c = (int*) __wrap_malloc(size);
    auto i = c;
    while(size-=4) *i++ = 0;
    return c;
}
1 Like

My performance instincts are cringing,
but I suppose technically Java would actually be doing something similar to this anyway.
(At least I presume so, I never read Java’s rules that in depth.)

Mine did some cringing too, but this is probably better performance-wise than setting each object’s properties to zero individually. Even if it weren’t, the cost of simply using new (making malloc go through a linked list looking for free RAM) is probably going to be much higher anyway, so it shouldn’t be a problem.

1 Like

Would anybody mind if Java had overclocking always enabled, like in MicroPython?

I kind of like having it as an optional thing.

2 Likes

I’ll be honest, I don’t feel comfortable with it being the default, to be honest. Please make it optional, as @torbuntu said

It’s totally irrational, and I can’t explain it well. I guess I just want my Pokitto to operate at its nominal speed for some reason :stuck_out_tongue: (I never overclocked my PC or felt the need to for the same unknown reason I guess).

Also, I’d like to know the effects on the battery as well, if that could be possible to measure. I think overclocking is OK (turbo mode!) when you really need temporary power (like for generating our stuff, or simulating heavy things), but if that’s for doing some kind of while(!hasFrameEndedYet()); 99% of the time, it’s just kind of silly in my opinion

4 Likes

The issue I have with it being optional is that enabling it is a bit of a hassle:
In Java, you have to put
"--defsym=_OSCT=2" inside SFlags -> Pokitto and "-D_OSCT=2", inside CPPFlags -> Pokitto.
This feels at odds with how simple and easy everything else is.
Ideally we’d just call Game.goFaster() or something, but that complicates things internally.

As for wanting the Pokitto to run at its nominal speed… there isn’t one, really. While the data sheet describes it as a “32-bit MCU family operating at CPU frequencies of up to 50 MHz.”, that number is more of a TL;DR. There are various parts in the chip that can have different speeds and limitations. The SPI bus, for example, can’t go above 25mhz.
It is also possible to underclock the CPU.

On a PC, overclocking means you risk damaging something by overheating.
On the Pokitto it just means that it isn’t running at the same speed used by the default mbed startup code. It’s 100% safe and well tested: GB and MicroPython games have been running at 72mhz for a while now.

About battery life… the reason we haven’t looked into sleep modes for decreasing power consumption is the elephant in the room: the screen consumes far more power than the CPU.
If someone wants to make a Tamagotchi that’s always on, the #1 priority would be implementing some way to turn the screen on/off.

In summary, while overclocking only to get stuck in a while(...); loop might seem silly, it has no negative consequences or waste. Since the majority of games benefit from higher framerates, it’d make sense that overclocking be on by default and we’d use a flag for underclocking in exceptional situations.

4 Likes

During the python compo, when the OSCT=2 was introduced, I noticed that the game I was working on, had some artifacts due to the overclock. The game have high contrast sprite and the some sparkling pixels were visible on Hardware display with full moving scenes.
Not sure if later, the problem was fixed by reducing SPI frequency or simply I get used to.