+ for ( ; m_y <= m_y1; m_y += 8, m_x = m_x0)
+ for ( ; m_x <= m_x1; m_x += 8)
+ {
+ if ((c = LinkBox(m_x, m_y, false)) == NULL)
+ continue;
+
+ // check whether there is enough space left in the array
+ if (m_ncells > (ARRAYSIZE - 64))
+ {
+ *ncells = m_ncells;
+ return false;
+ }
+
+ DoLine(m_x, m_y , c->m_live1 );
+ DoLine(m_x, m_y + 1, c->m_live1 >> 8 );
+ DoLine(m_x, m_y + 2, c->m_live1 >> 16);
+ DoLine(m_x, m_y + 3, c->m_live1 >> 24);
+ DoLine(m_x, m_y + 4, c->m_live2 );
+ DoLine(m_x, m_y + 5, c->m_live2 >> 8 );
+ DoLine(m_x, m_y + 6, c->m_live2 >> 16);
+ DoLine(m_x, m_y + 7, c->m_live2 >> 24);
+ }
+ }
+
+ *ncells = m_ncells;
+ m_findmore = false;
+ return true;
+}
+
+// --------------------------------------------------------------------------
+// Evolution engine
+// --------------------------------------------------------------------------
+
+extern unsigned char *g_tab;
+extern int g_tab1[];
+extern int g_tab2[];
+
+// NextTic:
+// Advance one step in evolution :-)
+//
+bool Life::NextTic()
+{
+ LifeCellBox *c, *up, *dn, *lf, *rt;
+ wxUint32 t1, t2, t3, t4;
+ bool changed = false;
+
+ m_numcells = 0;
+
+ // Stage 1:
+ // Compute neighbours of each cell
+ //
+ // WARNING: unrolled loops and lengthy code follows!
+ //
+ c = m_head;
+
+ while (c)
+ {
+ if (! (c->m_live1 || c->m_live2))
+ {
+ c = c->m_next;
+ continue;
+ }
+ up = c->m_up;
+ dn = c->m_dn;
+ lf = c->m_lf;
+ rt = c->m_rt;
+
+ // up
+ t1 = c->m_live1 & 0x000000ff;
+ if (t1)
+ {
+ if (!up)
+ {
+ up = LinkBox(c->m_x, c->m_y - 8);
+ up->m_dn = c;
+ }
+ t2 = g_tab1[t1];
+ up->m_on[7] += t2;
+ c->m_on[1] += t2;
+ c->m_on[0] += g_tab2[t1];
+ }
+
+ // down
+ t1 = (c->m_live2 & 0xff000000) >> 24;
+ if (t1)
+ {
+ if (!dn)
+ {
+ dn = LinkBox(c->m_x, c->m_y + 8);
+ dn->m_up = c;
+ }
+ t2 = g_tab1[t1];
+ dn->m_on[0] += t2;
+ c->m_on[6] += t2;
+ c->m_on[7] += g_tab2[t1];
+ }
+
+ t1 = c->m_live1;
+ t2 = c->m_live2;
+
+ // left
+ if (t1 & 0x01010101)
+ {
+ if (!lf)
+ {
+ lf = LinkBox(c->m_x - 8, c->m_y);
+ lf->m_rt = c;
+ }
+ if (t1 & 0x00000001)
+ {
+ if (!lf->m_up)
+ {
+ lf->m_up = LinkBox(c->m_x - 8, c->m_y - 8);
+ lf->m_up->m_dn = lf;
+ }
+ lf->m_up->m_on[7] += 0x10000000;
+ lf->m_on[0] += 0x10000000;
+ lf->m_on[1] += 0x10000000;
+ }
+ if (t1 & 0x00000100)
+ {
+ lf->m_on[0] += 0x10000000;
+ lf->m_on[1] += 0x10000000;
+ lf->m_on[2] += 0x10000000;
+ }
+ if (t1 & 0x00010000)
+ {
+ lf->m_on[1] += 0x10000000;
+ lf->m_on[2] += 0x10000000;
+ lf->m_on[3] += 0x10000000;
+ }
+ if (t1 & 0x01000000)
+ {
+ lf->m_on[2] += 0x10000000;
+ lf->m_on[3] += 0x10000000;
+ lf->m_on[4] += 0x10000000;
+ }
+ }
+ if (t2 & 0x01010101)
+ {
+ if (!lf)
+ {
+ lf = LinkBox(c->m_x - 8, c->m_y);
+ lf->m_rt = c;
+ }
+ if (t2 & 0x00000001)
+ {
+ lf->m_on[3] += 0x10000000;
+ lf->m_on[4] += 0x10000000;
+ lf->m_on[5] += 0x10000000;
+ }
+ if (t2 & 0x00000100)
+ {
+ lf->m_on[4] += 0x10000000;
+ lf->m_on[5] += 0x10000000;
+ lf->m_on[6] += 0x10000000;
+ }
+ if (t2 & 0x00010000)
+ {
+ lf->m_on[5] += 0x10000000;
+ lf->m_on[6] += 0x10000000;
+ lf->m_on[7] += 0x10000000;
+ }
+ if (t2 & 0x01000000)
+ {
+ if (!lf->m_dn)
+ {
+ lf->m_dn = LinkBox(c->m_x - 8, c->m_y + 8);
+ lf->m_dn->m_up = lf;
+ }
+ lf->m_on[6] += 0x10000000;
+ lf->m_on[7] += 0x10000000;
+ lf->m_dn->m_on[0] += 0x10000000;
+ }
+ }
+
+ // right
+ if (t1 & 0x80808080)
+ {
+ if (!rt)
+ {
+ rt = LinkBox(c->m_x + 8, c->m_y);
+ rt->m_lf = c;
+ }
+ if (t1 & 0x00000080)
+ {
+ if (!rt->m_up)
+ {
+ rt->m_up = LinkBox(c->m_x + 8, c->m_y - 8);
+ rt->m_up->m_dn = rt;
+ }
+ rt->m_up->m_on[7] += 0x00000001;
+ rt->m_on[0] += 0x00000001;
+ rt->m_on[1] += 0x00000001;
+ }
+ if (t1 & 0x00008000)
+ {
+ rt->m_on[0] += 0x00000001;
+ rt->m_on[1] += 0x00000001;
+ rt->m_on[2] += 0x00000001;
+ }
+ if (t1 & 0x00800000)
+ {
+ rt->m_on[1] += 0x00000001;
+ rt->m_on[2] += 0x00000001;
+ rt->m_on[3] += 0x00000001;
+ }
+ if (t1 & 0x80000000)
+ {
+ rt->m_on[2] += 0x00000001;
+ rt->m_on[3] += 0x00000001;
+ rt->m_on[4] += 0x00000001;
+ }
+ }
+ if (t2 & 0x80808080)
+ {
+ if (!rt)
+ {
+ rt = LinkBox(c->m_x + 8, c->m_y);
+ rt->m_lf = c;
+ }
+ if (t2 & 0x00000080)
+ {
+ rt->m_on[3] += 0x00000001;
+ rt->m_on[4] += 0x00000001;
+ rt->m_on[5] += 0x00000001;
+ }
+ if (t2 & 0x00008000)
+ {
+ rt->m_on[4] += 0x00000001;
+ rt->m_on[5] += 0x00000001;
+ rt->m_on[6] += 0x00000001;
+ }
+ if (t2 & 0x00800000)
+ {
+ rt->m_on[5] += 0x00000001;
+ rt->m_on[6] += 0x00000001;
+ rt->m_on[7] += 0x00000001;
+ }
+ if (t2 & 0x80000000)
+ {
+ if (!rt->m_dn)
+ {
+ rt->m_dn = LinkBox(c->m_x + 8, c->m_y + 8);
+ rt->m_dn->m_up = rt;
+ }
+ rt->m_on[6] += 0x00000001;
+ rt->m_on[7] += 0x00000001;
+ rt->m_dn->m_on[0] += 0x00000001;
+ }
+ }
+
+ // inner cells
+ int i;
+ for (i = 1; i <= 3; i++)
+ {
+ t1 = ((c->m_live1) >> (i * 8)) & 0x000000ff;
+ if (t1)
+ {
+ c->m_on[i - 1] += g_tab1[t1];
+ c->m_on[i ] += g_tab2[t1];
+ c->m_on[i + 1] += g_tab1[t1];
+ }
+ }
+ for (i = 0; i <= 2; i++)
+ {
+ t1 = ((c->m_live2) >> (i * 8)) & 0x000000ff;
+ if (t1)
+ {
+ c->m_on[i + 3] += g_tab1[t1];
+ c->m_on[i + 4] += g_tab2[t1];
+ c->m_on[i + 5] += g_tab1[t1];
+ }
+ }
+
+ c->m_up = up;
+ c->m_dn = dn;
+ c->m_lf = lf;
+ c->m_rt = rt;
+ c = c->m_next;
+ }
+
+ // Stage 2:
+ // Stabilize
+ //
+ c = m_head;
+
+ while (c)
+ {
+ t1 = 0;
+ t2 = 0;
+
+ t3 = c->m_live1;
+ c->m_old1 = t3;
+
+ t4 = c->m_on[0];
+ t1 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 ) & 0xf) ];
+ t1 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 4 ) & 0xf) ] << 4;
+ t4 = c->m_on[1];
+ t1 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 8 ) & 0xf) ] << 8;
+ t1 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 12) & 0xf) ] << 12;
+ t4 = c->m_on[2];
+ t1 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 16) & 0xf) ] << 16;
+ t1 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 20) & 0xf) ] << 20;
+ t4 = c->m_on[3];
+ t1 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 24) & 0xf) ] << 24;
+ t1 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 28) & 0xf) ] << 28;
+
+ t3 = c->m_live2;
+ c->m_old2 = t3;
+
+ t4 = c->m_on[4];
+ t2 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 ) & 0xf) ];
+ t2 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 4 ) & 0xf) ] << 4;
+ t4 = c->m_on[5];
+ t2 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 8 ) & 0xf) ] << 8;
+ t2 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 12) & 0xf) ] << 12;
+ t4 = c->m_on[6];
+ t2 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 16) & 0xf) ] << 16;
+ t2 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 20) & 0xf) ] << 20;
+ t4 = c->m_on[7];
+ t2 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 24) & 0xf) ] << 24;
+ t2 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 28) & 0xf) ] << 28;
+
+ c->m_on[0] = c->m_on[1] = c->m_on[2] = c->m_on[3] =
+ c->m_on[4] = c->m_on[5] = c->m_on[6] = c->m_on[7] = 0;
+ c->m_live1 = t1;
+ c->m_live2 = t2;
+
+ // count alive cells
+#if 1
+ wxUint32 t1_, t2_;
+
+ t1_ = (t1 & 0x55555555) + (t1 >> 1 & 0x55555555);
+ t1_ = (t1_ & 0x33333333) + (t1_ >> 2 & 0x33333333);
+
+ t2_ = (t2 & 0x55555555) + (t2 >> 1 & 0x55555555);
+ t2_ = (t2_ & 0x33333333) + (t2_ >> 2 & 0x33333333) + t1_;
+ t2_ = (t2_ & 0x0F0F0F0F) + (t2_ >> 4 & 0x0F0F0F0F);
+ t2_ = (t2_ & 0x00FF00FF) + (t2_ >> 8 & 0x00FF00FF);
+
+ m_numcells += (t2_ & 0xFF) + (t2_ >> 16 & 0xFF);
+#else
+ // Original, slower code
+ for (int i = 0; i < 32; i++)
+ {
+ if (t1 & (1 << i)) m_numcells++;
+ if (t2 & (1 << i)) m_numcells++;
+ }
+#endif
+
+ changed |= ((t1 ^ c->m_old1) || (t2 ^ c->m_old2));
+
+ // mark, and discard if necessary, dead boxes
+ if (t1 || t2)
+ {
+ c->m_dead = 0;
+ c = c->m_next;
+ }
+ else
+ {
+ LifeCellBox *aux = c->m_next;
+ if (c->m_dead++ > MAXDEAD)
+ KillBox(c);
+
+ c = aux;
+ }
+ }
+
+ return changed;
+}
+
+// ==========================================================================
+// LifeModule
+// ==========================================================================
+
+// A module to pregenerate lookup tables without having to do it
+// from the application.
+
+class LifeModule: public wxModule
+{
+DECLARE_DYNAMIC_CLASS(LifeModule)
+
+public:
+ LifeModule() {};
+ bool OnInit();
+ void OnExit();
+};
+
+IMPLEMENT_DYNAMIC_CLASS(LifeModule, wxModule)
+
+bool LifeModule::OnInit()
+{
+ // see below
+ g_tab = new unsigned char [0xfffff];
+
+ if (!g_tab) return false;
+
+ for (wxUint32 i = 0; i < 0xfffff; i++)
+ {
+ wxUint32 val = i >> 4;
+ wxUint32 old = i & 0x0000f;
+ wxUint32 live = 0;
+
+ for (int j = 0; j < 4; j++)
+ {
+ live >>= 1;
+
+ if (((val & 0xf) == 3) || (((val & 0xf) == 2) && (old & 0x1)))
+ live |= 0x8;
+
+ old >>= 1;
+ val >>= 4;
+ }
+
+ g_tab[i] = (unsigned char) live;