128 битное число как?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ЕвгенийП пишет:

Этих конверторов как говна за баней. Когда мне понадобился - один запрос к гуглу всё решил. Там выбирать затрахаешься. Я, правда, не выбирал - взял из первого результата поиска Image2Lcd, он закрыл мою потребность а больше мне от него ничего не нужно. Можете попробовать.

(выделено мною)

Вот-вот. Поэтому я предпочитаю писать сам, чем сначала искать в Гугле, потом выбирать, а потом еще и проверять... IMHO быстрее выходит.

lilik
Offline
Зарегистрирован: 19.10.2017

ЕвгенийП пишет:

lilik пишет:

конвертер картинок в массивы к библиотекам не помешал бы). Авторам написал, но вряд ли ответят.

Этих конверторов как говна за баней. Когда мне понадобился - один запрос к гуглу всё решил. Там выбирать затрахаешься. Я, правда, не выбирал - взял из первого результата поиска Image2Lcd, он закрыл мою потребность а больше мне от него ничего не нужно. Можете попробовать.

Эту как раз мимо пропустил. Перепробовал несколько, вроде нашёл даже под данный тип экрана, но код генерит - одни 11111. Пользуюсь вот этим :

https://www.dcode.fr/binary-image

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:
MHO быстрее выходит.
Да, ладно Вам. Я скачал первый, что попался. Запустил. Он мне картинку в массив перегнал, только запятую в конце лишнюю поставил. Меня вполне устроило.

b707
Offline
Зарегистрирован: 26.05.2017

lilik пишет:

Да, соглашусь пожалуй, но конвертер картинок в массивы к библиотекам не помешал бы). Авторам написал, но вряд ли ответят.

так напишите сами...

А то не понятно, о чем тема, нытье одно - это не подходит, то не устраивает...

lilik
Offline
Зарегистрирован: 19.10.2017

Я не напишу. Что ЕвгенийП предложил работает, но пока краказябры-фарш (способа сканирования не подберу) из рисунка на экране. А тема о том, что к хорошо разжёванным библиотекам под экраны чуток добавить конкретных конвертеров. Такие варианты есть, но к другим библиотекам (нытьё в чистом виде-факт!).

lilik
Offline
Зарегистрирован: 19.10.2017

После забавных попыток-краказябров я таки попал настройками (а их много) в правильное сканирование картинки под экранчик. Но вот фокус - на экранчике картинка в инверсных цветах. То есть либо автор конвертера, либо библиотеки что-то напутал (себя я исключаю :)) 

Что означает Antitone pixel in byte (переводчик ясности не внёс)?

b707
Offline
Зарегистрирован: 26.05.2017

Галочку "Reverse color" попробуйте

sadman41
Offline
Зарегистрирован: 19.10.2016

"Anti tone", видимо "инверсия".

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Там же есть галка "Reverse color". Это разве не инверсия цвета?

lilik
Offline
Зарегистрирован: 19.10.2017

sadman41 пишет:

"Anti tone", видимо "инверсия".

Нет, если её снять картинка ломается, а цвет остаётся (судя по просматриваемым обрывкам фарша на экране)

 

lilik
Offline
Зарегистрирован: 19.10.2017

andriano пишет:

Там же есть галка "Reverse color". Это разве не инверсия цвета?

Да, с галочкой цвет меняется - в конвертере на чёрный фон (рисунок справа), а на экране на белый.

lilik
Offline
Зарегистрирован: 19.10.2017

sadman41 пишет:

"Anti tone", видимо "инверсия".

Да, видимо порядок укладки бит в байт при сканировании (от 0b или к 0b).

32 варианта сканирования в конвертере по расположению "обрывков" картинки в массиве - это дань творчеству авторов библиотек или производителей экранов-дисплейчиков?

А всё таки в языке, применительно для Ардуино, нет возможности работать с битовыми строками-полями, минуя понятие байт? Вроде bit massiv []={011001100110010111010...} (но именно бит, а не байт) по типу:

bool massiv []={0,1,1,0,0,0,1...}

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

lilik пишет:

А всё таки в языке, применительно для Ардуино, нет возможности работать с битовыми строками-полями, минуя понятие байт? Вроде bit massiv []={011001100110010111010...} (но именно бит, а не байт) по типу:

Почему нет? Есть. И описание с примерами есть на этом форуме.

Я одного не пойму - НАЮХА?

lilik
Offline
Зарегистрирован: 19.10.2017

Так нагляднее и проще писателю : понятный один способ сканирования-воспроизведения на экран, визуализация картинки в массиве. Ведь замена 0х00, на 00000000 раздувает массив не очень. Другой вопрос - скорость прорисовки на экране и одноцветность рисунка. 

sadman41
Offline
Зарегистрирован: 19.10.2016

По мне так вполне себе даже колхозный способ решает проблему примерной визуализации в массиве:

0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,
0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b00000111,0b11111111,
0b11111111,0b11111111,0b11111111,0b11111111,0b11111110,0b00000000,0b00000011,0b11111111,
0b11111111,0b11111111,0b11111111,0b11111111,0b11000000,0b00011111,0b11111011,0b11111111,
0b11111111,0b11111111,0b11111111,0b11111100,0b00000111,0b11111111,0b11111001,0b11111111,
0b11111111,0b11111111,0b11111111,0b11111000,0b11111111,0b11111111,0b11111100,0b11111111,
0b11111111,0b11111111,0b11111111,0b11111001,0b11111111,0b11111111,0b11111100,0b11111111,
0b11111111,0b11111111,0b11111111,0b11111001,0b11111111,0b11111111,0b11111110,0b01111111,
0b11111111,0b11111111,0b11111111,0b11111000,0b11111111,0b11100011,0b11111110,0b01111111,
0b11111111,0b11111111,0b11111101,0b11110010,0b11111111,0b11000001,0b11111111,0b00111111,
0b11111111,0b11111111,0b11100000,0b01110010,0b11111111,0b10000001,0b11111111,0b00111111,
0b11111111,0b11111111,0b10000111,0b00011011,0b11111111,0b10000001,0b11111111,0b10011111,
0b11111111,0b11111110,0b00011111,0b10001111,0b11111111,0b11100111,0b11111111,0b10011111,
0b11111111,0b11111000,0b11111111,0b11100011,0b11111111,0b11111111,0b11111111,0b11001111,
0b11111111,0b11100011,0b11111111,0b11110001,0b11111111,0b11111111,0b11111111,0b11001111,
0b11111111,0b10000111,0b11111111,0b11111100,0b11111111,0b11111111,0b11111111,0b11101111,
0b11111110,0b00011111,0b11111111,0b11111110,0b00111111,0b11111111,0b11111111,0b11100111,
0b11111100,0b01111111,0b11111111,0b11111111,0b00011111,0b11111111,0b11111110,0b00000111,
0b11110001,0b11111111,0b11000001,0b11111111,0b10001111,0b11111111,0b11000000,0b00000111,
0b11100011,0b11111111,0b11000000,0b11111111,0b11000111,0b11111000,0b00000011,0b11100111,
0b11100001,0b11111111,0b11000000,0b11111111,0b11110011,0b11111111,0b11111111,0b11100111,
0b11100000,0b11111111,0b11100001,0b11111111,0b11100011,0b11111111,0b11111111,0b11101111,
0b11100100,0b01111111,0b11111111,0b11111111,0b11000001,0b11011111,0b11100000,0b11101111,
0b11100110,0b00111111,0b11111111,0b11111111,0b00001001,0b00000111,0b11100000,0b11001111,
0b11100111,0b10011111,0b11111111,0b11111110,0b00111001,0b00000111,0b11110001,0b11001111,
0b11100111,0b11001111,0b11111111,0b11111000,0b11111001,0b10000111,0b11111111,0b11001111,
0b11100111,0b11100111,0b11111111,0b11110011,0b11111001,0b11111111,0b11111111,0b11001111,
0b11100110,0b01111011,0b11111111,0b11001111,0b10011001,0b11111111,0b11111111,0b11011111,
0b11100100,0b00111101,0b11111111,0b01111111,0b00001001,0b11111111,0b11111111,0b11011111,
0b11100110,0b00111111,0b11111111,0b11111111,0b00011001,0b11111111,0b11110011,0b10011111,
0b11110110,0b00111111,0b11111111,0b11111111,0b00111001,0b10001111,0b11000001,0b10011111,
0b11110111,0b11111111,0b11111111,0b11111111,0b11111001,0b00000111,0b11000001,0b10111111,
0b11110111,0b11111111,0b11111111,0b11111111,0b11111001,0b00000111,0b11100011,0b00111111,
0b11110111,0b11111111,0b11111111,0b11111101,0b11111001,0b10001111,0b11111110,0b00111111,
0b11110011,0b11111111,0b11111111,0b11111001,0b11111001,0b11111111,0b11000000,0b01111111,
0b11110011,0b11111111,0b11111111,0b11110001,0b11111001,0b00000000,0b00000111,0b11111111,
0b11110011,0b11111111,0b11111111,0b11110001,0b11111010,0b00000000,0b11111111,0b11111111,
0b11110011,0b11111111,0b11001111,0b11111011,0b11111011,0b11111111,0b11111111,0b11111111,
0b11111001,0b11111011,0b11001111,0b11111111,0b11110011,0b11111111,0b11111111,0b11111111,
0b11111100,0b11110001,0b11001111,0b11111111,0b11110011,0b11111111,0b11111111,0b11111111,
0b11111110,0b01110000,0b11001111,0b10011111,0b11100111,0b11111111,0b11111111,0b11111111,
0b11111111,0b00110000,0b11001111,0b00011111,0b10001111,0b11111111,0b11111111,0b11111111,
0b11111111,0b10011001,0b11001111,0b00011111,0b00011111,0b11111111,0b11111111,0b11111111,
0b11111111,0b11000111,0b11001111,0b00111100,0b01111111,0b11111111,0b11111111,0b11111111,
0b11111111,0b11100011,0b11001111,0b11111000,0b11111111,0b11111111,0b11111111,0b11111111,
0b11111111,0b11110001,0b11000111,0b11100011,0b11111111,0b11111111,0b11111111,0b11111111,
0b11111111,0b11111100,0b11000111,0b10000111,0b11111111,0b11111111,0b11111111,0b11111111,
0b11111111,0b11111110,0b01000100,0b00011111,0b11111111,0b11111111,0b11111111,0b11111111,
0b11111111,0b11111111,0b11100100,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,
0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111

 

nik182
Offline
Зарегистрирован: 04.05.2015

Простой вопрос. Зачем визаулизировать массив в программе? Есть же конвертор, который показывает картинку. Если уж очень хочется видить, сохраните картинку рядом с программой. И смотрите когда надо. Всё равно в скомпилированной прошивке картинка будет перекорёжена и её не возможно будет идентифицировать. А видеть картинку в программе это блажь. Она уходит с экрана, как только переходишь к тексту программы. Какая разница - всё равно крутить экран. А хекс вместо бин существенно сократит длину программного кода.

lilik
Offline
Зарегистрирован: 19.10.2017

Ну, вроде разобрался - библиотек для текста и вывода картинок много, конвертеров тоже, в МК можно записать больше десятка изображений (хранить в соседнем ino - визуализация лишнее). Даже фотка давняя моя - узнаваема :)

Интересно, а как с 3д графикой для Ардуино? Искал готовые, разжёванные библиотеки - их нет. Наткнулся на интересный вариант:

https://drububu.com/miscellaneous/tiny_devices/index.html

Каким инструментом можно быстро нарисовать каркасную 3Д модель?  Сам пользуюсь только "Опенскадом", мне хватает для печати и моделирования.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

lilik пишет:

Интересно, а как с 3д графикой для Ардуино? Искал готовые, разжёванные библиотеки - их нет. Наткнулся на интересный вариант:

https://drububu.com/miscellaneous/tiny_devices/index.html

Каким инструментом можно быстро нарисовать каркасную 3Д модель?  Сам пользуюсь только "Опенскадом", мне хватает для печати и моделирования.

 

3D-графика, Ардуино и быстро - вещи несовместимые.

 

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

andriano пишет:

3D-графика, Ардуино и быстро - вещи несовместимые.

ESP/STM по идее "каркасную" псевдо-3D должны потянуть. Помню, "каркасные" Т-72 и прочие БРДМ очень бодро на 286-й машине шпыняли Абрамса)) Да и Elite на Z80... 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

"Помню" - это хорошо. А помните, были ли в этих 286 еще и 287?

lilik
Offline
Зарегистрирован: 19.10.2017

Разобрался. Рисуем модель как обычно. Авторский конвертер сам превратит её в каркасную и выдаст скетч.

Хочу чуть модернизировать вариант автора- добавить управление приближением-удалением к модели, осями вращения и его направлением, добавить массивов моделей - несколько вместо одной. Хватит ресурса УНО? Сейчас 42 процента памяти и 81 динамической использует. Есть ли конвертеры отдельные для преобразования obj или stl в массивы, используемые автором? Прилично у него спросить, почему не сделал библиотеку (товарищ из-за рубежа)? 

Забавно: stl файлы тоже берёт конвертер его, но ругается и вместо скетча выдаёт тхт с его текстом.



/****************************************************************************
 //
 // sketch displaying an animated wire frame representation of a 
 // 3d model on a mini oled screen ( SSDI1306 ) via i2c.
 // hidden surface removal is used; non-visible polgons are not displayed.
 // code is made for arduino nano - 2kb(!) ram & 30kb sram - just for curiousity
 // purpose; is it possible to display 3d graphics and if so how fast 
 // will it run.
 // 
 // 2018 / version 0.02
 // arjan westerdiep / www.drububu.com 
 //
 // generate an arduino sketch with your own 3D model at drububu.com
 //
 //****************************************************************************

 #include <Wire.h>
// #include <avr/pgmspace.h>

 //****************************************************************************
 // slave address
 // find your device at http://playground.arduino.cc/Main/I2cScanner
 //****************************************************************************

 #define   SLAVE                   0x3C

 //****************************************************************************
 // 
 //****************************************************************************

 #define   OBJECT_SIZE             140   

 #define   ROTATE_X_AXIS           0
 #define   ROTATE_Y_AXIS           1
 #define   ROTATE_Z_AXIS           1
 #define   SHOW_FRAMES_PER_SECOND  true
 #define   PROFILING               false

 //****************************************************************************
 // set to true if backside of object is displayed instead of front.
 //****************************************************************************

 #define  FLIP_NORMAL              true 

 //****************************************************************************
 // 
 //****************************************************************************

 #define WIDTH                     128
 #define HEIGHT                    64
 #define ROWS                      8
 #define OFFSET_HORIZONTAL         64
 #define OFFSET_VERTICAL           32

 //****************************************************************************
 // 
 //****************************************************************************

 #if OBJECT_SIZE >= ( WIDTH - 2 ) || OBJECT_SIZE >= ( HEIGHT - 2 ) 
  #define isMeshInsideScreen       false
 #else 
  #define isMeshInsideScreen       true
 #endif

 //****************************************************************************
 // 
 //****************************************************************************


 #if ROTATE_X_AXIS 
  byte _frameXAxis = 0;
 #endif

 #if ROTATE_Y_AXIS 
  byte _frameYAxis = 0;
 #endif

 #if ROTATE_Z_AXIS 
  byte _frameZAxis = 0;
 #endif

 //****************************************************************************
 // 
 //****************************************************************************

 byte          _bitmapData[ WIDTH * ( HEIGHT >> 3 ) ];
 byte          _lookupMinimumcolumn[ ROWS ];
 byte          _lookupMaximumcolumn[ ROWS ];
 byte          _minimumRow = 0;
 byte          _maximumRow = ROWS - 1;
 word          _lookupOledRefresh[ ROWS ];

 #if PROFILING
  unsigned long _timePreprocessing = 0;
  unsigned long _timeScanConvert   = 0;
  unsigned long _timeRendering     = 0;
 #endif
 
 //****************************************************************************
 // frames per second code
 //****************************************************************************

 #if SHOW_FRAMES_PER_SECOND

  #define       FPS_ROW_POSITION 7

  word          _totalOfFrameRates = 0.0;
  byte          _numberOfFrames = 0;
  unsigned long _time = millis();

  //***************************************************************************
  // 
  //***************************************************************************

  const static byte _lookupFps[ 65 ] PROGMEM = {
   14, 17, 17, 14,  0, // 0
    0, 17, 31, 16,  0, // 1
   29, 21, 21, 23,  0, // 2  
   21, 21, 21, 31,  0, // 3  
   12, 10,  9, 31,  0, // 4  
   23, 21, 21, 29,  0, // 5  
   31, 21, 21, 29,  0, // 6
    1, 25,  5,  3,  0, // 7
   31, 21, 21, 31,  0, // 8
   23, 21, 21, 31,  0, // 9
   31,  5,  5,  5,  0, // F
   31,  5,  5,  7,  0, // P
   23, 21, 21, 29,  0  // S
  };

 #endif
 //*******************************************************************************
 // sine & cosine data 
 //*******************************************************************************

 const static word _lookupSineCosine[ 256 ] PROGMEM = {
  0x7FFE, 0x82FD, 0x85FD, 0x88FD, 0x8BFD, 0x8EFD, 0x91FC, 0x94FC, 0x97FB, 0x9AFA, 
  0x9DFA, 0xA0F9, 0xA3F8, 0xA6F7, 0xA9F6, 0xACF5, 0xAFF4, 0xB2F3, 0xB5F1, 0xB8F0, 
  0xBAEF, 0xBDED, 0xC0EB, 0xC2EA, 0xC5E8, 0xC8E6, 0xCAE5, 0xCDE3, 0xCFE1, 0xD1DF, 
  0xD4DD, 0xD6DA, 0xD8D8, 0xDAD6, 0xDDD4, 0xDFD1, 0xE1CF, 0xE3CD, 0xE5CA, 0xE6C8, 
  0xE8C5, 0xEAC2, 0xEBC0, 0xEDBD, 0xEFBA, 0xF0B8, 0xF1B5, 0xF3B2, 0xF4AF, 0xF5AC, 
  0xF6A9, 0xF7A6, 0xF8A3, 0xF9A0, 0xFA9D, 0xFA9A, 0xFB97, 0xFC94, 0xFC91, 0xFD8E, 
  0xFD8B, 0xFD88, 0xFD85, 0xFD82, 0xFD7F, 0xFD7B, 0xFD78, 0xFD75, 0xFD72, 0xFD6F, 
  0xFC6C, 0xFC69, 0xFB66, 0xFA63, 0xFA60, 0xF95D, 0xF85A, 0xF757, 0xF654, 0xF551, 
  0xF44E, 0xF34B, 0xF148, 0xF045, 0xEF43, 0xED40, 0xEB3D, 0xEA3B, 0xE838, 0xE635, 
  0xE533, 0xE330, 0xE12E, 0xDF2C, 0xDD29, 0xDA27, 0xD825, 0xD623, 0xD420, 0xD11E, 
  0xCF1C, 0xCD1A, 0xCA18, 0xC817, 0xC515, 0xC213, 0xC012, 0xBD10, 0xBA0E, 0xB80D, 
  0xB50C, 0xB20A, 0xAF09, 0xAC08, 0xA907, 0xA606, 0xA305, 0xA004, 0x9D03, 0x9A03, 
  0x9702, 0x9401, 0x9101, 0x8E00, 0x8B00, 0x8800, 0x8500, 0x8200, 0x7F00, 0x7B00, 
  0x7800, 0x7500, 0x7200, 0x6F00, 0x6C01, 0x6901, 0x6602, 0x6303, 0x6003, 0x5D04, 
  0x5A05, 0x5706, 0x5407, 0x5108, 0x4E09, 0x4B0A, 0x480C, 0x450D, 0x430E, 0x4010, 
  0x3D12, 0x3B13, 0x3815, 0x3517, 0x3318, 0x301A, 0x2E1C, 0x2C1E, 0x2920, 0x2723, 
  0x2525, 0x2327, 0x2029, 0x1E2C, 0x1C2E, 0x1A30, 0x1833, 0x1735, 0x1538, 0x133B, 
  0x123D, 0x1040, 0x0E43, 0x0D45, 0x0C48, 0x0A4B, 0x094E, 0x0851, 0x0754, 0x0657, 
  0x055A, 0x045D, 0x0360, 0x0363, 0x0266, 0x0169, 0x016C, 0x006F, 0x0072, 0x0075, 
  0x0078, 0x007B, 0x007E, 0x0082, 0x0085, 0x0088, 0x008B, 0x008E, 0x0191, 0x0194, 
  0x0297, 0x039A, 0x039D, 0x04A0, 0x05A3, 0x06A6, 0x07A9, 0x08AC, 0x09AF, 0x0AB2, 
  0x0CB5, 0x0DB8, 0x0EBA, 0x10BD, 0x12C0, 0x13C2, 0x15C5, 0x17C8, 0x18CA, 0x1ACD, 
  0x1CCF, 0x1ED1, 0x20D4, 0x23D6, 0x25D8, 0x27DA, 0x29DD, 0x2CDF, 0x2EE1, 0x30E3, 
  0x33E5, 0x35E6, 0x38E8, 0x3BEA, 0x3DEB, 0x40ED, 0x43EF, 0x45F0, 0x48F1, 0x4BF3, 
  0x4EF4, 0x51F5, 0x54F6, 0x57F7, 0x5AF8, 0x5DF9, 0x60FA, 0x63FA, 0x66FB, 0x69FC, 
  0x6CFC, 0x6FFD, 0x72FD, 0x75FD, 0x78FD, 0x7BFD 
 };

 //****************************************************************************
 //
 //****************************************************************************

 #define  NUMBER_OF_VERTEX_INDICES           1516
 #define  NUMBER_OF_POLYGON_INDICES          1420

 //****************************************************************************
 // lookup entries unique segments ( = bitfield ( word ( 2 bytes ) ) ) 
 // maximum 199 unique segments per chunck
 //****************************************************************************

 #define  LOOKUP_ENTRIES_UNIQUE_SEGMENTS  13

 //****************************************************************************
 // lookup entries transformed vertices ( = bitfield ( word ( 2 bytes ) ) ) 
 // maximum 197 unique vertices per chunck
 //****************************************************************************

 #define  LOOKUP_ENTRIES_TRANSFORMED_VERTICES  13

 word     _lookupTransformedVerticesBitfield[ LOOKUP_ENTRIES_TRANSFORMED_VERTICES ];
 char     _lookupTransformedVertices[ 394 ];

 //****************************************************************************
 // lookup vertex ( & normal ) data
 //****************************************************************************

 const static word _lookupVertices[ 1516 ] PROGMEM = {
  0x00B2, 0x788E, 0x00FC, 0x6E3F, 0x00C9, 0x7049, 0x00C8, 0x6B48, 0x00C8, 0x7F7F, 
  0x0000, 0x84DE, 0x002F, 0x8FD1, 0x002F, 0x89CF, 0x002F, 0x88E0, 0x002F, 0x91D3, 
  0x002F, 0x82E1, 0x002F, 0x82DF, 0x002F, 0x6F5D, 0x002F, 0x705A, 0x002F, 0x6C5A, 
  0x002F, 0x714F, 0x002F, 0x6352, 0x002F, 0x644E, 0x002F, 0x6C4B, 0x002F, 0x644A, 
  0x002F, 0x74DF, 0x002F, 0x72CE, 0x002F, 0x6CD3, 0x002F, 0x79DE, 0x002F, 0x76CD, 
  0x002F, 0x79E2, 0x002F, 0x8A4E, 0x002F, 0x974D, 0x002F, 0x944B, 0x002F, 0x9158, 
  0x002F, 0x984F, 0x002F, 0x955D, 0x002F, 0x965A, 0x002F, 0x8D4A, 0x002F, 0x4E09, 
  0x007B, 0x6857, 0x0036, 0x7052, 0x0062, 0x6756, 0x0068, 0x017F, 0x008F, 0x85D3, 
  0x0046, 0x87CE, 0x0059, 0x86E0, 0x0053, 0xB40C, 0x0084, 0x7158, 0x0034, 0x7259, 
  0x004D, 0x6C56, 0x0039, 0xFA9D, 0x007B, 0x6F60, 0x003A, 0x028D, 0x0093, 0x85BC, 
  0x0057, 0x35E5, 0x008C, 0x6DD8, 0x004B, 0x78E0, 0x0052, 0x6EDC, 0x0036, 0xCCE1, 
  0x0091, 0x91D8, 0x004C, 0x90DE, 0x0035, 0x470E, 0x0069, 0x79D3, 0x0045, 0x5B12, 
  0x0048, 0x89D9, 0x0037, 0xBC13, 0x0063, 0xB10B, 0x008D, 0x6A51, 0x0074, 0x7555, 
  0x0067, 0x7957, 0x006B, 0xF889, 0x005C, 0x765D, 0x0060, 0x7668, 0x0063, 0x7760, 
  0x0067, 0xFA87, 0x0062, 0x7160, 0x004D, 0x4410, 0x0066, 0x1ECE, 0x0068, 0x6E65, 
  0x0050, 0x3B1C, 0x00AB, 0x6743, 0x00BA, 0x633F, 0x00AB, 0x703C, 0x00B7, 0x3F1D, 
  0x00B2, 0x0474, 0x009F, 0x664B, 0x00BA, 0x684B, 0x00C1, 0x7A01, 0x006E, 0x7F1C, 
  0x00C1, 0x811B, 0x00C6, 0x7A1C, 0x00C3, 0x8601, 0x006A, 0x861D, 0x00BE, 0x2BDE, 
  0x008A, 0x694D, 0x00BD, 0x87EF, 0x00B9, 0x6F4B, 0x00C0, 0x86F3, 0x00B1, 0x61F4, 
  0x00A5, 0x2CD8, 0x00A3, 0x714B, 0x00C5, 0x7702, 0x0066, 0x781D, 0x00BE, 0x7A03, 
  0x0061, 0x7B1F, 0x00B7, 0x8C6F, 0x0001, 0x7AC5, 0x0088, 0x7ACA, 0x0087, 0x86C6, 
  0x0089, 0x5834, 0x001F, 0x7DD3, 0x0080, 0x84D1, 0x007F, 0x6A25, 0x0027, 0x8605, 
  0x00A4, 0x904B, 0x0032, 0xFD87, 0x0072, 0xE83A, 0x006F, 0x9803, 0x006F, 0x8A56, 
  0x0035, 0x9257, 0x003A, 0x8E50, 0x0065, 0x18BB, 0x0053, 0x645F, 0x006D, 0x6469, 
  0x007E, 0x6C65, 0x0064, 0x54F1, 0x005C, 0x739E, 0x0004, 0x82D4, 0x0080, 0x43DA, 
  0x00BF, 0x83CE, 0x008A, 0x5FD6, 0x00D5, 0x11BB, 0x0067, 0x7FBC, 0x0071, 0x86C3, 
  0x0062, 0x0CAB, 0x005E, 0x87C9, 0x0067, 0xEAC1, 0x0070, 0x9063, 0x003A, 0x9465, 
  0x0062, 0x9659, 0x0037, 0x018F, 0x0084, 0x3845, 0x00D7, 0x28B6, 0x0033, 0xEE43, 
  0x0072, 0xD320, 0x0072, 0x8847, 0x007D, 0x9856, 0x0071, 0x8A46, 0x0093, 0x9E76, 
  0x0004, 0x8970, 0x0067, 0x815D, 0x0066, 0x81B6, 0x000D, 0x7574, 0x0069, 0x2D2C, 
  0x004B, 0xF592, 0x00A7, 0x9463, 0x0098, 0x9A57, 0x008C, 0x9A79, 0x007B, 0x767D, 
  0x00FD, 0x859A, 0x0099, 0x73A7, 0x0098, 0x717D, 0x0098, 0x6E83, 0x00FC, 0x8678, 
  0x009B, 0x7CB7, 0x00F0, 0x725D, 0x00A8, 0x8762, 0x00A5, 0x2295, 0x00D3, 0x6E95, 
  0x008E, 0x6863, 0x0095, 0xD1AC, 0x00D4, 0x0675, 0x0058, 0x6DA3, 0x008D, 0x76A5, 
  0x0071, 0xDA96, 0x00D4, 0x9096, 0x008E, 0xF68F, 0x00A5, 0xEFB5, 0x0068, 0x8A98, 
  0x0075, 0x0EB2, 0x0061, 0x7494, 0x0074, 0x687C, 0x0079, 0x00BF, 0x8997, 0x00FB, 
  0x8EB1, 0x0094, 0x73A7, 0x0098, 0x859A, 0x0099, 0x3BD7, 0x00BC, 0x7AC5, 0x0088, 
  0x70C4, 0x007F, 0x7BBE, 0x0093, 0x0BA9, 0x009F, 0x6FB5, 0x0091, 0x6AB6, 0x007A, 
  0x0392, 0x0095, 0x7ACA, 0x0087, 0xF5AC, 0x0081, 0x86C6, 0x0089, 0x83CE, 0x008A, 
  0xF6A7, 0x0090, 0x84D1, 0x007F, 0x82D4, 0x0080, 0xF5A9, 0x0090, 0x7DF6, 0x0053, 
  0x81C3, 0x0080, 0x33E5, 0x0086, 0x87C9, 0x0067, 0xA7F6, 0x008A, 0x8DC4, 0x007F, 
  0x4CEE, 0x00A0, 0x8ECE, 0x0061, 0x59F5, 0x0096, 0x74C9, 0x006B, 0x2AC1, 0x003B, 
  0x8A56, 0x0035, 0x9063, 0x003A, 0x9158, 0x002F, 0x955D, 0x002F, 0x22BC, 0x0040, 
  0x6EDC, 0x0036, 0x74DF, 0x002F, 0x6CD3, 0x002F, 0xFD8A, 0x0080, 0x78E0, 0x0052, 
  0x7BBE, 0x0056, 0x79D3, 0x0045, 0xFD89, 0x0082, 0x7AD9, 0x0036, 0x79DE, 0x002F, 
  0x79E2, 0x002F, 0xF1B4, 0x0074, 0x9465, 0x0062, 0x985E, 0x006C, 0x9659, 0x0037, 
  0x63FA, 0x0070, 0x9169, 0x0069, 0x8A66, 0x0064, 0x035F, 0x007A, 0x645F, 0x006D, 
  0x6857, 0x0036, 0x6756, 0x0068, 0x18C7, 0x006D, 0x6E65, 0x0050, 0x6702, 0x0076, 
  0x7052, 0x0062, 0x6C56, 0x0039, 0x84FB, 0x0067, 0x7668, 0x0063, 0x6F60, 0x003A, 
  0xF960, 0x0071, 0x7160, 0x004D, 0xF5A7, 0x006C, 0x7158, 0x0034, 0x705A, 0x002F, 
  0x6F5D, 0x002F, 0x10B9, 0x006A, 0x016A, 0x0086, 0x8E50, 0x0065, 0xE331, 0x0080, 
  0xC515, 0x0075, 0x9257, 0x003A, 0xD5CC, 0x00B2, 0x91D8, 0x004C, 0x86E0, 0x0053, 
  0x94D1, 0x00DD, 0x0077, 0x007A, 0x87CE, 0x0059, 0x2CCB, 0x00B9, 0x6DD8, 0x004B, 
  0x72D1, 0x005C, 0xDB93, 0x00D3, 0xFD86, 0x0083, 0x660B, 0x0050, 0x0081, 0x008D, 
  0x85D3, 0x0046, 0x82DF, 0x002F, 0x56F7, 0x007B, 0x6C65, 0x0064, 0xE7C6, 0x0085, 
  0x90A8, 0x0008, 0x8970, 0x0067, 0x8094, 0x0072, 0x8A98, 0x0075, 0xF973, 0x005E, 
  0x90A4, 0x0087, 0x9096, 0x008E, 0xF1A9, 0x00A3, 0x95B4, 0x007A, 0x0489, 0x009E, 
  0x6DA3, 0x008D, 0xF88B, 0x00A2, 0x90A3, 0x0093, 0x0F81, 0x00BC, 0x107D, 0x00BD, 
  0x6E95, 0x008E, 0xCD61, 0x00DE, 0xFD84, 0x0082, 0xF654, 0x007D, 0xCF22, 0x005C, 
  0x93AF, 0x0073, 0x89A8, 0x006D, 0x5D21, 0x002F, 0x83A8, 0x0070, 0x85BC, 0x0057, 
  0x9A22, 0x002C, 0x76A5, 0x0071, 0x70B8, 0x005A, 0xAA66, 0x000A, 0x7067, 0x0003, 
  0x7AA1, 0x0071, 0x7494, 0x0074, 0x5544, 0x0015, 0x786D, 0x0001, 0x6E68, 0x0003, 
  0xB730, 0x002C, 0x94C3, 0x005B, 0x82E1, 0x002F, 0x4135, 0x002B, 0x282E, 0x0051, 
  0x6AAF, 0x0076, 0x4E9B, 0x000C, 0x815D, 0x0066, 0x6E77, 0x0001, 0xDC42, 0x0041, 
  0x765D, 0x0060, 0x7957, 0x006B, 0x7F7E, 0x007E, 0x7555, 0x0067, 0x9FF9, 0x0081, 
  0x90DE, 0x0035, 0x88E0, 0x002F, 0x46F0, 0x0084, 0x0DB7, 0x0077, 0x085D, 0x0062, 
  0x7431, 0x00B8, 0x772D, 0x00B3, 0x781D, 0x00BE, 0x83A0, 0x00F9, 0x803A, 0x00CE, 
  0x914B, 0x00C9, 0x7E4C, 0x00C9, 0xF981, 0x00A1, 0x9A3E, 0x00AA, 0x9551, 0x00BA, 
  0x9343, 0x00C2, 0x1A4A, 0x0045, 0x7B1F, 0x00B7, 0xF39E, 0x0058, 0x8B4F, 0x00BB, 
  0x8E4D, 0x00C2, 0x8F49, 0x00C2, 0x8D06, 0x005A, 0x8420, 0x00B7, 0x7F1C, 0x00C1, 
  0xA1F7, 0x0092, 0x884E, 0x00C5, 0xEC67, 0x00BB, 0x811B, 0x00C6, 0x861D, 0x00BE, 
  0x852A, 0x00C5, 0x8D4E, 0x00F3, 0x8B35, 0x00C8, 0x7C30, 0x00C8, 0xD85B, 0x00D1, 
  0x8C36, 0x00C2, 0xF962, 0x0071, 0x8B38, 0x00B3, 0xF686, 0x00A8, 0xEA3C, 0x0075, 
  0x8A42, 0x00AF, 0x8A46, 0x0093, 0x9252, 0x009A, 0xFA75, 0x009B, 0x9463, 0x0098, 
  0x00C5, 0xF760, 0x0098, 0x8B4F, 0x00BB, 0x8A42, 0x00AF, 0x9252, 0x009A, 0x69EB, 
  0x00BD, 0x7E4C, 0x00C9, 0x8762, 0x00A5, 0x725D, 0x00A8, 0x89E9, 0x00C3, 0x884E, 
  0x00C5, 0x87EA, 0x00C1, 0x914B, 0x00C9, 0x669D, 0x00F7, 0x6E3F, 0x00C9, 0x803A, 
  0x00CE, 0x7E2E, 0x001C, 0x7957, 0x006B, 0x815D, 0x0066, 0x7F4D, 0x0073, 0x8E1A, 
  0x0033, 0x8847, 0x007D, 0x7B44, 0x007F, 0x3617, 0x0071, 0x6A51, 0x0074, 0x7346, 
  0x009B, 0xD11F, 0x006D, 0x8E50, 0x0065, 0x9856, 0x0071, 0x5C26, 0x002A, 0x8576, 
  0x00FD, 0x744A, 0x00C9, 0x7755, 0x0007, 0x7B1F, 0x00B7, 0x772D, 0x00B3, 0x8539, 
  0x00AD, 0x0867, 0x0058, 0x7248, 0x00AF, 0x7431, 0x00B8, 0x0C47, 0x0080, 0x7939, 
  0x00AC, 0x9704, 0x0067, 0x8043, 0x0088, 0x8646, 0x000D, 0x3EE0, 0x00B1, 0x714B, 
  0x00C5, 0x7049, 0x00C8, 0xD5DA, 0x0071, 0x664B, 0x00BA, 0x6F43, 0x00C0, 0x6D43, 
  0x00AF, 0x78E1, 0x002F, 0x633F, 0x00AB, 0x8010, 0x003F, 0x7F3C, 0x00A7, 0xF99C, 
  0x006D, 0x703C, 0x00B7, 0x7E53, 0x0007, 0x8420, 0x00B7, 0xCE59, 0x0022, 0x8B38, 
  0x00B3, 0xAC6A, 0x00F3, 0x8B35, 0x00C8, 0x8F3E, 0x00C8, 0xF85B, 0x0070, 0x8C36, 
  0x00C2, 0xF24A, 0x008A, 0x007C, 0x0087, 0x8F49, 0x00C2, 0x8E3C, 0x00B7, 0x1735, 
  0x0082, 0x6B51, 0x0097, 0x007F, 0x0085, 0xE534, 0x0083, 0x9343, 0x00C2, 0xD499, 
  0x0024, 0x694D, 0x00BD, 0x046B, 0x0064, 0xBD33, 0x002E, 0x076E, 0x00A6, 0x6B48, 
  0x00C8, 0x684B, 0x00C1, 0x6743, 0x00BA, 0x0FBB, 0x007F, 0x0290, 0x006E, 0x9044, 
  0x00AF, 0x3245, 0x002B, 0x9A3E, 0x00AA, 0xBF19, 0x00A7, 0xEE72, 0x00BB, 0xA977, 
  0x00F6, 0x0A4D, 0x007E, 0x70ED, 0x00BB, 0xF290, 0x004D, 0xFD84, 0x0071, 0xE6BD, 
  0x00A4, 0x923F, 0x00EA, 0x7C30, 0x00C8, 0xBCD6, 0x00C3, 0x9463, 0x0098, 0xAC7E, 
  0x00F5, 0x811B, 0x00C6, 0x852A, 0x00C5, 0xED40, 0x0086, 0x81D1, 0x001E, 0x9551, 
  0x00BA, 0x14BD, 0x0064, 0x2966, 0x0024, 0xFD77, 0x008C, 0x5509, 0x0064, 0xE941, 
  0x005F, 0xAE32, 0x0025, 0x6702, 0x007F, 0xB27C, 0x000A, 0x6F4B, 0x00C0, 0xAE0A, 
  0x006D, 0x8A46, 0x0093, 0x096D, 0x00AA, 0x781D, 0x00BE, 0x7A1C, 0x00C3, 0x7730, 
  0x00C3, 0x056F, 0x009F, 0x6FA8, 0x0007, 0x7574, 0x0069, 0x7494, 0x0074, 0x8094, 
  0x0072, 0x6643, 0x0011, 0x7668, 0x0063, 0x7F7E, 0x007E, 0x7760, 0x0067, 0x6C24, 
  0x0027, 0x3022, 0x0058, 0xA606, 0x0075, 0xDAC0, 0x00B9, 0x8EB1, 0x0094, 0x8DC4, 
  0x007F, 0x86C6, 0x0089, 0xCBB9, 0x002B, 0x90DE, 0x0035, 0x91D3, 0x002F, 0x88E0, 
  0x002F, 0xBC13, 0x0063, 0x91D8, 0x004C, 0x85D3, 0x0046, 0x8E30, 0x001C, 0x79D3, 
  0x0045, 0x7BBE, 0x0056, 0x70B8, 0x005A, 0xFA69, 0x006B, 0x7FBC, 0x0071, 0x7AA1, 
  0x0071, 0x0FBA, 0x0072, 0x81C3, 0x0080, 0x87C9, 0x0067, 0xBF44, 0x0022, 0x94C3, 
  0x005B, 0xB43A, 0x0022, 0x85BC, 0x0057, 0xF986, 0x005C, 0x7158, 0x0034, 0x714F, 
  0x002F, 0x705A, 0x002F, 0xCDE1, 0x0071, 0x9465, 0x0062, 0x9063, 0x003A, 0x9169, 
  0x0069, 0xAFF4, 0x0083, 0x7AC5, 0x0088, 0x74C9, 0x006B, 0x2827, 0x005E, 0x6DA3, 
  0x008D, 0x6AAF, 0x0076, 0x76A5, 0x0071, 0x38D6, 0x00BA, 0x72D1, 0x005C, 0x6DD8, 
  0x004B, 0x6AB6, 0x007A, 0x32D4, 0x00B6, 0x0863, 0x005B, 0x0081, 0x0077, 0x3C4D, 
  0x001E, 0xF2B1, 0x008C, 0xD0DE, 0x0069, 0x0076, 0x008C, 0x31CC, 0x00BE, 0x6FB5, 
  0x0091, 0x7BBE, 0x0093, 0x70C4, 0x007F, 0x0B84, 0x00B2, 0x73A7, 0x0098, 0x6E95, 
  0x008E, 0x717D, 0x0098, 0x43CD, 0x00CF, 0x83CE, 0x008A, 0x7ACA, 0x0087, 0x45A7, 
  0x00E8, 0x9DB0, 0x00EF, 0x8A94, 0x00FB, 0x00BE, 0x7DB7, 0x00F0, 0x725D, 0x00A8, 
  0x8678, 0x009B, 0x717D, 0x0098, 0x4B66, 0x00F0, 0x7A1C, 0x00C3, 0x811B, 0x00C6, 
  0x7C30, 0x00C8, 0x0361, 0x007A, 0x7431, 0x00B8, 0x7235, 0x00C8, 0x6F43, 0x00C0, 
  0xA085, 0x00F9, 0x9463, 0x0098, 0x859A, 0x0099, 0xBF7D, 0x00EC, 0x90A3, 0x0093, 
  0x8EB1, 0x0094, 0x1ECE, 0x006A, 0x6857, 0x0036, 0x6F60, 0x003A, 0x6C5A, 0x002F, 
  0x6F5D, 0x002F, 0x2EE0, 0x007C, 0x6352, 0x002F, 0x008E, 0x0082, 0x87C9, 0x0067, 
  0x87CE, 0x0059, 0x86C3, 0x0062, 0xFD8D, 0x007F, 0x91D8, 0x004C, 0x95B4, 0x007A, 
  0x94C3, 0x005B, 0xDCC6, 0x00AF, 0x8ECE, 0x0061, 0xF964, 0x006B, 0x93AF, 0x0073, 
  0xD234, 0x0042, 0x89A8, 0x006D, 0xF552, 0x007B, 0x90A4, 0x0087, 0x0E5A, 0x00AC, 
  0x89D9, 0x0037, 0x84DE, 0x002F, 0x89CF, 0x002F, 0xFC8E, 0x0088, 0x9659, 0x0037, 
  0x984F, 0x002F, 0x965A, 0x002F, 0x2C64, 0x00DB, 0x694D, 0x0033, 0x644E, 0x002F, 
  0xD754, 0x00CF, 0x9257, 0x003A, 0x974D, 0x002F, 0x3762, 0x00E3, 0x6C56, 0x0039, 
  0xEEBA, 0x008C, 0x9063, 0x003A, 0x955D, 0x002F, 0xBB3C, 0x00D8, 0x904B, 0x0032, 
  0x944B, 0x002F, 0x29DC, 0x0077, 0x6E65, 0x0050, 0x645F, 0x006D, 0x6C65, 0x0064, 
  0x1735, 0x0082, 0x7346, 0x009B, 0x6B51, 0x0097, 0x6A51, 0x0074, 0x0755, 0x008D, 
  0x6756, 0x0068, 0x045E, 0x0083, 0x6469, 0x007E, 0x159B, 0x00BF, 0x6863, 0x0095, 
  0x026C, 0x0092, 0x0D71, 0x00B5, 0x604F, 0x00F0, 0x803A, 0x00CE, 0x5761, 0x00F4, 
  0x6E3F, 0x00C9, 0x0C53, 0x005E, 0xDF2F, 0x0096, 0x9252, 0x009A, 0x8A46, 0x0093, 
  0x9A57, 0x008C, 0xDA27, 0x0078, 0x9856, 0x0071, 0xEE7C, 0x00BA, 0xFD73, 0x0081, 
  0x985E, 0x006C, 0x9A79, 0x007B, 0xE54E, 0x0045, 0x8E50, 0x0065, 0x2F7B, 0x00E1, 
  0x644A, 0x002F, 0xBEA3, 0x0017, 0x9169, 0x0069, 0x8A66, 0x0064, 0x8970, 0x0067, 
  0xC9B3, 0x0026, 0xFD78, 0x0072, 0xD59C, 0x0026, 0x8A98, 0x0075, 0xF878, 0x005B, 
  0x0758, 0x0093, 0x1583, 0x0038, 0x7668, 0x0063, 0x687C, 0x0079, 0x0387, 0x0061, 
  0x7494, 0x0074, 0x6E95, 0x008E, 0x76A5, 0x0071, 0x269B, 0x0028, 0x7574, 0x0069, 
  0x0299, 0x0082, 0x0490, 0x009B, 0xEBB0, 0x0052, 0x6F4B, 0x00C0, 0x714B, 0x00C5, 
  0x744A, 0x00C9, 0xF27F, 0x004A, 0xFB77, 0x0067, 0x8F49, 0x00C2, 0x8F3E, 0x00C8, 
  0x8B38, 0x00B3, 0x7A07, 0x0052, 0x8420, 0x00B7, 0x861D, 0x00BE, 0x7F1C, 0x00C1, 
  0x1F72, 0x00D1, 0x7730, 0x00C3, 0x2922, 0x008C, 0x6685, 0x0002, 0x7FBC, 0x0071, 
  0x83A8, 0x0070, 0x7AA1, 0x0071, 0xF2AF, 0x0092, 0x8DC4, 0x007F, 0x0468, 0x0064, 
  0x85BC, 0x0057, 0xFC85, 0x006D, 0x7BBE, 0x0056, 0x81C3, 0x0080, 0xF968, 0x0068, 
  0x7AD9, 0x0036, 0x76CD, 0x002F, 0x79DE, 0x002F, 0xD538, 0x00BB, 0x7158, 0x0034, 
  0xC046, 0x00DB, 0x6C4B, 0x002F, 0x714F, 0x002F, 0x29A2, 0x0027, 0x7DA4, 0x0005, 
  0x8094, 0x0072, 0x4249, 0x00E0, 0x8A56, 0x0035, 0x8913, 0x00C1, 0xB349, 0x00E5, 
  0x90DE, 0x0035, 0x91D3, 0x002F, 0x8FD1, 0x002F, 0x6E36, 0x00E5, 0x6EDC, 0x0036, 
  0x6CD3, 0x002F, 0x9B38, 0x00E5, 0x5A56, 0x00F1, 0x72CE, 0x002F, 0x7247, 0x00F0, 
  0xD7A5, 0x002C, 0xA809, 0x0065, 0x7F3C, 0x00A7, 0x7939, 0x00AC, 0x8043, 0x0088, 
  0x4418, 0x00AD, 0xEE57, 0x0051, 0xCE5A, 0x0022, 0x8539, 0x00AD, 0x20D3, 0x0084, 
  0x9551, 0x00BA, 0x914B, 0x00C9, 0xF39E, 0x0058, 0x8E4D, 0x00C2, 0x068B, 0x00A5, 
  0x7248, 0x00AF, 0x4197, 0x00EB, 0x7049, 0x00C8 
 };

 //****************************************************************************
 // polygon data
 //****************************************************************************

 const static word _lookupPolygons[ 1420 ] PROGMEM = {
  0xC759, 0x0003, 0x0101, 0x0202, 0x0303, 0x0403, 0x0405, 0x0506, 0x0607, 0x0403, 
  0x0705, 0x0808, 0x0406, 0x0403, 0x0806, 0x0908, 0x0A09, 0x0403, 0x0B05, 0x0C0A, 
  0x0708, 0x0403, 0x0D0B, 0x0B0A, 0x0E05, 0x0403, 0x0F0C, 0x100D, 0x110E, 0x0403, 
  0x120E, 0x130F, 0x1410, 0x0403, 0x100E, 0x150D, 0x120F, 0x0403, 0x1611, 0x1712, 
  0x1813, 0x0403, 0x1310, 0x190F, 0x1A11, 0x0403, 0x1911, 0x1B0F, 0x1612, 0x0403, 
  0x1C14, 0x1D15, 0x1E16, 0x0403, 0x1F17, 0x2018, 0x2115, 0x0403, 0x2214, 0x2319, 
  0x2417, 0x0403, 0x2414, 0x2117, 0x1C15, 0x0403, 0x251A, 0x261B, 0x271C, 0x0403, 
  0x281D, 0x291E, 0x2A1B, 0x0403, 0x2B1D, 0x2C1F, 0x2D20, 0x0403, 0x2E21, 0x271A, 
  0x2F1C, 0x0403, 0x301A, 0x2A1D, 0x251B, 0x0403, 0x2D1D, 0x3120, 0x281E, 0x2203, 
  0x3223, 0x3324, 0x3425, 0x2603, 0x3527, 0x3628, 0x3729, 0x2A03, 0x382B, 0x392C, 
  0x3A2D, 0x2E03, 0x382C, 0x3B2B, 0x3C2F, 0x3003, 0x3528, 0x3D27, 0x3E31, 0x3203, 
  0x3F33, 0x4034, 0x4135, 0x3603, 0x4237, 0x4338, 0x4429, 0x3903, 0x4133, 0x4535, 
  0x463A, 0x3B03, 0x473C, 0x0E0B, 0x4805, 0x3B03, 0x493C, 0x4A27, 0x470B, 0x3D03, 
  0x4B38, 0x4927, 0x4C3C, 0x3E03, 0x4D3F, 0x4E24, 0x4F40, 0x3E03, 0x5041, 0x4F3F, 
  0x5140, 0x4203, 0x5243, 0x5344, 0x5445, 0x4203, 0x5541, 0x5443, 0x5645, 0x4603, 
  0x572C, 0x5847, 0x5943, 0x4603, 0x5244, 0x5843, 0x5A47, 0x4803, 0x5B3F, 0x3325, 
  0x4D24, 0x4903, 0x5C4A, 0x5D2F, 0x5E23, 0x4B03, 0x5F4C, 0x604D, 0x614E, 0x4F03, 
  0x6203, 0x614C, 0x634E, 0x5003, 0x644C, 0x6551, 0x5F4D, 0x5003, 0x6652, 0x6451, 
  0x674C, 0x5303, 0x6854, 0x6955, 0x6A56, 0x5703, 0x6855, 0x6B54, 0x6C58, 0x5903, 
  0x6D52, 0x6E5A, 0x6651, 0x5B03, 0x6F52, 0x7003, 0x715C, 0x5D03, 0x725C, 0x6D5A, 
  0x7152, 0x5E03, 0x705C, 0x0203, 0x7302, 0x5F03, 0x7402, 0x7560, 0x735C, 0x6103, 
  0x7662, 0x6A54, 0x7756, 0x6303, 0x7654, 0x7862, 0x7964, 0x6503, 0x7A66, 0x7B67, 
  0x7C68, 0x6903, 0x7D67, 0x7E6A, 0x7F6B, 0x6C03, 0x806B, 0x7B68, 0x7F67, 0x6D03, 
  0x816E, 0x2F21, 0x821C, 0x6F03, 0x3C2C, 0x832F, 0x5747, 0x7003, 0x392D, 0x842C, 
  0x8524, 0x7103, 0x8672, 0x8773, 0x8874, 0x7503, 0x8976, 0x8A77, 0x8B78, 0x7903, 
  0x8C77, 0x8D44, 0x8A78, 0x7A03, 0x7E6B, 0x8E6A, 0x8F7B, 0x7C03, 0x9067, 0x917D, 
  0x927B, 0x7E03, 0x8E7B, 0x7D6A, 0x9267, 0x7F03, 0x9331, 0x9480, 0x9581, 0x8203, 
  0x9683, 0x9481, 0x9780, 0x8403, 0x9885, 0x9986, 0x9A87, 0x8803, 0x9B81, 0x3E28, 
  0x9531, 0x8903, 0x9C6E, 0x9D72, 0x9E1A, 0x8903, 0x9E6E, 0x2E1A, 0x8121, 0x8A03, 
  0x9F72, 0x301D, 0x9D1A, 0x8B03, 0x592C, 0xA043, 0x8424, 0x8C03, 0xA18D, 0xA28E, 
  0xA38F, 0x9003, 0xA444, 0xA591, 0xA692, 0x9303, 0xA744, 0xA894, 0xA491, 0x9503, 
  0xA992, 0xAA74, 0xAB8D, 0x9603, 0xAC97, 0xAD98, 0xAE99, 0x9A03, 0xAF9B, 0xB09C, 
  0xB19D, 0x9E03, 0xB29D, 0xB39F, 0xB19B, 0xA003, 0xB49F, 0xB5A1, 0xB6A2, 0xA303, 
  0xB79D, 0xB8A4, 0xB9A5, 0xA603, 0xBAA2, 0xBB97, 0xB69F, 0xA703, 0xBCA8, 0xBDA9, 
  0xBEA4, 0xAA03, 0xBF9B, 0xC097, 0xC1AB, 0xAC03, 0xC299, 0xC0AB, 0xAE97, 0xAD03, 
  0xC399, 0xC4AE, 0xC2AB, 0xAF03, 0xC5B0, 0xC6B1, 0xC7A4, 0xC757, 0x0003, 0x0101, 
  0x0202, 0x0303, 0x0403, 0x0405, 0x0506, 0x0607, 0x0803, 0x0709, 0x0806, 0x090A, 
  0x0B03, 0x0A07, 0x0B0C, 0x0605, 0x0D03, 0x0C01, 0x0D0E, 0x0E0F, 0x1003, 0x0F11, 
  0x1012, 0x110F, 0x1303, 0x0D0F, 0x120E, 0x1111, 0x1403, 0x1315, 0x1405, 0x150E, 
  0x1603, 0x1515, 0x160E, 0x1717, 0x1803, 0x1617, 0x180E, 0x1919, 0x1A03, 0x1A19, 
  0x1B1B, 0x1917, 0x1C03, 0x1C05, 0x1D1D, 0x0406, 0x1E03, 0x1E1F, 0x1F20, 0x2021, 
  0x1E03, 0x2122, 0x1F21, 0x2220, 0x2303, 0x2324, 0x2425, 0x2526, 0x2703, 0x2628, 
  0x2729, 0x282A, 0x2B03, 0x2928, 0x2A2C, 0x2B2D, 0x2B03, 0x2B28, 0x2C2D, 0x2D2E, 
  0x2F03, 0x2E30, 0x2F31, 0x3032, 0x3303, 0x3134, 0x3220, 0x3335, 0x3603, 0x3437, 
  0x3538, 0x3639, 0x3A03, 0x3737, 0x383B, 0x3438, 0x3C03, 0x393D, 0x3A38, 0x3B3E, 
  0x3F03, 0x3C3B, 0x3D40, 0x3E41, 0x4203, 0x3F40, 0x4043, 0x3D41, 0x4403, 0x4141, 
  0x4245, 0x4346, 0x4403, 0x4341, 0x4446, 0x4547, 0x4803, 0x461F, 0x3235, 0x1E20, 
  0x4903, 0x474A, 0x4635, 0x481F, 0x4B03, 0x494A, 0x2F32, 0x4A31, 0x4C03, 0x4932, 
  0x4B4A, 0x4C4D, 0x4E03, 0x4D4F, 0x4E50, 0x4F1B, 0x5103, 0x4E1B, 0x5050, 0x1B17, 
  0x5203, 0x5150, 0x5253, 0x5017, 0x5403, 0x5328, 0x5455, 0x5556, 0x5703, 0x2629, 
  0x5528, 0x5656, 0x5803, 0x2828, 0x572A, 0x292C, 0x5903, 0x5824, 0x572C, 0x592A, 
  0x5A03, 0x5A5B, 0x5B50, 0x5C5C, 0x5D03, 0x5D3B, 0x5E5E, 0x3C40, 0x5F03, 0x2E31, 
  0x5F30, 0x6034, 0x6003, 0x6161, 0x6262, 0x6363, 0x6403, 0x6465, 0x6566, 0x6663, 
  0x6703, 0x6701, 0x6868, 0x6919, 0x6903, 0x6A6A, 0x0909, 0x6B0A, 0x6B03, 0x6C6C, 
  0x6768, 0x6D01, 0x6D03, 0x6E02, 0x6A09, 0x6F6A, 0x6E03, 0x706A, 0x716F, 0x6F02, 
  0x7003, 0x7203, 0x7366, 0x746C, 0x7103, 0x736C, 0x6466, 0x7565, 0x7203, 0x756C, 
  0x7665, 0x6C68, 0x7303, 0x7774, 0x7865, 0x7975, 0x7603, 0x7A75, 0x7B77, 0x7C78, 
  0x7903, 0x7D7A, 0x7E7B, 0x7F29, 0x7C03, 0x8062, 0x8177, 0x6263, 0x7D03, 0x827A, 
  0x837E, 0x847F, 0x8003, 0x8163, 0x7A77, 0x8575, 0x8103, 0x867E, 0x8077, 0x8762, 
  0x8203, 0x8862, 0x837F, 0x877E, 0x8303, 0x7C75, 0x8978, 0x8A84, 0x5A03, 0x8B85, 
  0x5B5C, 0x8C50, 0x8603, 0x8D29, 0x827E, 0x7F7A, 0x8703, 0x8E88, 0x7D7B, 0x8F7A, 
  0x8903, 0x908A, 0x9161, 0x9235, 0x8B03, 0x934A, 0x928A, 0x4735, 0x8C03, 0x943D, 
  0x958D, 0x968E, 0x8F03, 0x978E, 0x9890, 0x963D, 0x9103, 0x9950, 0x9A92, 0x9B93, 
  0x9103, 0x9B50, 0x9C93, 0x8C85, 0x9403, 0x9D24, 0x9E28, 0x2325, 0x9403, 0x9F2E, 
  0x9E25, 0x2D28, 0x9503, 0xA01D, 0x080A, 0x1D06, 0x9603, 0xA197, 0xA298, 0xA399, 
  0x9A03, 0xA49B, 0xA59C, 0xA69D, 0x9E03, 0xA79F, 0xA8A0, 0xA9A1, 0xA203, 0xAAA3, 
  0xA299, 0xAB98, 0xA403, 0xACA5, 0xADA6, 0xAEA7, 0xA803, 0xAFA9, 0xB0AA, 0xB1A3, 
  0xAB03, 0xB2A5, 0xB3AC, 0xB49C, 0xAD03, 0xB5AE, 0xB6AF, 0xB7B0, 0xB103, 0xB8B0, 
  0xB9B2, 0xBAB3, 0x8F03, 0xBB9C, 0xACA6, 0xB4A5, 0xB403, 0xBCB5, 0xB6B0, 0xBDAF, 
  0xB603, 0xBEAF, 0xBFB7, 0xBDB5, 0xB803, 0xA8A1, 0xC0A0, 0xC19C, 0xB903, 0xC2BA, 
  0xC3BB, 0xC4BC, 0xBD03, 0xC5BE, 0xC6A5, 0xC7BC, 0xC75D, 0x0003, 0x0101, 0x0202, 
  0x0303, 0x0403, 0x0405, 0x0506, 0x0607, 0x0803, 0x0406, 0x0705, 0x0809, 0x0A03, 
  0x0709, 0x0905, 0x0A0B, 0x0C03, 0x0B05, 0x0C0D, 0x0D0E, 0x0F03, 0x0E10, 0x0F11, 
  0x1012, 0x1303, 0x1112, 0x1214, 0x1315, 0x1603, 0x1417, 0x1515, 0x1618, 0x1903, 
  0x1714, 0x181A, 0x191B, 0x1C03, 0x1312, 0x1A15, 0x1010, 0x1D03, 0x1B05, 0x1C1E, 
  0x0B0D, 0x1F03, 0x1D20, 0x1E21, 0x1F22, 0x2303, 0x2024, 0x2121, 0x2225, 0x2603, 
  0x2324, 0x2418, 0x2527, 0x2803, 0x2629, 0x1215, 0x2714, 0x2A03, 0x2827, 0x1E22, 
  0x2921, 0x2B03, 0x2A1E, 0x2B2C, 0x2C2D, 0x2E03, 0x2D2F, 0x2E30, 0x2F31, 0x3203, 
  0x3031, 0x3133, 0x2F2F, 0x3403, 0x3235, 0x2822, 0x3327, 0x3603, 0x2E31, 0x3430, 
  0x3537, 0x3803, 0x1F20, 0x3622, 0x3739, 0x3A03, 0x3802, 0x393B, 0x3A22, 0x3C03, 
  0x3B0E, 0x3C3D, 0x3D3E, 0x3F03, 0x3E40, 0x3F3B, 0x403E, 0x4103, 0x3C3E, 0x413D, 
  0x4040, 0x4203, 0x423E, 0x4343, 0x4444, 0x4503, 0x4524, 0x4646, 0x2318, 0x4703, 
  0x471E, 0x4807, 0x4924, 0x4803, 0x4A49, 0x443E, 0x4B44, 0x4A03, 0x4C4B, 0x2D30, 
  0x4D2F, 0x4C03, 0x2224, 0x4E25, 0x4F30, 0x4D03, 0x3531, 0x5037, 0x3033, 0x4E03, 
  0x514F, 0x5250, 0x5351, 0x5203, 0x5430, 0x491E, 0x4F24, 0x5303, 0x5554, 0x4344, 
  0x5643, 0x5503, 0x5544, 0x5754, 0x5856, 0x5703, 0x5956, 0x4B49, 0x5844, 0x5803, 
  0x5A49, 0x5B0B, 0x4A3E, 0x5903, 0x5B3E, 0x5C0B, 0x3D0E, 0x5A03, 0x5D37, 0x5E0D, 
  0x5F4F, 0x5B03, 0x4707, 0x1B1E, 0x0605, 0x5C03, 0x6001, 0x6143, 0x623B, 0x5D03, 
  0x383B, 0x0102, 0x6201, 0x5E03, 0x6309, 0x6401, 0x0806, 0x5F03, 0x650E, 0x6660, 
  0x3B3D, 0x6103, 0x6406, 0x6701, 0x6862, 0x6303, 0x6960, 0x6A64, 0x6B65, 0x6603, 
  0x6C3D, 0x6D65, 0x4140, 0x6703, 0x6E68, 0x5756, 0x6F54, 0x6903, 0x5654, 0x7043, 
  0x6F68, 0x6A03, 0x2021, 0x2524, 0x2927, 0x6B03, 0x3437, 0x7130, 0x5D0D, 0x6C03, 
  0x3222, 0x7235, 0x7329, 0x6D03, 0x7429, 0x3A02, 0x7322, 0x6E03, 0x7511, 0x1114, 
  0x0F12, 0x6F03, 0x2615, 0x7629, 0x1518, 0x7003, 0x4C30, 0x774B, 0x7871, 0x7203, 
  0x7973, 0x7402, 0x7A29, 0x7403, 0x7B75, 0x7C76, 0x7D77, 0x7803, 0x7E77, 0x7F25, 
  0x7D75, 0x7903, 0x807A, 0x817B, 0x827C, 0x7D03, 0x837E, 0x0E11, 0x8410, 0x7F03, 
  0x8510, 0x8680, 0x847E, 0x8103, 0x1A10, 0x1415, 0x8717, 0x8203, 0x8829, 0x2427, 
  0x7618, 0x8303, 0x2729, 0x8914, 0x7A73, 0x8403, 0x8A85, 0x8B86, 0x8C87, 0x8803, 
  0x8D89, 0x8E8A, 0x8F8B, 0x8C03, 0x9089, 0x918D, 0x928E, 0x8F03, 0x9390, 0x9491, 
  0x9592, 0x9303, 0x9691, 0x9794, 0x9895, 0x9603, 0x9994, 0x9A97, 0x9B98, 0x9903, 
  0x918E, 0x9C8D, 0x9D9A, 0x9B03, 0x9E9A, 0x9F9C, 0x9D8E, 0x9D03, 0xA09E, 0xA19F, 
  0xA2A0, 0xA103, 0xA3A2, 0xA4A3, 0xA5A4, 0xA503, 0xA6A6, 0xA797, 0xA8A7, 0xA803, 
  0xA9A9, 0xAAAA, 0xABAB, 0xAC03, 0xACAD, 0xADAE, 0xAEAF, 0xB003, 0xAFAF, 0xB0A7, 
  0xAEAD, 0xB103, 0xB1AA, 0xB2AE, 0xB392, 0xB203, 0xB4AA, 0xADAF, 0xB1AE, 0xB303, 
  0xB5AE, 0x9590, 0xB292, 0xB403, 0xB691, 0xB0AD, 0xB7A7, 0xB503, 0xA7A7, 0xB897, 
  0xB791, 0xB603, 0xB9A9, 0xB4AF, 0xA9AA, 0xB703, 0xBAB8, 0xBBB9, 0xBCBA, 0xBB03, 
  0xBDBC, 0xBEBD, 0xBFBE, 0xBF03, 0xC0B9, 0xC1C0, 0xC2C1, 0xC203, 0xC3B8, 0xC4BC, 
  0xBAB9, 0xC303, 0xC585, 0xC0C0, 0xC6B9, 0xC403, 0xC7BC, 0xC685, 0xC4B9, 0xBF55, 
  0x0003, 0x0101, 0x0202, 0x0303, 0x0403, 0x0405, 0x0506, 0x0607, 0x0803, 0x0709, 
  0x080A, 0x090B, 0x0C03, 0x0A0D, 0x0B0E, 0x0C02, 0x0F03, 0x0D0E, 0x0E10, 0x0F11, 
  0x1203, 0x1013, 0x1114, 0x1215, 0x1203, 0x1316, 0x1115, 0x1414, 0x1703, 0x1213, 
  0x1515, 0x1618, 0x1903, 0x171A, 0x181B, 0x191C, 0x1D03, 0x1A1E, 0x1B1F, 0x1C20, 
  0x2103, 0x1D1E, 0x1E22, 0x1A1F, 0x2303, 0x1F1F, 0x2024, 0x1B20, 0x2503, 0x2126, 
  0x2020, 0x2224, 0x2703, 0x1F24, 0x231F, 0x2428, 0x2903, 0x252A, 0x262B, 0x272C, 
  0x2D03, 0x282E, 0x292F, 0x2A30, 0x3103, 0x2B32, 0x1613, 0x2C18, 0x3103, 0x2C32, 
  0x2D18, 0x2E33, 0x3403, 0x2F2E, 0x3035, 0x282F, 0x3403, 0x3136, 0x302F, 0x3235, 
  0x3703, 0x3332, 0x3438, 0x2B13, 0x3903, 0x353A, 0x2A2E, 0x3630, 0x3903, 0x363A, 
  0x3730, 0x383B, 0x3C03, 0x3935, 0x3A3D, 0x3B3E, 0x3F03, 0x3C40, 0x3D41, 0x3E42, 
  0x4303, 0x3F44, 0x4045, 0x4146, 0x4703, 0x4241, 0x4348, 0x4446, 0x4903, 0x4046, 
  0x4545, 0x464A, 0x4B03, 0x474C, 0x0301, 0x4803, 0x4D03, 0x454A, 0x4945, 0x4A4C, 
  0x4E03, 0x494C, 0x4B45, 0x4701, 0x4F03, 0x4C0A, 0x4D07, 0x4E50, 0x5103, 0x4F50, 
  0x5052, 0x4E0A, 0x5303, 0x5152, 0x080B, 0x500A, 0x5403, 0x5255, 0x5356, 0x5457, 
  0x5803, 0x5559, 0x5357, 0x5656, 0x5A03, 0x5757, 0x580D, 0x5455, 0x5B03, 0x595C, 
  0x5A5D, 0x5B59, 0x3C03, 0x3B35, 0x5C3E, 0x3236, 0x5E03, 0x5B5C, 0x5D59, 0x5E5F, 
  0x6003, 0x2E32, 0x5F33, 0x6061, 0x6203, 0x6163, 0x6264, 0x6365, 0x6603, 0x6465, 
  0x655D, 0x6363, 0x6703, 0x5A59, 0x665D, 0x5557, 0x6803, 0x6765, 0x6869, 0x645D, 
  0x6A03, 0x6928, 0x6A69, 0x6B26, 0x6B03, 0x4441, 0x4646, 0x6C4A, 0x6C03, 0x6D6D, 
  0x6E4A, 0x6F6E, 0x6F03, 0x7070, 0x7171, 0x7272, 0x7303, 0x7370, 0x7474, 0x756E, 
  0x7503, 0x7671, 0x6E6E, 0x774A, 0x7603, 0x4A4A, 0x784C, 0x7771, 0x7703, 0x7978, 
  0x7A79, 0x7B7A, 0x7B03, 0x7C7A, 0x7D0B, 0x7B78, 0x7C03, 0x7E7D, 0x7F7E, 0x807F, 
  0x8003, 0x8181, 0x8282, 0x8383, 0x8403, 0x8407, 0x8585, 0x0605, 0x8603, 0x070A, 
  0x8609, 0x8785, 0x8703, 0x8888, 0x8989, 0x8A8A, 0x8B03, 0x1E1F, 0x8B22, 0x8C8C, 
  0x8D03, 0x8D88, 0x8E8E, 0x8889, 0x8F03, 0x8F90, 0x9091, 0x9188, 0x9203, 0x9293, 
  0x9394, 0x9495, 0x9603, 0x3338, 0x9532, 0x9697, 0x9803, 0x9597, 0x9732, 0x9899, 
  0x9803, 0x9897, 0x9999, 0x9A9A, 0x9B03, 0x746E, 0x9B74, 0x6F6D, 0x9C03, 0x9C74, 
  0x9D9D, 0x9E65, 0x9E03, 0x393D, 0x9F35, 0xA09F, 0xA003, 0x6032, 0xA161, 0x9799, 
  0xA103, 0xA2A2, 0xA32A, 0xA4A3, 0xA103, 0xA5A4, 0xA3A3, 0xA62A, 0xA503, 0xA7A6, 
  0xA8A7, 0xA993, 0xA803, 0x272A, 0xAA2C, 0xA6A4, 0xA903, 0xABAA, 0xA893, 0xACA7, 
  0xAB03, 0xAB93, 0xADAA, 0x9294, 0xAC03, 0x6563, 0x595D, 0xAE5C, 0xAD03, 0xAFAE, 
  0xB0AF, 0xB1B0, 0xB103, 0x8485, 0x4C07, 0x870A, 0xB203, 0x8182, 0xB281, 0xB37F, 
  0xB303, 0xB481, 0xB5B4, 0xB27F, 0xB503, 0xB6B6, 0xB77D, 0xB8B7, 0xB803, 0xB97D, 
  0xBAB9, 0xB7B7, 0xBA03, 0xBB45, 0xBCBB, 0x4B01, 0xBC03, 0xBD7A, 0xBEBD, 0xBF52 
   
 };


 //****************************************************************************
 //
 //****************************************************************************

 void initialize(){
   
  Wire.begin(); 
  TWBR = 12;
  while( !Serial ); 
    
  delay( 50 ); 
  
  Wire.beginTransmission( SLAVE ); 
  Wire.write( 0x00 );
  Wire.write( 0xAE ); // set display Off
  Wire.write( 0xD5 ); // set display clock divide ratio/oscillator frequency
  Wire.write( 0x80 );
  Wire.write( 0xA8 ); // set multiplex ratio
  Wire.write( 0x3F );
  Wire.write( 0xD3 ); // set display offset
  Wire.write( 0x00 );
  Wire.write( 0x40 ); // set display start line
  Wire.write( 0x8D ); // set charge pump
  Wire.write( 0x14 ); // VCC generated by internal DC/DC circuit
  Wire.write( 0xA1 ); // set segment re-map 
  Wire.write( 0xC0 ); // 
  Wire.write( 0xC8 ); // 
  Wire.write( 0x12 );
  Wire.write( 0x81 ); // set contrast control
  Wire.write( 0x88 ); // 0 ... 255
  Wire.write( 0xD9 ); // set pre-changed period
  Wire.write( 0xF1 );
  Wire.write( 0xDB ); // set VCOMH Deselected level
  Wire.write( 0x40 );
  Wire.write( 0xA4 ); // set entire display on/off
  Wire.write( 0xA6 ); // set normal display 
  Wire.write( 0x20 ); // set memory address mode
  Wire.write( 0x00 ); // horizontal
  Wire.write( 0xAF ); // set display on
  Wire.endTransmission(); 
 }

 //****************************************************************************
 //
 //****************************************************************************

 void clearScreen() {
  int  a, entries;
  byte lookup[ 16 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

  setOledPosition( 0, 0 );

  entries = ( WIDTH * ( HEIGHT >> 3 ) ) >> 4;

  for( a = 0; a < entries; a += 1 ){
   Wire.beginTransmission( SLAVE ); 
   Wire.write( 0x40 ); 
   Wire.write( &lookup[ 0 ], 16 );
   Wire.endTransmission();
  }
  
  memset( _bitmapData, 0, sizeof( _bitmapData ) );
 }
     
 //****************************************************************************
 //
 //****************************************************************************
     
 void setup() {
  byte row;

 // Serial.begin( 115200 );
 
  initialize(); 

  for( row = 0; row < ROWS; row += 1 ) {
   _lookupMinimumcolumn[ row ] = WIDTH - 1;
   _lookupMaximumcolumn[ row ] =         0;
   _lookupOledRefresh  [ row ] =         0;
  }

  Wire.setClock( 400000L );

  clearScreen();
 }

 //****************************************************************************
 //
 //****************************************************************************

 void loop() {

  render();

  #if SHOW_FRAMES_PER_SECOND
   drawFps();
  #endif   
 
//  delay( 1000 );
//  clearScreen();

/*#if PROFILING
  Serial.println( F(" - profiling -----------------------") );
  Serial.print( F(" time preprocessing : ") );
  Serial.println( _timePreprocessing, DEC );

  Serial.print( F(" time scanconversion: ") );
  Serial.println( _timeScanConvert, DEC );

  Serial.print( F(" time rendering     : ") );
  Serial.println( _timeRendering, DEC );
  Serial.print( F("
") );
#endif
 */ 
 }

 //****************************************************************************
 //
 //****************************************************************************

 void setOledPosition( byte row,  byte collum ) {

  byte oledSetPosition[ 7 ] = {
   0x00,   // [ 0 ] command stream
   0x22,   // [ 1 ] ver
   row,    // [ 2 ] vertical start
   7,      // [ 3 ] vertical end
   0x21,   // [ 4 ] hor
   collum, // [ 5 ] start collum 
   0x7F    // [ 6 ] end collum
  };

  Wire.beginTransmission( SLAVE ); 
  Wire.write( &oledSetPosition[ 0 ], 7 ); 
  Wire.endTransmission();
 }
     
  
 //****************************************************************************
 // 
 //****************************************************************************

 void render() {
  bool  isVisible;
  word  i0, i1, indexLookupVertices, indexLookupPolygons, vertex,
        segmentLookup[ LOOKUP_ENTRIES_UNIQUE_SEGMENTS ];
  byte  a, b, row, rowStart, rowEnd, width, offset, column, vertexIndex,
        polygon, spanHeight, spanWidth, rowData, minimumRow, maximumRow,
        indexNormal, numberOfSegments, numberOfVertices, numberOfUniqueVertices,
        numberOfPolygons, lookupMinimumcolumn[ ROWS ],
        lookupMaximumcolumn[ ROWS ], *pBitmapData;
  int   xs, ys, xe, ye, x0, y0, x1, y1, x, y, z, tmp, entries, deltaX, deltaY,
        bitmapDataAdres;
  char  *pTransformedVertex;
  word  bitfield, lookupOledRefresh[ ROWS ];
  const word *pLookupSineCosine, *pLookupVertices, *pLookupPolygons;
  byte  oledSetPosition[ 6 ] = {
   0x22,   // [ 0 ] ver
   0,      // [ 1 ] vertical start
   7,      // [ 2 ] vertical end
   0x21,   // [ 3 ] hor
   0,      // [ 4 ] start collum 
   0x7F    // [ 5 ] end collum
  };          


  #if PROFILING
   unsigned long tt;
  #endif 
  
  //***************************************************************************
  // 
  //***************************************************************************

  #if ROTATE_X_AXIS
   int  sinXAxis, cosXAxis;
  #endif

  #if ROTATE_Y_AXIS
   int  sinYAxis, cosYAxis;
  #endif

  #if ROTATE_Z_AXIS
   int sinZAxis, cosZAxis;
  #endif

  //***************************************************************************
  // 
  //***************************************************************************

  memset( lookupMinimumcolumn, WIDTH - 1, sizeof( lookupMinimumcolumn ) );
  memset( lookupMaximumcolumn,         0, sizeof( lookupMaximumcolumn ) ); 
  memset( lookupOledRefresh  ,         0, sizeof( lookupOledRefresh   ) );

  minimumRow          = ROWS - 1;
  maximumRow          = 0;
  indexLookupVertices = 0;
  indexLookupPolygons = 0;
  pTransformedVertex  = &_lookupTransformedVertices[ 0 ];
  pLookupVertices     = &_lookupVertices[ 0 ];
  pLookupPolygons     = &_lookupPolygons[ 0 ];
  pBitmapData         = &_bitmapData[ 0 ];

  //***************************************************************************
  // initialize rotation variables
  //***************************************************************************

  pLookupSineCosine = &_lookupSineCosine[ 0 ];

  #if ROTATE_X_AXIS
   i0       = pgm_read_word( pLookupSineCosine + _frameXAxis );
   sinXAxis = ( ( i0 >> 8 ) & 255 ) - 127;
   cosXAxis = (   i0        & 255 ) - 127;
  #endif

  #if ROTATE_Y_AXIS
   i0       = pgm_read_word( pLookupSineCosine + ( 255 - _frameYAxis ) );
   sinYAxis = ( ( i0 >> 8 ) & 255 ) - 127;
   cosYAxis = (   i0        & 255 ) - 127;
  #endif

  #if ROTATE_Z_AXIS
   i0       = pgm_read_word( pLookupSineCosine + _frameZAxis );
   sinZAxis = ( ( i0 >> 8 ) & 255 ) - 127;
   cosZAxis = (   i0        & 255 ) - 127;
  #endif

  //***************************************************************************
  // 
  //***************************************************************************

  do { 
       
   numberOfUniqueVertices  = ( byte )( pgm_read_word( pLookupVertices + indexLookupVertices ) & 255 );

   //**************************************************************************
   // number of transformed vertices per chunk is equals to 
   // numberOfUniqueVertices. number of bitfields never exceeds
   // numberOfUniqueVertices / 16.
   //**************************************************************************

   a = ( numberOfUniqueVertices >> 4 ) + 1 - !( numberOfUniqueVertices % 16 );
   memset( _lookupTransformedVerticesBitfield, 0, a << 1 );        
       
   //**************************************************************************
   // number of polygons per chunk
   // number of unique segments indices per chunk
   //**************************************************************************

   i0               = pgm_read_word( pLookupPolygons + indexLookupPolygons );
   numberOfPolygons = ( byte )( i0 & 255 );
   b                = ( byte )( ( i0 >> 8 ) & 255 );
   a                = ( b >> 4 ) + 1 - !( b % 16 );
       
   memset( segmentLookup, 0, a << 1 );

   //**************************************************************************
   // 
   //**************************************************************************
      
   indexLookupVertices += 1;
   indexLookupPolygons += 1;

   //**************************************************************************
   //
   // loop polygons 
   //
   // the arduino nano has 2kb ram.
   // the 3D model data is stored in sram ( 30kb ) and retrieved in
   // chunks. per chunk a couple of polygons are drawn.
   //
   //**************************************************************************

   for( polygon = 0; polygon < numberOfPolygons; polygon += 1 ) {

    i0                   = pgm_read_word( pLookupPolygons + indexLookupPolygons );
    numberOfVertices     = i0 & 255;
    indexLookupPolygons += 1;
    isVisible            = true;

    //*************************************************************************
    // 
    // preproces polygon; transform polygon normal & vertices
    //
    //*************************************************************************

    #if PROFILING
     tt = micros();
    #endif

    for( vertex = 0; vertex < numberOfVertices + 1; vertex += 1 ) {

     //************************************************************************
     // get vertex index
     //************************************************************************

     if( vertex != 0 ) { 
      vertexIndex = pgm_read_word( pLookupPolygons + indexLookupPolygons + vertex - 1 ) & 255;
     } else { 
      vertexIndex = ( i0 >> 8 ) & 255;
     }

     i1 = 1 << ( vertexIndex % 16 );

     //************************************************************************
     // check if verter ( or polygon normal ) is transformed previously
     // if alreay calculated do not re-calculate transformation
     //************************************************************************

     if( !( _lookupTransformedVerticesBitfield[ vertexIndex >> 4 ] & i1 ) ) {

      //***********************************************************************
      // set bit ( vertex is processed )
      //***********************************************************************

      _lookupTransformedVerticesBitfield[ vertexIndex >> 4 ] |= i1;

      //***********************************************************************
      // transform/rotate
      // fixed point math
      //***********************************************************************

      tmp = indexLookupVertices + ( vertexIndex << 1 );
         
      i0  = pgm_read_word( pLookupVertices + tmp    );
      i1  = pgm_read_word( pLookupVertices + tmp + 1 );

      x   = ( char )( ( ( i0 >> 8 ) & 255 ) - 127 ); 
      y   = ( char )(   ( i0        & 255 ) - 127 ); 
      z   = ( char )(   ( i1        & 255 ) - 127 ); 
 
      #if ROTATE_X_AXIS 
       tmp  = y;
       y    = (   y * cosXAxis -   z * sinXAxis ) >> 7;
       z    = ( tmp * sinXAxis +   z * cosXAxis ) >> 7; 
      #endif

      #if ROTATE_Y_AXIS 
       tmp  = x;
       x    = ( z * sinYAxis +   x * cosYAxis ) >> 7;
       z    = ( z * cosYAxis - tmp * sinYAxis ) >> 7;   
      #endif

      #if ROTATE_Z_AXIS 
       tmp  = x;
       x    = (   x * cosZAxis -   y * sinZAxis ) >> 7;
       y    = ( tmp * sinZAxis +   y * cosZAxis ) >> 7;  
      #endif

      //***********************************************************************
      // if position is vertex data use vertical position to set 
      // minimum & maximum row.
      //***********************************************************************

      if( vertex != 0 ) {

       x = ( WIDTH  >> 1 ) - ( ( x * OBJECT_SIZE ) >> 8 ) - 64;
       y = ( HEIGHT >> 1 ) - ( ( y * OBJECT_SIZE ) >> 8 );

       //**********************************************************************
       // horizontal correction ( screen is 0 ... WIDTH )
       // width = 128, char maximum is 127
       // correction is undone during drawing
       //**********************************************************************
          
       *( pTransformedVertex + ( vertexIndex << 1 )     ) = ( char )max( -117, min( x, 127 ) );
       *( pTransformedVertex + ( vertexIndex << 1 ) + 1 ) = ( char )max( -127, min( y, 127 ) );

       row        = max( 0, min( ROWS - 1, y >> 3 ) );
       minimumRow = min( row, minimumRow );
       maximumRow = max( row, maximumRow );

       x = max( 0, min( *( pTransformedVertex + ( vertexIndex << 1 ) ) + 64, WIDTH - 1 ) );
           
       if( x < lookupMinimumcolumn[ row ] ) { lookupMinimumcolumn[ row ] = x; }
       if( x > lookupMaximumcolumn[ row ] ) { lookupMaximumcolumn[ row ] = x; }
          
      } else {
       *( pTransformedVertex + ( vertexIndex << 1 ) ) = z;
      }
     } 

     //************************************************************************
     // if position is polygon normal check sign z position ( stored in
     // [ 0 ] ) for visibility; hidden surface removal.
     //************************************************************************
 
     if( vertex == 0 && ( *( pTransformedVertex + ( vertexIndex << 1 ) ) <= 0 ) == FLIP_NORMAL ) {
      isVisible = false;
      break;
     } 
    } // end loop polygon vertices

    #if PROFILING
     _timePreprocessing += micros() - tt;
    #endif

    //*************************************************************************
    //
    // 
    // scanconvert polygon if visible
    //
    //
    //*************************************************************************

    if( isVisible ) {

     #if PROFILING
      tt = micros();
     #endif

     //************************************************************************
     // scan convert segments polygons
     //************************************************************************
         
     for( vertex = 0; vertex < numberOfVertices ; vertex += 1 ) {
 
      //***********************************************************************
      // start position becomes previous end 
      //***********************************************************************
 
      i0 = pgm_read_word( pLookupPolygons + indexLookupPolygons + vertex );

      //***********************************************************************
      // check if segment is already drawn
      // if segment index == 0 no need to draw segment.
      // segment == 0 is used for poly lists to hide the segment which
      // closes the polygon which doesn''t like nice on the screen.
      //***********************************************************************

      row = ( i0 >> 8 ) & 255;
 
      if( row == 0 ) {
       continue;
      }

      xs = 1 << ( ( row - 1 ) % 16 );
      xe =        ( row - 1 ) >> 4  ; 

      //***********************************************************************
      // check if segment is drawn previously; avoid multiple draws 
      // of the same polygon segment
      //***********************************************************************

      if( !( segmentLookup[ xe ] & xs ) ) { 

       //**********************************************************************
       // set bitfield bit; do not proces segment a next time
       //**********************************************************************
     
       segmentLookup[ xe ] |= xs;

       //**********************************************************************
       // init start & end position segment
       //**********************************************************************

       i0 = ( i0 & 255 ) << 1;
       x0 = *( pTransformedVertex + i0     ) + 64;
       y0 = *( pTransformedVertex + i0 + 1 );

       i0 = ( pgm_read_word( pLookupPolygons + indexLookupPolygons + ( ( vertex + 1 ) % numberOfVertices ) ) & 255 ) << 1;
       x1 = *( pTransformedVertex + i0     ) + 64;
       y1 = *( pTransformedVertex + i0 + 1 );

       //**********************************************************************
       //
       //**********************************************************************

       deltaX = x1 - x0;
       deltaY = y1 - y0;

       //**********************************************************************
       //
       //**********************************************************************

       #if !isMeshInsideScreen
        if( ( deltaX < 0 && x1 < WIDTH && x0 >= 0 ) || ( deltaX >= 0  && x0 < WIDTH && x1 >= 0 ) ) {
         if( ( deltaY < 0 && y1 < HEIGHT && y0 >= 0 ) || ( deltaY >= 0  && y0 < HEIGHT && y1 >= 0 ) ) {
       #endif

       //**********************************************************************
       //
       // delta y line greater delta x line; draw scanlines vertical 
       // per byte ( 0 ... 255 )
       //
       //  .....+............  scanline 0
       //  .....|+...........  scanline 1
       //  .....||...........  scanline 2
       //  .....+|...........  scanline 3
       //  ......+...........  scanline 4
       //   
       //**********************************************************************

       if( abs( deltaY ) >= abs( deltaX ) ) {

        entries   = abs( deltaX );   
        deltaY    = ( ( y1 - y0 ) << 8 ) / ( entries == 0 ? 1 : entries );
        y0      <<= 8;
        ys        = ( y0 + 128 ) >> 8;

        for( a = 0; a <= entries ; a += 1 ) { 

         ye = x0 == x1 ? y1 : ( ( y0 + deltaY ) + 128 ) / 256;
 
         #if !isMeshInsideScreen
          if( x0 >= 0 && x0 < WIDTH ) {
         #endif

          spanHeight = max( 1, abs( ys - ye ) + ( x0 == x1 ? 1 : 0 ) );
          y          = ys - ( ys <= ye ? 0 : ( spanHeight - 1 ) );

          //*******************************************************************
          // check if scanline horizontal start & end position is in screen
          //*******************************************************************

          #if !isMeshInsideScreen
           if( y < HEIGHT && ( y + spanHeight ) >= 0 ) {
          #endif

           spanHeight      = y + spanHeight;  
           y               = max( 0, y );  
           spanHeight      = min( spanHeight - y, HEIGHT - y );
               
           rowStart        = max( 0, min(   y                    >> 3, ROWS - 1 ) );
           rowEnd          = max( 0, min( ( y + spanHeight - 1 ) >> 3, ROWS - 1 ) );
           bitmapDataAdres = ( rowStart * WIDTH ) + x0;

           for( row = rowStart; row <= rowEnd; row += 1, bitmapDataAdres += WIDTH ) {

            i0      = row == rowStart ? y % 8: 0; 
            i1      = min( min( spanHeight, ( y + spanHeight ) - ( row * 8 ) ), 8 - i0 ); 
            rowData = ( ( 1 << i1 ) - 1 ) << i0;
                
            *( pBitmapData + bitmapDataAdres ) |= rowData;

            if( x0 < lookupMinimumcolumn[ row ] ) { lookupMinimumcolumn[ row ] = x0; }    
            if( x0 > lookupMaximumcolumn[ row ] ) { lookupMaximumcolumn[ row ] = x0; }    
 
            lookupOledRefresh[ row ] |= 1 << ( x0 >> 3 );
           } 

         #if !isMeshInsideScreen
           } // end check vertical interval
          } // end check horizontal minimum & maximum
         #endif 

         //********************************************************************
         //
         //********************************************************************

         ys  = ye;
         x0 += ( x1 < x0 ) ? -1 : 1;
         y0 += deltaY;

         //********************************************************************
         //
         //********************************************************************

         #if !isMeshInsideScreen

          if( ( deltaY >= 0 && y >= ( HEIGHT - 1 ) ) || ( deltaY < 0 && y <= 0 ) ) {
           break;
          }

         #endif

        } // end loop entries
       } // end check delta y

       //**********************************************************************
       //
       // delta x line greater delta y line; draw scanlines horizontal
       //
       //  .....+------+......  scanline 0
       //  ..........+------+.  scanline 1
       //
       //**********************************************************************
   
       else  { 

        entries   = abs( deltaY );   
        deltaX    = ( ( ( x1 - x0 ) << 8 ) / ( entries == 0 ? 1 : entries ) );
        x0      <<= 8;
        xs        = ( x0 + 128 ) >> 8;

        //*********************************************************************
        // loop vertical
        //*********************************************************************

        for( a = 0; a <= entries ; a += 1 ) { 
 
         xe = y0 == y1 ? x1 : ( ( x0 + deltaX ) + 128 ) / 256;

         //********************************************************************
         // check if scanline vertical position is in screen
         //********************************************************************

         #if !isMeshInsideScreen
          if( y0 >= 0 && y0 < HEIGHT ) {
         #endif

          spanWidth = max( 1, abs( xs - xe ) + ( y0 == y1 ? 1 : 0 ) );
          x         = xs - ( xs <= xe ? 0 : ( spanWidth - 1 ) );

          //*******************************************************************
          // check if scanline horizontal start & end position is in screen
          //*******************************************************************

          #if !isMeshInsideScreen
           if( x >= 0 && x < WIDTH && ( x + spanWidth ) >= 0 ) {
          #endif

           spanWidth       = x + spanWidth;  
           x               = max( 0, x );  
           spanWidth       = min( spanWidth - x, WIDTH - x );
       
           row             = y0 >> 3;
           bitmapDataAdres = ( row * WIDTH ) + x;
           rowData         = 1 << ( y0 % 8);

           if( ( rowData & 129 ) != 0 ) { 
            if(   x                   < lookupMinimumcolumn[ row ] ) { lookupMinimumcolumn[ row ] = x                ; }    
            if( ( x + spanWidth - 1 ) > lookupMaximumcolumn[ row ] ) { lookupMaximumcolumn[ row ] = x + spanWidth - 1; }    
           }
 
           //******************************************************************
           // loop vertical
           //******************************************************************
  
           for( b = 0; b < spanWidth; b += 1, x += 1 ) {
            *( pBitmapData + bitmapDataAdres + b ) |= rowData;
            lookupOledRefresh[ row ] |= 1 << ( x >> 3 );
           }

         #if !isMeshInsideScreen
           } 
          }
         #endif 

         //*******************************************************************
         //
         //*******************************************************************

         xs  = xe;
         y0 += ( y1 < y0 ) ? -1 : 1;
         x0 += deltaX;

         //********************************************************************
         //
         //********************************************************************

         #if !isMeshInsideScreen

          if( ( deltaX >= 0 && x >= ( WIDTH - 1 ) ) || ( deltaX < 0 && x <= 0 ) ) {
           break;
          }

         #endif

        } // end loop entries
       } // end check delta x
   
       #if !isMeshInsideScreen
         }
        }
       #endif

      } // end is segment already drawn check
     } // end loop vertices

     #if PROFILING
      _timeScanConvert += micros() - tt;
     #endif
     
    } // end check is polygon visible

    //*************************************************************************
    // update indices
    //*************************************************************************

    indexLookupPolygons += numberOfVertices;
    
    } // end loop polygons

    indexLookupVertices += numberOfUniqueVertices << 1;

  } while( indexLookupPolygons < NUMBER_OF_POLYGON_INDICES );

  //***************************************************************************
  //
  // draw & remove data per row
  // render content bitmapdata to oled screen.
  //
  //  min +------+ max // previous drawn row
  //    min +--+ max   // current row
  //
  // previous drawn row is still visible on screen.
  // previous minimum is compared againt current row minimum. the lowest
  // value is used to remove previous drawn row ( and draw ) current row.
  // same applies for maximum.
  //
  // draw from top row to bottom row; fps is drawn at bottom row
  // bottom row is drawn last so time between fps draw and 3d object
  // draw is minimumal ( less flickering )
  //
  //***************************************************************************

  #if PROFILING
   tt = micros();
  #endif
  
  a = max( _maximumRow, maximumRow ) ; 

  for( row = min( _minimumRow, minimumRow ) ; row <= a ; row += 1 ) {

   xs = min( _lookupMinimumcolumn[ row ], lookupMinimumcolumn[ row ] )    ;
   xe = max( _lookupMaximumcolumn[ row ], lookupMaximumcolumn[ row ] ) + 1;
   
   if( xs < xe ) {

    //*************************************************************************
    // display minimum and maximum area needed for oled screen removal.
    //*************************************************************************

    // *( pBitmapData + ( row * WIDTH ) + lookupMinimumcolumn[ row ] ) |= 255;
    // *( pBitmapData + ( row * WIDTH ) + lookupMaximumcolumn[ row ] ) |= 255;

    oledSetPosition[ 1 ] = row; 
    oledSetPosition[ 2 ] = row;
    oledSetPosition[ 4 ] = xs ;

    Wire.beginTransmission( SLAVE ); 
    Wire.write( 0x00 );
    Wire.write( &oledSetPosition[ 0 ], 6 ); 
    Wire.endTransmission();

    column   = xs;
    width    = 8 - ( column & 7 ); 
    bitfield = _lookupOledRefresh[ row ] | lookupOledRefresh[ row ];
    i1       = row * WIDTH;

    do { //********************************************************************
         // draw span
         //********************************************************************

         i0 = bitfield >> ( column >> 3 );
 
         if( i0 & 1 ) {

          //*******************************************************************
          // check lsb if oled position needs to be set
          //*******************************************************************

          if( ( bitfield & 1 ) == 0 ) {
           oledSetPosition[ 4 ] = column ;
           Wire.beginTransmission( SLAVE ); 
           Wire.write( 0x00 );
           Wire.write( &oledSetPosition[ 3 ], 3 ); 
           Wire.endTransmission();
          }

          //*******************************************************************
          // send data in packages of 8, 16 or 24 
          // ( 32 is one too many for 32 bytes since 0x40 is send aswell )
          //*******************************************************************

          switch( i0 & 7 ) {
           case 7:
            spanWidth = 16;
            break;
           case 3:
            spanWidth = 8;
            break;
           default:
            spanWidth = 0;
            break;
          };

          Wire.beginTransmission( SLAVE ); 
          Wire.write( 0x40 ); 
          Wire.write( ( pBitmapData + i1 + column ), min( width + spanWidth, xe - column ) );
          Wire.endTransmission();
 
          //*******************************************************************
          // lsb is used as data send 
          //*******************************************************************
      
          bitfield |= 1;
         } 

         //********************************************************************  
         // skip span(s)
         //********************************************************************
     
         else {

          switch(  ~i0 & 127  ) {
           case 127:
            spanWidth = 48;
            break;
           case 63:
            spanWidth = 40;
            break;
           case 31:
            spanWidth = 32;
            break;
           case 15:
            spanWidth = 24;
            break;
           case 7:
            spanWidth = 16;
            break;
           case 3:
            spanWidth = 8;
            break;
           default:
            spanWidth = 0;
            break;
          };

          //*******************************************************************
          // lsb is used as no-data send.
          // if 0 - zero - and data needs to be send on same row adjust 
          // oled screen position 
          //*******************************************************************
 
          bitfield -= bitfield & 1;
         }

        column += width + spanWidth;
        width   = 8;

      } while( column < xe );
 

    //*************************************************************************
    // 
    //*************************************************************************

    #if SHOW_FRAMES_PER_SECOND
     if( row != FPS_ROW_POSITION ) {
      memset( ( pBitmapData + ( row * WIDTH ) + xs ), 0, xe - xs ); 
     }
    #else 
      memset( ( pBitmapData + ( row * WIDTH ) + xs ), 0, xe - xs ); 
    #endif

    _lookupMinimumcolumn[ row ] = lookupMinimumcolumn[ row ];
    _lookupMaximumcolumn[ row ] = lookupMaximumcolumn[ row ];
    _lookupOledRefresh  [ row ] = lookupOledRefresh  [ row ];
   }
  }

  //***************************************************************************
  // 
  //***************************************************************************
  
  #if PROFILING
   _timeRendering += micros() - tt;
  #endif
 
  //***************************************************************************
  // 
  //***************************************************************************

  _minimumRow = minimumRow;
  _maximumRow = maximumRow;

  //***************************************************************************
  // 
  //***************************************************************************

  #if ROTATE_Y_AXIS
   _frameYAxis = ( _frameYAxis + 3 ) & 255;
  #endif
 
  #if ROTATE_X_AXIS
   _frameXAxis = ( _frameXAxis + 1 ) & 255;
  #endif

  #if ROTATE_Z_AXIS
   _frameZAxis = ( _frameZAxis + 1 ) & 255;
  #endif
 }

 //****************************************************************************
 // 
 // draw frames per second
 //
 //****************************************************************************

 #if SHOW_FRAMES_PER_SECOND

  void drawFps() {
   byte a, i, fps, index, *pBitmapData;
   word bitmapPos;
   const byte *pLookupFps;

   pBitmapData         = &_bitmapData[ 0 ];
   pLookupFps          = &_lookupFps[ 0 ];
   index               = WIDTH - 1 - 30;
   _numberOfFrames     = ( _numberOfFrames + 1 ) % 32;
   fps                 = 1000 / ( millis() - _time );
   _time               = millis();

   if( !_numberOfFrames ) {
    _totalOfFrameRates  = ( _totalOfFrameRates / 32 ) << 4;
    _numberOfFrames     = 16;
   } else {
    _totalOfFrameRates += fps;
   }

   fps       = byte( _totalOfFrameRates  / _numberOfFrames );
   bitmapPos = ( FPS_ROW_POSITION * WIDTH ) + index;

   for( a = ( fps > 99 ? 0 : fps > 9 ? 5 : 10 ); a < 30; a += 1 ) {

    if( !( a % 5 ) ) {    
 
     i = a / 5;

     if( i < 3 ) {
      i = ( ( fps / ( i == 0 ? 100 : i == 1 ? 10 : 1 ) ) % 10 ) * 5;
     } else {
      i = 50 + ( i - 3 ) * 5;
     }
    }
    
    *( pBitmapData + bitmapPos + a ) |= pgm_read_byte( pLookupFps + i + ( a % 5 ) ); 
   }
   
   //**************************************************************************
   // 
   //**************************************************************************

   byte oledSetPosition[ 7 ] = {
    0x00,             // [ 0 ] command stream
    0x22,             // [ 1 ] ver
    FPS_ROW_POSITION, // [ 2 ] vertical start
    FPS_ROW_POSITION, // [ 3 ] vertical end
    0x21,             // [ 4 ] hor
    index,            // [ 5 ] start collum 
    0x7F              // [ 6 ] end collum
   };
  
   Wire.beginTransmission( SLAVE ); 
   Wire.write( &oledSetPosition[ 0 ], 7 ); 
   Wire.endTransmission();

   for( a = 0;  a < 30; a += 24 ) {
    Wire.beginTransmission( SLAVE ); 
    Wire.write( 0x40 ); 
    Wire.write( ( pBitmapData + bitmapPos + a ), min( 24, 30 - a ) ); 
    Wire.endTransmission();
   }

   //**************************************************************************
   // clear bitmapdata
   //**************************************************************************

   index = min( _lookupMinimumcolumn[ FPS_ROW_POSITION ], index );
   memset( ( pBitmapData + ( FPS_ROW_POSITION * WIDTH ) + index ), 0, WIDTH - index ); 
  }

 #endif

  

 

lilik
Offline
Зарегистрирован: 19.10.2017

Переделал код в части loop, для примера 5 моделек в скетче их просмотра заняли чуть более 60 процентов.

 void loop() {

//////////////// 
 OBJECT_SIZE = map(analogRead(A0), 0,1023, 10, 260);//ближе-дальше модель
 if(OBJECT_SIZE >= ( WIDTH - 2 ) || OBJECT_SIZE >= ( HEIGHT - 2 )){isMeshInsideScreen = false;}else{isMeshInsideScreen = true;}
///////////////
 if (digitalRead (7) == LOW) // если кнопка нажата...
  { delay(500); 
    if (digitalRead (7) == HIGH) { // и быстро отпущена...
   model_++;if(model_>5){model_=1;} // меняем модель  
    }
  }
if(model_==1){NUMBER_OF_VERTEX_INDICES=1516;NUMBER_OF_POLYGON_INDICES=1420;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 13;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 13; render(394);}
if(model_==2){NUMBER_OF_VERTEX_INDICES=185;NUMBER_OF_POLYGON_INDICES=385;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 9;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 6; render(184);}
if(model_==3){NUMBER_OF_VERTEX_INDICES=977;NUMBER_OF_POLYGON_INDICES=1165;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 13;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 13; render(400);}
if(model_==4){NUMBER_OF_VERTEX_INDICES=33;NUMBER_OF_POLYGON_INDICES=49;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 2;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 1; render(32);}
if(model_==5){NUMBER_OF_VERTEX_INDICES=95;NUMBER_OF_POLYGON_INDICES=241;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 6;LOOKUP_ENTRIES_TRANSFORMED_VERTICES = 3; render(94);} 


 }

Автор ответил-пока делать библиотеку желания не имеет. А жаль, мне кажется по наивности, он смог бы впихнуть и шрифты, и графику 2D, 3D. Библиотек таких хороших ведь нет :(

sadman41
Offline
Зарегистрирован: 19.10.2016

Так Вы можете инвестировать в хорошую библиотеку, оплатив труд автора.

lilik
Offline
Зарегистрирован: 19.10.2017

Была такая шальная мысль :) Но расценки за рубежом большие, наверное, + настоящего художника обидеть деньгами можно. А так, в складчину, ежели для всех библиотека - 500 р. могу без щекотки отдать.

lilik
Offline
Зарегистрирован: 19.10.2017

Отложил пока 3D анимацию (до появления публичной библиотеки), пробую OLED_I2C для анимации картинок (она вроде визуально шустрее). Как двигать картинку вдоль, поперёк, наискосок понял. А как удалять-приближать к наблюдателю, поворачивать на угол хотя бы относительно оси Z?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

lilik пишет:
в складчину, ежели для всех

Тогда ищите всех, кому ещё (кроме Вас), это нужно и складывайтесь.

Я вот не вижу смысла в такой библиотеке :-(

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Я вот не вижу смысла в такой библиотеке :-(

библиотека хорошая... но денег не дам

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

библиотека хорошая... но денег не дам

Ну, да, как у Михаила Афанасьевича

– Почему же вы отказываетесь?
– Не хочу.
– Вы не сочувствуете детям Германии?
– Равнодушен к ним.
– Жалеете отдать полтинник?
– Нет.
– Так почему же?!
– Не хочу.
lilik
Offline
Зарегистрирован: 19.10.2017

ЕвгенийП пишет:

lilik пишет:
в складчину, ежели для всех

Тогда ищите всех, кому ещё (кроме Вас), это нужно и складывайтесь.

Я вот не вижу смысла в такой библиотеке :-(

Нет, не отдельная библиотека, а как опция к текстовым и 2Д картиночным функциям "обычных" библиотек. Вот в этой, что я выше упомянул есть пример с 3D кубом, но это явно единичный случай. Хотя это наверное желание впихнуть невпихуемое в одно целое.

А так, я уже до 1000р созрел для коллективного разума )))

Просто вот, например, хочется жучка по экрану, что бы бегал под разными углами, а в функции myOLED.drawBitmap(0, 0,foto_A, 32, 32); нет аргумента - угол поворота картинки (((

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

lilik пишет:
Просто вот, например, хочется жучка по экрану, что бы бегал под разными углами, а в функции myOLED.drawBitmap(0, 0,foto_A, 32, 32); нет аргумента - угол поворота картинки (((
И как жить-то? :-(

lilik
Offline
Зарегистрирован: 19.10.2017

ЕвгенийП пишет:

И как жить-то? :-(

Ну или блажь пройдёт, или по картиночно придётся изгаляться :)

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Ну, да, как у Михаила Афанасьевича

– Почему же вы отказываетесь?
– Не хочу.
– Вы не сочувствуете детям Германии?
– Равнодушен к ним.
– Жалеете отдать полтинник?
– Нет.
– Так почему же?!
– Не хочу.

Профессор, вас стоило бы расстрелять!

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

lilik пишет:

Просто вот, например, хочется жучка по экрану, что бы бегал под разными углами, а в функции myOLED.drawBitmap(0, 0,foto_A, 32, 32); нет аргумента - угол поворота картинки (((

Вы когда-нибудь слышали такой термин - спрайтовая анимация.

lilik
Offline
Зарегистрирован: 19.10.2017

Да, так примерно и задумывал, но хотелось в рамках функций библиотеки спрайт не только поступательно двигать, а и вращать, уменьшать-увеличивать на экране.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

lilik пишет:

Да, так примерно и задумывал, но хотелось в рамках функций библиотеки спрайт не только поступательно двигать, а и вращать, уменьшать-увеличивать на экране.

Спрайт не нужно вращать (на угол отличный от кратных 90), и увеличивать-уменьшать.

И потом, спрайтовая анимация - слишком специфичная область, чтобы ее включать в универсальную библиотеку.

lilik
Offline
Зарегистрирован: 19.10.2017

Ну вот вставил я гифку жука в экранчик. Пробегает он мимо. Но в библиотеке не нашёл и вращение спрайта даже на 90 градусов (( А хотелось имитации жука в банке (сейчас дети начнут майских жуков насмерть  рассматривать, как они копошатся)... Получается новый комплект картинок подгружать в скетч. 

b707
Offline
Зарегистрирован: 26.05.2017

lilik пишет:

в библиотеке не нашёл и вращение спрайта даже на 90 градусов (( А хотелось

вращение на 90 делается заменой координаты х на у и наоборот. И иногда инвертированием значений.

lilik
Offline
Зарегистрирован: 19.10.2017

Где менять? В координатах вывода спрайта?

lilik
Offline
Зарегистрирован: 19.10.2017

Реализовал, правда за счёт поворотов изображений всего экрана.

lilik
Offline
Зарегистрирован: 19.10.2017


#include <Wire.h>//Подключаю библиотеку протокола I2C.
extern char glaza_A[];
extern char glaza_B[];
extern char glaza_C[];
extern char glaza_D[];
extern char glaza_F[];

//////////////////////////////////////////////////////////////////////
//Предварительно создам функции ввода команд и данных в дисплей.
 void oledCommand(int comm) {
 Wire.beginTransmission(0x3C);//Начинаем передачу команд устройству с адресом 0x3C.
 Wire.write(0x00);//Сообщаем дисплею, что следующее передаваемое значение - команда.
 Wire.write(comm);//Передаем команду.
 Wire.endTransmission();//Завершаем передачу данных.
 }
/////////////////////////////////////////////////////////////////////// 
 void oledData(int data) {
 Wire.beginTransmission(0x3C);//Начинаем передачу данных устройству с адресом 0x3C.
 Wire.write(0x40);//Сообщаем дисплею, что следующее передаваемое значение - данные, которые необходимо вывести на дисплей.
 Wire.write(data);//Передаем данные.
 Wire.endTransmission();//Завершаем передачу данных.
 }

 /////////////////////////////////////////////////////////////////////
 void setup() {
 
 Wire.begin();
 
//процесс инициализации частично команды необязательны, т.к. имеют выбранное значение после RESET
 oledCommand(0xAE);//выключение дисплея
 oledCommand(0xD5);// Частота обновления экрана
 oledCommand(0x80);
 oledCommand(0xD3);// Смещение изображения на дисплее (Offset)
 oledCommand(0x0);
 oledCommand(0x40);
 oledCommand(0x8D);//включение емкостного умножителя
 oledCommand(0x14);
 oledCommand(0x20);//настройка адресации
 oledCommand(0x00);// 0х00 для горизонтальной, 0х01 для вертикальной, 0х02 для постраничной адресации
 oledCommand(0xA1);//отражение по горизонтали, для отображения справа налево необходимо использовать команду 0xA0
 oledCommand(0xC8);//отражение по вертикали, 0xC0 для переворота изображения по вертикали.
 //Одновременное использование команд 0xC8 и 0xA1 или 0xA0 и 0xC0 позволяет повернуть изображение на 180 градусов.
 oledCommand(0xDA);
 oledCommand(0x12);
 oledCommand(0x81);//установка контрастности дисплея
 oledCommand(0xCF);
 oledCommand(0xD9);
 oledCommand(0xF1);
 oledCommand(0xDB); // установка Vcomh(влияет на яркость)
// oledCommand (0x30); // 0x00 - 0,65Vcc; 0x20 - 0,77Vcc; 0x30 - 0,83Vcc
 oledCommand(0x40);
 oledCommand(0xA4);
 oledCommand(0xA6);//инверсия дисплея, 0xA6 для отключения инверсии, 0xA7 для включения инверсии цвета.
 oledCommand(0xAF);//включение дисплея

 Wire.setClock( 400000L );
 
}
 
void loop() {
 // сценарий анимации глаз 
for (int i = 0; i < 1024; i++){oledData(pgm_read_byte(&glaza_A[i]));}delay(500);//ВПРАВО
for (int i = 0; i < 1024; i++){oledData(pgm_read_byte(&glaza_C[i]));}delay(2000);//ЦЕНТР
for (int i = 0; i < 1024; i++){oledData(pgm_read_byte(&glaza_B[i]));}delay(500);//ВЛЕВО
for (int i = 0; i < 1024; i++){oledData(pgm_read_byte(&glaza_C[i]));}delay(2000);//ЦЕНТР
for (int i = 0; i < 1024; i++){oledData(pgm_read_byte(&glaza_D[i]));}delay(500);//ВНИЗ
for (int i = 0; i < 1024; i++){oledData(pgm_read_byte(&glaza_C[i]));}delay(2000);//ЦЕНТР
for (int i = 0; i < 1024; i++){oledData(pgm_read_byte(&glaza_F[i]));}delay(500);//ЗАКРЫТЬ 
for (int i = 0; i < 1024; i++){oledData(pgm_read_byte(&glaza_C[i]));}delay(2000);//ЦЕНТР
//
}
 

Пробую экран-мордашку без библиотек с буфером-дублем экрана в озу - чтобы в про мини 168 всё влезало. С анимацией понятно. Возникает вопрос с 33 строкой - как она работает? Как смещать спрайт-картинку вверх-вниз, влево-вправо? Все ссылаются на даташит, но процедуры работы команды не поясняют. Может кто это уже делал? 

 

lilik
Offline
Зарегистрирован: 19.10.2017

Оказалось просто. После (0*D3) пишем, например, (-16) - смещаем вниз на 16 строчек.

А оттенки серого никто не пробовал на варианте с I2C? Идея сама интересна.

lilik
Offline
Зарегистрирован: 19.10.2017

Фокус не удался - частота мала.