[Suggestion]Future of PokittoLib - v2.0

I’m half and half about the 2 suffix.
A clean break would be good, but at the same time I’m not a big fan of how close it is to ‘Arduboy2’.

Possibly just in separate repos?
Normally extensions have to be downloaded separately with other libraries (e.g. SDL2 doesn’t include SDL_image or SDL_TTF).


I like the idea of splitting the simulator from the main lib because it solves some of the other issues that have cropped up (e.g. clashes from things that try to precomiple all .cpp files).

The only issue is that it might be hard to keep them in sync in terms of the API and versioning.


While I think of it, regarding screen modes, maybe we ought to turn to templates or namespaces as a solution to that issue.

Templates aren’t compiled unless they’re instantiated and they’re actually language-level instead of preprocessor level.

could this alow to have mutliple modes at once? (high res cinematic, low res game)
or could that give us problems?

To add to this, I think for future versions of the loader we should put our games in their own folder. This way when the time comes where we can have game icons shown in the loader, it will make things easier. Plus most of my games I’ve messed with I already try to store the files in their own folder rather than cluttering the root any more than needed.

1 Like

The problem with multiple modes is that each mode expects a differenly sized screen buffer and expects to be the only mode that’s active.

Theoretically there’s nothing stopping using multiple screen modes other than coordinating the software, but in practice there’s a limit because there’s a memory limit.

Basically screen modes would have to be written under the impression that they weren’t the only mode in use and each mode would need to be separately accessible from the public API somehow.

That’s a good idea depending on how long paths can be.

If we did go down that route it would be good to be able to limit games to only accessing their own folder, so there’s no chance of messing with another game’s data.

Though that does have its downsides, e.g. you can’t add easter egss for people who played the previous game.
(Unless we grouped people’s games by the name of the person who made them?)


One more thing while I think of it.

I know people will accuse me of being a bit of a pedant, but if we revamp the AI, could we strive to be const correct?

Sometimes it doesn’t matter, but somtimes it does, and it certainly helps to reduce compiler warnings.

1 Like

If you had many different modes in use at once, all different gfx functions would have to be included in the binary (4-bit, 8-bit etc).

The original reason for opting against this was to prevent memory bloat.

Of course it can be done, thats not the issue.

That’s what I mean by a ‘memory limit’.
Trying to use all screen modes at once would chew up a large chunk of memory and not leave much left for the actual game.

Either way, @adekto you have your answer.


When I said about templates for screen modes, I was thinking of something like:

// ScreenMode.h

// Could be uint8_t if we'll never have more than 255 modes
enum class ScreenModeType : uint16_t
{
  LowRes, HiRes, Mode13, Mode14, Mode15,
};

template< ScreenModeType > class ScreenMode;

// ScreenModes/LowRes.h
template<>
class ScreenMode<ScreenModeType::LowRes>
{
  constexpr const static unsigned BufferWidth = 110;
  constexpr const static unsigned BufferHeight = 88;
  // Implementation
};

// Display.h
template< ScreenModeType mode >
class Display
{
  constexpr const static ScreenModeType ModeType = mode;
  using Mode = ScreenMode<ModeType>; // selects the correct mode
};

// User's MySettings.h
struct MySettings
{
  constexpr const static ScreenModeType ModeType = /* user's chosen mode */;
};

// Pokitto.h
template< typename settings >
class PokittoType
{
  using Settings = settings;
  using DisplayType = Display<Settings::ModeType>;
};

#include "MySettings.h"
using Pokitto = PokittoType<MySettings>;

(Or does everyone think that seems a bit too complicated?)

The advantages of this over defines are:

  • Better compiler warnings/errors
  • If you mess up a setting name (like happened recently with Mode13) it’s a compiler error, not a silent error
  • Still esentially no overhead
  • Each mode is its own class/type
  • The only existing code that needs to be edited to add a new mode is the enum class and the file including the mode files
  • Easier to add a new mode because of the previous two points

The disadvantages are:

  • Potentially confusing
  • Templates can’t separate their definitions from their declarations
1 Like

im in favor for templates even though there complex
an idea it to abstract the modes more
the buffer could be reused for ech mode used (just have to set it to the largest screen mode)

theres also no conversion in formats right now apart from fonts i guess
2bpp sprites cant be drawn to 4bpp buffers, wich could be more memory efficient for say multicoloured fonts

The ‘one class per mode’ thing certainly helps with using more than one mode at once, but it wouldn’t be possible with the system I outlined there.
That would take something more complicated.

That’s doable (if a bit psychadelic.)

It would look a bit like this:

template< typename T, T ... Values > struct Max;

template< typename T >
struct Max<T, a, b>
{
  constexpr const static T value = (a < b) ? b : a;
};

template< typename T, T ... Values, T a, T b >
struct Max : Max<T, Values ..., (a < b) ? b : a> {};

But for modes.

(Spoiler: learn Haskell, it really helps with understanding templates.)

i mean iv done it with custom buffers (wich where basicly composite sprites for directbitmap)

and with that i could even have composite screens with sections being highres (for example text) and parts bieng lowres

I meant the calculating part.
To make it truly generic (so you can use any number of screenmodes) requires template code like the code I posted above.
Actually reusing a buffer is easy as long as you keep track of the details. Just bear in mind how much memory you’re using.


Anyway, “how to achieve multiple screenmodes” is a bit off topic until it’s decided if that should be a job for the library or for an extension.
This thread is about deciding what’s best for the library.

yes my bad, though this brings up a point on how much the library has to do under the hood
currently the update loop is drawing the screen but we could give the user control over when to draw and in what mode

to go back on topic if we started work on pokittolib2 we could break compatibility completely and fix and streamline allot of things

Another suggestion for if we go ahead with PokittoLib V2.
Perhaps move the Arduino stuff into a separate part of the library that has to be manually included.

A number of the Arduino facilities clash with the C++ stdlib facilities because they’ve been designed for an environment that doesn’t have the stdlib. Notably min, max and abs.

It makes sense that the Arduino facilities should be something you have to add on top of the regular library for porting Arduino projects rather than something native Pokitto projects should have to choose to disable manually.

Essentially an Arduino port could do:

#include <Pokitto.h>
#include <Arduino.h>

Or something similar.

And you’d no longer have to do:

#define DISABLEAVRMIN
#include <Pokitto.h>

For regular Pokitto projects.

Doing this would also allow some of the more lightweight stdlib facilities like the type_traits and utility headers to be used in the library itself to simplify some of the code used.

4 Likes

Agreed. I am going to start this evolution soon.

3 Likes

I don’t know if this has been discussed or hasn’t been done because it’s a lot of work, but it would make things easier for people using the lib for the first time if the template settings file had all the options in it, commented. Changing settings would be done by uncommenting a line.
Something like:

// uncomment to hide the startup logo
// #define PROJ_STARTUPLOGO 0

// uncomment to disable sound
// #define PROJ_ENABLE_SOUND 0

...etc...

3 Likes

One of the recent questions reminded me of another issue.

Instead of having the Pokitto try to seed the random number generator with srand, it would be better to provide functions that can be used to generate an almost random initial seed that users can then feed into a random number engine of their choosing.
E.g. Pokitto::generateRandomSeed<uint32_t>()

That way they can pick any of the engines from C++'s random header or the bog-standard rand from C.
(Dependency inversion in action!)

The source could be the RTC, an unconnected pin or something else.

It feels like we need to do a hole redesign on the system, not allot of code would remain it be good to figure out all the optimizations and plan this out before actually implentation no?

About rng do we need multiple? Idk what the advantage is from doing or own one over c or standard library one?
Bieng compliant with standard makes it easier for people to use the language on other platforms, but idk

We have code that works that we can use as a base for the new code rather than starting from scratch.

The changes should be focused more on the API, which bits work, which bits don’t work and which bits people find confusing or not as useful.

Though I agree we should spend time planning it before implementing it. Making sure we consider different eventualities will help to prevent needing future changes.

There are several advantages.

Firstly by only providing a seed we give people the freedom to choose the PRNG that they want to use.
This means people who don’t need high quality randomness can choose a fast, simple PRNG and people who do need high quality randomness can choose a slower, stronger PRNG system.

Sticking with C’s srand like we currently are locks users into a particular implementation which may be wholly unsuitable for their need.

Furthermore, by only providing the seed and not the PRNG, we don’t have to make any promises about the quality of the random numbers.
We only have to verify the quality of the seed we provide, after that the onus is on the end user to chose a PRNG that suits their needs.

We don’t have to ‘be compliant’ with the standard.

We would be giving the library users the freedom to chose any PRNG they want, not just the ones from the C++ library, but any that merely require a seed of a certain size.

This is a case of less is more:
less work for library developers, more freedom for the end users.

sure i get that but would having multiple rng just make people more confused i think
idk it has to be very clear wich is for what but i have no idea how to approach that since i dont even know what the difference really gives or wich to pick

anyway how to we correctly and clearly manige this planning?

Not necessarily, we can just pick one that acts as a middle ground and say “if in doubt, use this”.

The difference between the types of PRNG are their data ranges, the cheapness of implementations and the quality of the randomness they produce.

A linear congruential generator gives pretty poor quality random numbers, but LCGs usually suffice for basic games and they’re really cheap.

A mersenne twister gives really good quality random numbers, but they require a lot of memory in exchange for that quality.

rand has no guarantees as to its quality. It could be something better than a mersenne twister, it could be something worse than an LCG. Technically it could probably just return 4; every time.

The code could look something like this:

const int seed = Pokitto::getRandomSeed<int>();
srand(seed);

Or this:

using SeedType = typename std::knuth_b::result_type;
const SeedType seed = Pokitto::getRandomSeed<SeedType>();
std::knuth_b engine = std::knuth_b(seed);

Or if we went a step further:

std::knuth_b engine = Pokitto::createRandomlySeededEngine<std::knuth_b>();

Where createRandomlySeededEngine is implemented as something like:

template< typename EngineType >
EngineType createRandomlySeededEngine(void)
{  
  using SeedType = typename EngineType::result_type;
  return EngineType(getRandomSeed<SeedType>());
}

I think for now the best thing to do is just pool ideas and make a wishlist of features.

What about using STL’s random generation facilities?