示例#1
0
        /* ----- render utilities ----- */

        /*-------------------------------------------------
        *   render_resample_argb_bitmap_hq - perform a high
        *   quality resampling of a texture
        *  -------------------------------------------------*/
        public static void render_resample_argb_bitmap_hq(bitmap_argb32 dest, bitmap_argb32 source, render_color color, bool force = false)
        {
            if (dest.width() == 0 || dest.height() == 0)
            {
                return;
            }

            /* adjust the source base */
            PointerU32 sbase = source.pix(0);  //const u32 *sbase = &source.pix(0);

            /* determine the steppings */
            u32 swidth  = (u32)source.width();
            u32 sheight = (u32)source.height();
            u32 dwidth  = (u32)dest.width();
            u32 dheight = (u32)dest.height();
            u32 dx      = (swidth << 12) / dwidth;
            u32 dy      = (sheight << 12) / dheight;

            /* if the source is higher res than the target, use full averaging */
            if (dx > 0x1000 || dy > 0x1000 || force)
            {
                resample_argb_bitmap_average(dest.pix(0), (u32)dest.rowpixels(), dwidth, dheight, sbase, (u32)source.rowpixels(), swidth, sheight, color, dx, dy);
            }
            else
            {
                resample_argb_bitmap_bilinear(dest.pix(0), (u32)dest.rowpixels(), dwidth, dheight, sbase, (u32)source.rowpixels(), swidth, sheight, color, dx, dy);
            }
        }
示例#2
0
            public static void sha1_process(std.array <uint32_t, u64_const_5> st, PointerU32 data)  //inline void sha1_process(std::array<uint32_t, 5> &st, uint32_t *data)
            {
                std.array <uint32_t, u64_const_5> d = st;
                unsigned i = 0U;

                while (i < 16U)
                {
                    sha1_r0(data, d, i++);
                }
                while (i < 20U)
                {
                    sha1_r1(data, d, i++);
                }
                while (i < 40U)
                {
                    sha1_r2(data, d, i++);
                }
                while (i < 60U)
                {
                    sha1_r3(data, d, i++);
                }
                while (i < 80U)
                {
                    sha1_r4(data, d, i++);
                }
                for (i = 0U; i < 5U; i++)
                {
                    st[i] += d[i];
                }
            }
示例#3
0
            static uint32_t sha1_b(PointerU32 data, unsigned i)
            {
                uint32_t r = data[(i + 13) & 15U];

                r            ^= data[(i + 8) & 15U];
                r            ^= data[(i + 2) & 15U];
                r            ^= data[i & 15U];
                r             = sha1_rol(r, 1);
                data[i & 15U] = r;
                return(r);
            }
示例#4
0
        //-------------------------------------------------
        //  render_triangle - render a triangle that
        //  is used for up/down arrows and left/right
        //  indicators
        //-------------------------------------------------
        static void render_triangle(bitmap_argb32 dest, bitmap_argb32 source, rectangle sbounds, object param)  //void *param)
        {
            int halfwidth = dest.width() / 2;
            int height    = dest.height();

            // start with all-transparent
            dest.fill(new rgb_t(0x00, 0x00, 0x00, 0x00));

            // render from the tip to the bottom
            for (int y = 0; y < height; y++)
            {
                int        linewidth = (y * (halfwidth - 1) + (height / 2)) * 255 * 2 / height;
                PointerU32 target    = dest.pix(y, halfwidth); //uint32_t *const target = &dest.pix(y, halfwidth);

                // don't antialias if height < 12
                if (dest.height() < 12)
                {
                    int pixels = (linewidth + 254) / 255;
                    if (pixels % 2 == 0)
                    {
                        pixels++;
                    }
                    linewidth = pixels * 255;
                }

                // loop while we still have data to generate
                for (int x = 0; linewidth > 0; x++)
                {
                    int dalpha;

                    if (x == 0)
                    {
                        // first column we only consume one pixel
                        dalpha    = std.min(0xff, linewidth);
                        target[x] = new rgb_t((uint8_t)dalpha, 0xff, 0xff, 0xff);  //target[x] = rgb_t(dalpha, 0xff, 0xff, 0xff);
                    }
                    else
                    {
                        // remaining columns consume two pixels, one on each side
                        dalpha    = std.min(0x1fe, linewidth);
                        target[x] = target[-x] = new rgb_t((uint8_t)(dalpha / 2), 0xff, 0xff, 0xff);  //target[x] = target[-x] = rgb_t(dalpha / 2, 0xff, 0xff, 0xff);
                    }

                    // account for the weight we consumed
                    linewidth -= dalpha;
                }
            }
        }
示例#5
0
        public static void load_translation(random_read file)
        {
            MemoryU8   translation_data_buffer;                                                                                                        //std::unique_ptr<std::uint32_t []> translation_data;
            PointerU32 translation_data;                                                                                                               //std::unique_ptr<std::uint32_t []> translation_data;

            std.unordered_map <string, std.pair <string, uint32_t> > translation_map = new std.unordered_map <string, std.pair <string, uint32_t> >(); //std::unordered_map<std::string_view, std::pair<char const *, std::uint32_t> > translation_map;

            uint64_t size = 0;

            if (file.length(out size) || (20 > size))
            {
                osd_printf_error("Error reading translation file: {0}-byte file is too small to contain translation data\n", size);
                return;
            }

            translation_data_buffer = new MemoryU8((int)size + 3, true);  //translation_data.reset(new (std::nothrow) std::uint32_t [(size + 3) / 4]);
            translation_data        = new PointerU32(f_translation_data);
            if (translation_data == null)
            {
                osd_printf_error("Failed to allocate {0} bytes to load translation data file\n", size);
                return;
            }

            size_t read;

            file.read(translation_data, size, out read);
            if (read != size)
            {
                osd_printf_error("Error reading translation file: requested {0} bytes but got {1} bytes\n", size, read);
                translation_data = null;  //translation_data.reset();
                return;
            }

            if ((translation_data[0] != MO_MAGIC) && (translation_data[0] != MO_MAGIC_REVERSED))
            {
                osd_printf_error("Error reading translation file: unrecognized magic number {0}\n", translation_data[0]); //0x%08X
                translation_data = null;                                                                                  //translation_data.reset();
                return;
            }

            var fetch_word = new Func <size_t, uint32_t>(
                (size_t offset) =>     //[reversed = translation_data[0] == MO_MAGIC_REVERSED, words = translation_data.get()] (size_t offset)
            {
                var reversed = translation_data[0] == MO_MAGIC_REVERSED;
                var words    = translation_data;

                return(reversed ? swapendian_int32(words[offset]) : words[offset]);
            });

            // FIXME: check major/minor version number

            if ((fetch_word(3) % 4) != 0 || (fetch_word(4) % 4) != 0)
            {
                osd_printf_error("Error reading translation file: table offsets {0} and {1} are not word-aligned\n", fetch_word(3), fetch_word(4));
                translation_data = null;  //translation_data.reset();
                return;
            }

            uint32_t number_of_strings        = fetch_word(2);
            uint32_t original_table_offset    = fetch_word(3) >> 2;
            uint32_t translation_table_offset = fetch_word(4) >> 2;

            if ((4 * (original_table_offset + ((uint64_t)number_of_strings * 2))) > size)
            {
                osd_printf_error("Error reading translation file: {0}-entry original string table at offset {1} extends past end of {2}-byte file\n", number_of_strings, fetch_word(3), size);
                translation_data = null;  //translation_data.reset();
                return;
            }

            if ((4 * (translation_table_offset + ((uint64_t)number_of_strings * 2))) > size)
            {
                osd_printf_error("Error reading translation file: {0}-entry translated string table at offset {1} extends past end of {2}-byte file\n", number_of_strings, fetch_word(4), size);
                translation_data = null;  //translation_data.reset();
                return;
            }

            osd_printf_verbose("Reading translation file: {0} strings, original table at word offset {1}, translated table at word offset {2}\n", number_of_strings, original_table_offset, translation_table_offset);

            PointerU8 data = new PointerU8(translation_data);  //char const *const data = reinterpret_cast<char const *>(translation_data.get());

            for (uint32_t i = 1; number_of_strings > i; ++i)
            {
                uint32_t original_length = fetch_word(original_table_offset + (2 * i));
                uint32_t original_offset = fetch_word(original_table_offset + (2 * i) + 1);
                if ((original_length + original_offset) >= size)
                {
                    osd_printf_error("Error reading translation file: {0}-byte original string {1} at offset {2} extends past end of {3}-byte file\n", original_length, i, original_offset, size);
                    continue;
                }

                if (data[original_length + original_offset] != 0)
                {
                    osd_printf_error("Error reading translation file: {0}-byte original string {1} at offset {2} is not correctly NUL-terminated\n", original_length, i, original_offset);
                    continue;
                }

                uint32_t translation_length = fetch_word(translation_table_offset + (2 * i));
                uint32_t translation_offset = fetch_word(translation_table_offset + (2 * i) + 1);
                if ((translation_length + translation_offset) >= size)
                {
                    osd_printf_error("Error reading translation file: {0}-byte translated string {1} at offset {2} extends past end of {3}-byte file\n", translation_length, i, translation_offset, size);
                    continue;
                }

                if (data[translation_length + translation_offset] != 0)
                {
                    osd_printf_error("Error reading translation file: {0}-byte translated string {1} at offset {2} is not correctly NUL-terminated\n", translation_length, i, translation_offset);
                    continue;
                }

                string original    = data.ToString((int)original_offset, int.MaxValue);                                 //std::string_view const original(&data[original_offset], original_length);
                string translation = data.ToString((int)translation_offset, int.MaxValue);                              //char const *const translation(&data[translation_offset]);
                var    ins         = translation_map.emplace(original, std.make_pair(translation, translation_length)); //auto const ins = translation_map.emplace(original, std::make_pair(translation, translation_length));
                if (!ins)
                {
                    osd_printf_warning(
                        "Loading translation file: translation {0} '{1}'='{2}' conflicts with previous translation '{3}'='{4}'\n",
                        i,
                        original,
                        translation,
                        null,      //ins.first->first,
                        null);     //ins.first->second.first);
                }
            }

            osd_printf_verbose("Loaded {0} translated string from file\n", translation_map.size());
            f_translation_data = translation_data;
            f_translation_map  = translation_map;
        }
示例#6
0
        // updates
        //void animate(u16 auto_time);
        //void draw(render_container &container, u8 fade);


        // private helpers
        //-------------------------------------------------
        //  create_bitmap - create the rendering
        //  structures for the given player
        //-------------------------------------------------
        void create_bitmap()
        {
            rgb_t color = m_player < (int)std.size(crosshair_colors) ? crosshair_colors[m_player] : rgb_t.white();

            // if we have a bitmap and texture for this player, kill it
            if (m_bitmap == null)
            {
                m_bitmap  = new bitmap_argb32();
                m_texture = m_machine.render().texture_alloc(render_texture.hq_scale);
            }
            else
            {
                m_bitmap.reset();
            }

            emu_file crossfile = new emu_file(m_machine.options().crosshair_path(), OPEN_FLAG_READ);

            if (!m_name.empty())
            {
                // look for user specified file
                if (!crossfile.open(m_name + ".png"))
                {
                    render_load_png(out m_bitmap, crossfile.core_file_get());
                    crossfile.close();
                }
            }
            else
            {
                // look for default cross?.png in crsshair/game dir
                string filename = util.string_format("cross{0}.png", m_player + 1);
                if (!crossfile.open(m_machine.system().name + (PATH_SEPARATOR + filename)))
                {
                    render_load_png(out m_bitmap, crossfile.core_file_get());
                    crossfile.close();
                }

                // look for default cross?.png in crsshair dir
                if (!m_bitmap.valid() && !crossfile.open(filename))
                {
                    render_load_png(out m_bitmap, crossfile.core_file_get());
                    crossfile.close();
                }
            }

            /* if that didn't work, use the built-in one */
            if (!m_bitmap.valid())
            {
                /* allocate a blank bitmap to start with */
                m_bitmap.allocate(CROSSHAIR_RAW_SIZE, CROSSHAIR_RAW_SIZE);
                m_bitmap.fill(new rgb_t(0x00, 0xff, 0xff, 0xff));

                /* extract the raw source data to it */
                for (int y = 0; y < CROSSHAIR_RAW_SIZE / 2; y++)
                {
                    /* assume it is mirrored vertically */
                    PointerU32 dest0 = m_bitmap.pix(y);                          //u32 *dest0 = &m_bitmap->pix(y);
                    PointerU32 dest1 = m_bitmap.pix(CROSSHAIR_RAW_SIZE - 1 - y); //u32 *dest1 = &m_bitmap->pix(CROSSHAIR_RAW_SIZE - 1 - y);

                    /* extract to two rows simultaneously */
                    for (int x = 0; x < CROSSHAIR_RAW_SIZE; x++)
                    {
                        if (((crosshair_raw_top[y * CROSSHAIR_RAW_ROWBYTES + x / 8] << (x % 8)) & 0x80) != 0)
                        {
                            dest0[x] = dest1[x] = new rgb_t(0xff, 0x00, 0x00, 0x00) | color;
                        }
                    }
                }
            }

            /* reference the new bitmap */
            m_texture.set_bitmap(m_bitmap, m_bitmap.cliprect(), texture_format.TEXFORMAT_ARGB32);
        }
示例#7
0
        /*-------------------------------------------------
        *   resample_argb_bitmap_bilinear - perform texture
        *   sampling via a bilinear filter
        *  -------------------------------------------------*/
        static void resample_argb_bitmap_bilinear(PointerU32 dest, u32 drowpixels, u32 dwidth, u32 dheight, PointerU32 source, u32 srowpixels, u32 swidth, u32 sheight, render_color color, u32 dx, u32 dy)  //static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy)
        {
            u32 maxx = swidth << 12;
            u32 maxy = sheight << 12;
            u32 r;
            u32 g;
            u32 b;
            u32 a;
            u32 x;
            u32 y;

            /* precompute premultiplied R/G/B/A factors */
            r = (u32)(color.r * color.a * 256.0f);
            g = (u32)(color.g * color.a * 256.0f);
            b = (u32)(color.b * color.a * 256.0f);
            a = (u32)(color.a * 256.0f);

            /* loop over the target vertically */
            for (y = 0; y < dheight; y++)
            {
                u32 starty = y * dy;

                /* loop over the target horizontally */
                for (x = 0; x < dwidth; x++)
                {
                    u32   startx = x * dx;
                    rgb_t pix0;
                    rgb_t pix1;
                    rgb_t pix2;
                    rgb_t pix3;
                    u32   sumr;
                    u32   sumg;
                    u32   sumb;
                    u32   suma;
                    u32   nextx;
                    u32   nexty;
                    u32   curx;
                    u32   cury;
                    u32   factor;

                    /* adjust start to the center; note that this math will tend to produce */
                    /* negative results on the first pixel, which is why we clamp below */
                    curx = startx + dx / 2 - 0x800;
                    cury = starty + dy / 2 - 0x800;

                    /* compute the neighboring pixel */
                    nextx = curx + 0x1000;
                    nexty = cury + 0x1000;

                    /* fetch the four relevant pixels */
                    pix0 = pix1 = pix2 = pix3 = new rgb_t(0);
                    if ((int)cury >= 0 && cury < maxy && (int)curx >= 0 && curx < maxx)
                    {
                        pix0 = new rgb_t(source[(cury >> 12) * srowpixels + (curx >> 12)]);  //pix0 = source[(cury >> 12) * srowpixels + (curx >> 12)];
                    }
                    if ((int)cury >= 0 && cury < maxy && (int)nextx >= 0 && nextx < maxx)
                    {
                        pix1 = new rgb_t(source[(cury >> 12) * srowpixels + (nextx >> 12)]);  //pix1 = source[(cury >> 12) * srowpixels + (nextx >> 12)];
                    }
                    if ((int)nexty >= 0 && nexty < maxy && (int)curx >= 0 && curx < maxx)
                    {
                        pix2 = new rgb_t(source[(nexty >> 12) * srowpixels + (curx >> 12)]);  //pix2 = source[(nexty >> 12) * srowpixels + (curx >> 12)];
                    }
                    if ((int)nexty >= 0 && nexty < maxy && (int)nextx >= 0 && nextx < maxx)
                    {
                        pix3 = new rgb_t(source[(nexty >> 12) * srowpixels + (nextx >> 12)]);  //pix3 = source[(nexty >> 12) * srowpixels + (nextx >> 12)];
                    }
                    /* compute the x/y scaling factors */
                    curx &= 0xfff;
                    cury &= 0xfff;

                    /* contributions from pixel 0 (top,left) */
                    factor = (0x1000 - curx) * (0x1000 - cury);
                    sumr   = factor * pix0.r();
                    sumg   = factor * pix0.g();
                    sumb   = factor * pix0.b();
                    suma   = factor * pix0.a();

                    /* contributions from pixel 1 (top,right) */
                    factor = curx * (0x1000 - cury);
                    sumr  += factor * pix1.r();
                    sumg  += factor * pix1.g();
                    sumb  += factor * pix1.b();
                    suma  += factor * pix1.a();

                    /* contributions from pixel 2 (bottom,left) */
                    factor = (0x1000 - curx) * cury;
                    sumr  += factor * pix2.r();
                    sumg  += factor * pix2.g();
                    sumb  += factor * pix2.b();
                    suma  += factor * pix2.a();

                    /* contributions from pixel 3 (bottom,right) */
                    factor = curx * cury;
                    sumr  += factor * pix3.r();
                    sumg  += factor * pix3.g();
                    sumb  += factor * pix3.b();
                    suma  += factor * pix3.a();

                    /* apply scaling */
                    suma = (suma >> 24) * a / 256;
                    sumr = (sumr >> 24) * r / 256;
                    sumg = (sumg >> 24) * g / 256;
                    sumb = (sumb >> 24) * b / 256;

                    /* if we're translucent, add in the destination pixel contribution */
                    if (a < 256)
                    {
                        rgb_t dpix = new rgb_t(dest[y * drowpixels + x]);  //rgb_t dpix = dest[y * drowpixels + x];
                        suma += dpix.a() * (256 - a);
                        sumr += dpix.r() * (256 - a);
                        sumg += dpix.g() * (256 - a);
                        sumb += dpix.b() * (256 - a);
                    }

                    /* store the target pixel, dividing the RGBA values by the overall scale factor */
                    dest[y * drowpixels + x] = new rgb_t((u8)suma, (u8)sumr, (u8)sumg, (u8)sumb);  //dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb);
                }
            }
        }
示例#8
0
        /*-------------------------------------------------
        *   resample_argb_bitmap_average - resample a texture
        *   by performing a true weighted average over
        *   all contributing pixels
        *  -------------------------------------------------*/
        static void resample_argb_bitmap_average(PointerU32 dest, u32 drowpixels, u32 dwidth, u32 dheight, PointerU32 source, u32 srowpixels, u32 swidth, u32 sheight, render_color color, u32 dx, u32 dy)  //static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy)
        {
            u64 sumscale = (u64)dx * (u64)dy;
            u32 r;
            u32 g;
            u32 b;
            u32 a;
            u32 x;
            u32 y;

            /* precompute premultiplied R/G/B/A factors */
            r = (u32)(color.r * color.a * 256.0f);
            g = (u32)(color.g * color.a * 256.0f);
            b = (u32)(color.b * color.a * 256.0f);
            a = (u32)(color.a * 256.0f);

            /* loop over the target vertically */
            for (y = 0; y < dheight; y++)
            {
                u32 starty = y * dy;

                /* loop over the target horizontally */
                for (x = 0; x < dwidth; x++)
                {
                    u64 sumr   = 0;
                    u64 sumg   = 0;
                    u64 sumb   = 0;
                    u64 suma   = 0;
                    u32 startx = x * dx;
                    u32 xchunk;
                    u32 ychunk;
                    u32 curx;
                    u32 cury;

                    u32 yremaining = dy;

                    /* accumulate all source pixels that contribute to this pixel */
                    for (cury = starty; yremaining != 0; cury += ychunk)
                    {
                        u32 xremaining = dx;

                        /* determine the Y contribution, clamping to the amount remaining */
                        ychunk = 0x1000 - (cury & 0xfff);
                        if (ychunk > yremaining)
                        {
                            ychunk = yremaining;
                        }
                        yremaining -= ychunk;

                        /* loop over all source pixels in the X direction */
                        for (curx = startx; xremaining != 0; curx += xchunk)
                        {
                            u32 factor;

                            /* determine the X contribution, clamping to the amount remaining */
                            xchunk = 0x1000 - (curx & 0xfff);
                            if (xchunk > xremaining)
                            {
                                xchunk = xremaining;
                            }
                            xremaining -= xchunk;

                            /* total contribution = x * y */
                            factor = xchunk * ychunk;

                            /* fetch the source pixel */
                            rgb_t pix = new rgb_t(source[(cury >> 12) * srowpixels + (curx >> 12)]);  //rgb_t pix = source[(cury >> 12) * srowpixels + (curx >> 12)];

                            /* accumulate the RGBA values */
                            sumr += factor * pix.r();
                            sumg += factor * pix.g();
                            sumb += factor * pix.b();
                            suma += factor * pix.a();
                        }
                    }

                    /* apply scaling */
                    suma = (suma / sumscale) * a / 256;
                    sumr = (sumr / sumscale) * r / 256;
                    sumg = (sumg / sumscale) * g / 256;
                    sumb = (sumb / sumscale) * b / 256;

                    /* if we're translucent, add in the destination pixel contribution */
                    if (a < 256)
                    {
                        rgb_t dpix = new rgb_t(dest[y * drowpixels + x]);  //rgb_t dpix = dest[y * drowpixels + x];
                        suma += dpix.a() * (256 - a);
                        sumr += dpix.r() * (256 - a);
                        sumg += dpix.g() * (256 - a);
                        sumb += dpix.b() * (256 - a);
                    }

                    /* store the target pixel, dividing the RGBA values by the overall scale factor */
                    dest[y * drowpixels + x] = new rgb_t((u8)suma, (u8)sumr, (u8)sumg, (u8)sumb);  //dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb);
                }
            }
        }
示例#9
0
 static void sha1_r4(PointerU32 data, std.array <uint32_t, u64_const_5> d, unsigned i)  //inline void sha1_r4(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i)
 {
     d[i % 5]       = d[i % 5] + (d[(i + 3) % 5] ^ d[(i + 2) % 5] ^ d[(i + 1) % 5]) + sha1_b(data, i) + 0xca62c1d6U + sha1_rol(d[(i + 4) % 5], 5);
     d[(i + 3) % 5] = sha1_rol(d[(i + 3) % 5], 30);
 }
示例#10
0
 static void sha1_r3(PointerU32 data, std.array <uint32_t, u64_const_5> d, unsigned i)  //inline void sha1_r3(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i)
 {
     d[i % 5]       = d[i % 5] + (((d[(i + 3) % 5] | d[(i + 2) % 5]) & d[(i + 1) % 5]) | (d[(i + 3) % 5] & d[(i + 2) % 5])) + sha1_b(data, i) + 0x8f1bbcdcU + sha1_rol(d[(i + 4) % 5], 5);
     d[(i + 3) % 5] = sha1_rol(d[(i + 3) % 5], 30);
 }
示例#11
0
 static void sha1_r0(PointerU32 data, std.array <uint32_t, u64_const_5> d, unsigned i)  //inline void sha1_r0(const uint32_t *data, std::array<uint32_t, 5> &d, unsigned i)
 {
     d[i % 5]       = d[i % 5] + ((d[(i + 3) % 5] & (d[(i + 2) % 5] ^ d[(i + 1) % 5])) ^ d[(i + 1) % 5]) + data[i] + 0x5a827999U + sha1_rol(d[(i + 4) % 5], 5);
     d[(i + 3) % 5] = sha1_rol(d[(i + 3) % 5], 30);
 }
示例#12
0
        //-------------------------------------------------
        //  char_expand - expand the raw data for a
        //  character into a bitmap
        //-------------------------------------------------
        void char_expand(char32_t chnum, glyph gl)
        {
            LOG("render_font::char_expand: expanding character {0}\n", chnum);

            rgb_t fgcol  = (gl.color != 0 ? gl.color : new rgb_t(0xff, 0xff, 0xff, 0xff));
            rgb_t bgcol  = new rgb_t(0x00, 0xff, 0xff, 0xff);
            bool  is_cmd = ((chnum >= COMMAND_UNICODE) && (chnum < COMMAND_UNICODE + MAX_GLYPH_FONT));

            if (is_cmd)
            {
                throw new emu_unimplemented();
#if false
                // punt if nothing there
                if (gl.bmwidth == 0 || gl.bmheight == 0 || gl.rawdata == null)
                {
                    return;
                }

                // allocate a new bitmap of the size we need
                gl.bitmap.allocate(gl.bmwidth, m_height_cmd);
                gl.bitmap.fill(0);

                // extract the data
                const char *ptr      = gl.rawdata;
                byte        accum    = 0;
                byte        accumbit = 7;
                for (int y = 0; y < gl.bmheight; y++)
                {
                    int  desty = y + m_height_cmd + m_yoffs_cmd - gl.yoffs - gl.bmheight;
                    u32 *dest  = (desty >= 0 && desty < m_height_cmd) ? &gl.bitmap.pix(desty, 0) : nullptr;
                    {
                        for (int x = 0; x < gl.bmwidth; x++)
                        {
                            if (accumbit == 7)
                            {
                                accum = *ptr++;
                            }
                            if (dest != null)
                            {
                                *dest++ = (accum & (1 << accumbit)) ? color : rgb_t(0x00, 0xff, 0xff, 0xff);
                            }
                            accumbit = (accumbit - 1) & 7;
                        }
                    }
                }
#endif
            }
            else if (m_format == format.OSD)
            {
                throw new emu_unimplemented();
#if false
                // if we're an OSD font, query the info
#endif
            }
            else if (gl.bmwidth == 0 || gl.bmheight == 0 || gl.rawdata == null)
            {
                // abort if nothing there
                LOG("render_font::char_expand: empty bitmap bounds or no raw data\n");
                return;
            }
            else
            {
                // other formats need to parse their data
                LOG("render_font::char_expand: building bitmap from raw data\n");

                // allocate a new bitmap of the size we need
                gl.bitmap.allocate(gl.bmwidth, m_height);
                gl.bitmap.fill(0);

                // extract the data
                Pointer <u8> ptr      = new Pointer <u8>(gl.rawdata); //const char *ptr = gl.rawdata;
                u8           accum    = 0;
                u8           accumbit = 7;
                for (int y = 0; y < gl.bmheight; y++)
                {
                    int        desty = y + m_height + m_yoffs - gl.yoffs - gl.bmheight;
                    PointerU32 dest  = ((0 <= desty) && (m_height > desty)) ? gl.bitmap.pix(desty) : null; //u32 *dest(((0 <= desty) && (m_height > desty)) ? &gl.bitmap.pix(desty) : nullptr);

                    if (m_format == format.TEXT)
                    {
                        if (dest != null)
                        {
                            for (int x = 0; gl.bmwidth > x;)
                            {
                                // scan for the next hex digit
                                int bits = -1;
                                while ('\r' != ptr[0] && '\n' != ptr[0] && 0 > bits)  // while (('\r' != *ptr) && ('\n' != *ptr) && (0 > bits))
                                {
                                    if (ptr[0] >= '0' && ptr[0] <= '9')
                                    {
                                        bits = ptr[0] - '0';  //bits = *ptr++ - '0';
                                        ptr++;
                                    }
                                    else if (ptr[0] >= 'A' && ptr[0] <= 'F')
                                    {
                                        bits = ptr[0] - 'A' + 10;
                                        ptr++;
                                    }
                                    else if (ptr[0] >= 'a' && ptr[0] <= 'f')
                                    {
                                        bits = ptr[0] - 'a' + 10;
                                        ptr++;
                                    }
                                    else
                                    {
                                        ptr++;
                                    }
                                }

                                // expand the four bits
                                dest[0] = (bits & 8) != 0 ? fgcol : bgcol;  dest++;  //*dest++ = (bits & 8) ? fgcol : bgcol;
                                if (gl.bmwidth > ++x)
                                {
                                    dest[0] = (bits & 4) != 0 ? fgcol : bgcol;  dest++;
                                }                                                            //*dest++ = (bits & 4) ? fgcol : bgcol;
                                if (gl.bmwidth > ++x)
                                {
                                    dest[0] = (bits & 2) != 0 ? fgcol : bgcol;  dest++;
                                }                                                            //*dest++ = (bits & 2) ? fgcol : bgcol;
                                if (gl.bmwidth > ++x)
                                {
                                    dest[0] = (bits & 1) != 0 ? fgcol : bgcol;  dest++;
                                }                                                            //*dest++ = (bits & 1) ? fgcol : bgcol;

                                x++;
                            }

                            // advance to the next line
                            ptr = next_line(ptr);
                        }
                    }
                    else if (m_format == format.CACHED)
                    {
                        for (int x = 0; x < gl.bmwidth; x++)
                        {
                            if (accumbit == 7)
                            {
                                accum = ptr[0];
                                ptr++;
                            }

                            if (dest != null)
                            {
                                dest[0] = (accum & (1 << accumbit)) != 0 ? fgcol : bgcol;  dest++;
                            }                                                                           //*dest++ = (accum & (1 << accumbit)) ? fgcol : bgcol;

                            accumbit = (u8)((accumbit - 1) & 7);
                        }
                    }
                }
            }

            // wrap a texture around the bitmap
            gl.texture = m_manager.texture_alloc(render_texture.hq_scale);
            gl.texture.set_bitmap(gl.bitmap, gl.bitmap.cliprect(), texture_format.TEXFORMAT_ARGB32);
        }