try
        {
            find_min_single_variable(f, x, 0, 1, 1e-9);
            DLIB_TEST(std::abs(x-0.2) < 1e-7);
        }
        catch(optimize_single_variable_failure&)
        {
            DLIB_TEST(false);
        }

#include "optimization_test_functions.h"
#include <dlib/optimization.h>
#include <dlib/statistics.h>
#include <sstream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <vector>
#include "../stl_checked.h"
#include "../array.h"
#include "../rand.h"

#include "tester.h"

namespace
{

    using namespace test;
    using namespace dlib;
    using namespace std;

    logger dlog("test.optimization");

    bool approx_equal (
        double a,
        double b
    )
    {
        return std::abs(a - b) < 100*std::numeric_limits<double>::epsilon();
    }

    long total_count = 0;

    template <typename T>
    double apq ( const T& x)
    {
        DLIB_ASSERT(x.nr() > 1 && x.nc() == 1,"");
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        double temp = 0;
        for (long r = 0; r < x.nr(); ++r)
        {
            temp += (r+1)*x(r)*x(r);
        }

        ++total_count;

        return temp + 1/100.0*(x(0) + x(x.nr()-1))*(x(0) + x(x.nr()-1));
    }

    template <typename T>
    T der_apq ( const T& x)
    {
        DLIB_ASSERT(x.nr() > 1 && x.nc() == 1,"");
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        T temp(x.nr());
        for (long r = 0; r < x.nr(); ++r)
        {
            temp(r) = 2*(r+1)*x(r) ;
        }

        temp(0) += 1/50.0*(x(0) + x(x.nr()-1));
        temp(x.nr()-1) += 1/50.0*(x(0) + x(x.nr()-1));

        ++total_count;

        return temp;
    }

    double rosen ( const matrix<double,2,1>& x)
    {
        ++total_count;
        return 100*pow(x(1) - x(0)*x(0),2) + pow(1 - x(0),2);
    }

    matrix<double,2,1> der_rosen ( const matrix<double,2,1>& x)
    {
        ++total_count;
        matrix<double,2,1> res;
        res(0) = -400*x(0)*(x(1)-x(0)*x(0)) - 2*(1-x(0));
        res(1) = 200*(x(1)-x(0)*x(0));
        return res;
    }

    // negative of Rosenbrock's function.  minimum at (1,1)
    double neg_rosen ( const matrix<double,2,1>& x)
    {
        ++total_count;
        return -(100*pow(x(1) - x(0)*x(0),2) + pow(1 - x(0),2));
    }

    matrix<double,2,1> der_neg_rosen ( const matrix<double,2,1>& x)
    {
        ++total_count;
        matrix<double,2,1> res;
        res(0) = -400*x(0)*(x(1)-x(0)*x(0)) - 2*(1-x(0));
        res(1) = 200*(x(1)-x(0)*x(0));
        return -res;
    }

    double simple ( const matrix<double,2,1>& x)
    {
        ++total_count;
        return 10*x(0)*x(0) + x(1)*x(1);
    }

    matrix<double,2,1> der_simple ( const matrix<double,2,1>& x)
    {
        ++total_count;
        matrix<double,2,1> res;
        res(0) = 20*x(0);
        res(1) = 2*x(1);
        return res;
    }

    double powell ( const matrix<double,4,1>& x)
    {
        ++total_count;
        return pow(x(0) + 10*x(1),2) +
            pow(std::sqrt(5.0)*(x(2) - x(3)),2) +
            pow((x(1) - 2*x(2))*(x(1) - 2*x(2)),2) +
            pow(std::sqrt(10.0)*(x(0) - x(3))*(x(0) - x(3)),2);
    }

// a simple function with a minimum at zero
    double single_variable_function ( double x)
    {
        ++total_count;
        return 3*x*x + 5;
    }

    void test_apq (
        const matrix<double,0,1> p
    )
    {
        typedef matrix<double,0,1> T;
        const double eps = 1e-12;
        const double minf = -10;
        matrix<double,0,1> x(p.nr()), opt(p.nr());
        set_all_elements(opt, 0);
        double val = 0;

        if (p.size() < 20)
            dlog << LINFO << "testing with apq and the start point: " << trans(p);
        else
            dlog << LINFO << "testing with apq and a big vector with " << p.size() << " components.";

        // don't use bfgs on really large vectors
        if (p.size() < 20)
        {
            total_count = 0;
            x = p;
            val = find_min(bfgs_search_strategy(),
                     objective_delta_stop_strategy(eps),
                     wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            DLIB_TEST(approx_equal(val , apq(x)));
            dlog << LINFO << "find_min() bgfs: got apq in " << total_count;

            total_count = 0;
            x = p;
            find_min(bfgs_search_strategy(),
                     gradient_norm_stop_strategy(),
                     wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            dlog << LINFO << "find_min() bgfs(gn): got apq in " << total_count;
        }

        if (p.size() < 100)
        {
            total_count = 0;
            x = p;
            val=find_min_bobyqa(wrap_function(apq<T>), x, 2*x.size()+1,
                            uniform_matrix<double>(x.size(),1,-1e100),
                            uniform_matrix<double>(x.size(),1,1e100),
                            (max(abs(x))+1)/10,
                            1e-6,
                            10000);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            DLIB_TEST(approx_equal(val , apq(x)));
            dlog << LINFO << "find_min_bobyqa(): got apq in " << total_count;
        }

        total_count = 0;
        x = p;
        val=find_min(lbfgs_search_strategy(10),
                 objective_delta_stop_strategy(eps),
                 wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , apq(x)));
        dlog << LINFO << "find_min() lbgfs-10: got apq in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(lbfgs_search_strategy(1),
                 objective_delta_stop_strategy(eps),
                 wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , apq(x)));
        dlog << LINFO << "find_min() lbgfs-1: got apq in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(cg_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 wrap_function(apq<T>), wrap_function(der_apq<T>), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , apq(x)));
        dlog << LINFO << "find_min() cg: got apq in " << total_count;

        // don't do approximate derivative tests if the input point is really long
        if (p.size() < 20)
        {
            total_count = 0;
            x = p;
            val=find_min(bfgs_search_strategy(),
                     objective_delta_stop_strategy(eps),
                     wrap_function(apq<T>), derivative(wrap_function(apq<T>)), x, minf);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            DLIB_TEST(approx_equal(val , apq(x)));
            dlog << LINFO << "find_min() bfgs: got apq/noder in " << total_count;

            total_count = 0;
            x = p;
            val=find_min(cg_search_strategy(),
                     objective_delta_stop_strategy(eps),
                     wrap_function(apq<T>), derivative(wrap_function(apq<T>)), x, minf);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            DLIB_TEST(approx_equal(val , apq(x)));
            dlog << LINFO << "find_min() cg: got apq/noder in " << total_count;

            total_count = 0;
            x = p;
            val=find_min_using_approximate_derivatives(bfgs_search_strategy(),
                                                   objective_delta_stop_strategy(eps),
                                                   wrap_function(apq<T>), x, minf);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            DLIB_TEST(approx_equal(val , apq(x)));
            dlog << LINFO << "find_min() bfgs: got apq/noder2 in " << total_count;

            total_count = 0;
            x = p;
            val=find_min_using_approximate_derivatives(lbfgs_search_strategy(10),
                                                   objective_delta_stop_strategy(eps),
                                                   wrap_function(apq<T>), x, minf);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            dlog << LINFO << "find_min() lbfgs-10: got apq/noder2 in " << total_count;

            total_count = 0;
            x = p;
            val=find_min_using_approximate_derivatives(cg_search_strategy(),
                                                   objective_delta_stop_strategy(eps),
                                                   wrap_function(apq<T>), x, minf);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            DLIB_TEST(approx_equal(val , apq(x)));
            dlog << LINFO << "find_min() cg: got apq/noder2 in " << total_count;
        }
    }

    void test_powell (
        const matrix<double,4,1> p
    )
    {
        const double eps = 1e-15;
        const double minf = -1;
        matrix<double,4,1> x, opt;
        opt(0) = 0;
        opt(1) = 0;
        opt(2) = 0;
        opt(3) = 0;

        double val = 0;

        dlog << LINFO << "testing with powell and the start point: " << trans(p);

        /*
        total_count = 0;
        x = p;
        val=find_min(bfgs_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 powell, derivative(powell,1e-8), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-2),opt-x);
        DLIB_TEST(approx_equal(val , powell(x)));
        dlog << LINFO << "find_min() bfgs: got powell/noder in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(cg_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 powell, derivative(powell,1e-9), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-2),opt-x);
        DLIB_TEST(approx_equal(val , powell(x)));
        dlog << LINFO << "find_min() cg: got powell/noder in " << total_count;
        */

        total_count = 0;
        x = p;
        val=find_min_using_approximate_derivatives(bfgs_search_strategy(),
                                               objective_delta_stop_strategy(eps),
                                               powell, x, minf, 1e-10);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x);
        DLIB_TEST(approx_equal(val , powell(x)));
        dlog << LINFO << "find_min() bfgs: got powell/noder2 in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_using_approximate_derivatives(lbfgs_search_strategy(4),
                                               objective_delta_stop_strategy(eps),
                                               powell, x, minf, 1e-10);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x);
        DLIB_TEST(approx_equal(val , powell(x)));
        dlog << LINFO << "find_min() lbfgs-4: got powell/noder2 in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_using_approximate_derivatives(lbfgs_search_strategy(4),
                                               gradient_norm_stop_strategy(),
                                               powell, x, minf, 1e-10);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x);
        DLIB_TEST(approx_equal(val , powell(x)));
        dlog << LINFO << "find_min() lbfgs-4(gn): got powell/noder2 in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_using_approximate_derivatives(cg_search_strategy(),
                                               objective_delta_stop_strategy(eps),
                                               powell, x, minf, 1e-10);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x);
        DLIB_TEST(approx_equal(val , powell(x)));
        dlog << LINFO << "find_min() cg: got powell/noder2 in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_bobyqa(powell, x, 2*x.size()+1,
                        uniform_matrix<double>(x.size(),1,-1e100),
                        uniform_matrix<double>(x.size(),1,1e100),
                        (max(abs(x))+1)/10,
                        1e-8,
                        10000);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-3),opt-x);
        DLIB_TEST(approx_equal(val , powell(x)));
        dlog << LINFO << "find_min_bobyqa(): got powell in " << total_count;

    }

    void test_simple (
        const matrix<double,2,1> p
    )
    {
        const double eps = 1e-12;
        const double minf = -10000;
        matrix<double,2,1> x, opt;
        opt(0) = 0;
        opt(1) = 0;
        double val = 0;

        dlog << LINFO << "testing with simple and the start point: " << trans(p);

        total_count = 0;
        x = p;
        val=find_min(bfgs_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 simple, der_simple, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() bfgs: got simple in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(bfgs_search_strategy(),
                 gradient_norm_stop_strategy(),
                 simple, der_simple, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() bfgs(gn): got simple in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(lbfgs_search_strategy(3),
                 objective_delta_stop_strategy(eps),
                 simple, der_simple, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() lbfgs-3: got simple in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(cg_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 simple, der_simple, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() cg: got simple in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(bfgs_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 simple, derivative(simple), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() bfgs: got simple/noder in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(lbfgs_search_strategy(8),
                 objective_delta_stop_strategy(eps),
                 simple, derivative(simple), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() lbfgs-8: got simple/noder in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(cg_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 simple, derivative(simple), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() cg: got simple/noder in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_using_approximate_derivatives(bfgs_search_strategy(),
                                               objective_delta_stop_strategy(eps),
                                               simple, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() bfgs: got simple/noder2 in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_using_approximate_derivatives(lbfgs_search_strategy(6),
                                               objective_delta_stop_strategy(eps),
                                               simple, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() lbfgs-6: got simple/noder2 in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_using_approximate_derivatives(cg_search_strategy(),
                                               objective_delta_stop_strategy(eps),
                                               simple, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min() cg: got simple/noder2 in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_bobyqa(simple, x, 2*x.size()+1,
                        uniform_matrix<double>(x.size(),1,-1e100),
                        uniform_matrix<double>(x.size(),1,1e100),
                        (max(abs(x))+1)/10,
                        1e-6,
                        10000);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , simple(x)));
        dlog << LINFO << "find_min_bobyqa(): got simple in " << total_count;

    }

    void test_rosen (
        const matrix<double,2,1> p
    )
    {
        const double eps = 1e-15;
        const double minf = -10;
        matrix<double,2,1> x, opt;
        opt(0) = 1;
        opt(1) = 1;

        double val = 0;

        dlog << LINFO << "testing with rosen and the start point: " << trans(p);

        total_count = 0;
        x = p;
        val=find_min(bfgs_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 rosen, der_rosen, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
        DLIB_TEST(approx_equal(val , rosen(x)));
        dlog << LINFO << "find_min() bfgs: got rosen in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(bfgs_search_strategy(),
                 gradient_norm_stop_strategy(),
                 rosen, der_rosen, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
        DLIB_TEST(approx_equal(val , rosen(x)));
        dlog << LINFO << "find_min() bfgs(gn): got rosen in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(lbfgs_search_strategy(20),
                 objective_delta_stop_strategy(eps),
                 rosen, der_rosen, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
        DLIB_TEST(approx_equal(val , rosen(x)));
        dlog << LINFO << "find_min() lbfgs-20: got rosen in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(cg_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 rosen, der_rosen, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
        DLIB_TEST(approx_equal(val , rosen(x)));
        dlog << LINFO << "find_min() cg: got rosen in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(bfgs_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 rosen, derivative(rosen,1e-5), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x);
        DLIB_TEST(approx_equal(val , rosen(x)));
        dlog << LINFO << "find_min() bfgs: got rosen/noder in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(lbfgs_search_strategy(5),
                 objective_delta_stop_strategy(eps),
                 rosen, derivative(rosen,1e-5), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x);
        DLIB_TEST(approx_equal(val , rosen(x)));
        dlog << LINFO << "find_min() lbfgs-5: got rosen/noder in " << total_count;

        total_count = 0;
        x = p;
        val=find_min(cg_search_strategy(),
                 objective_delta_stop_strategy(eps),
                 rosen, derivative(rosen,1e-5), x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x);
        DLIB_TEST(approx_equal(val , rosen(x)));
        dlog << LINFO << "find_min() cg: got rosen/noder in " << total_count;

        total_count = 0;
        x = p;
        val=find_min_using_approximate_derivatives(cg_search_strategy(),
                                               objective_delta_stop_strategy(eps),
                                               rosen, x, minf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x);
        DLIB_TEST(approx_equal(val , rosen(x)));
        dlog << LINFO << "find_min() cg: got rosen/noder2 in " << total_count;

        if (max(abs(p)) < 1000)
        {
            total_count = 0;
            x = p;
            val=find_min_bobyqa(rosen, x, 2*x.size()+1,
                            uniform_matrix<double>(x.size(),1,-1e100),
                            uniform_matrix<double>(x.size(),1,1e100),
                            (max(abs(x))+1)/10,
                            1e-6,
                            10000);
            DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
            DLIB_TEST(approx_equal(val , rosen(x)));
            dlog << LINFO << "find_min_bobyqa(): got rosen in " << total_count;
        }
    }

    void test_neg_rosen (
        const matrix<double,2,1> p
    )
    {
        const double eps = 1e-15;
        const double maxf = 10;
        matrix<double,2,1> x, opt;
        opt(0) = 1;
        opt(1) = 1;

        double val = 0;

        dlog << LINFO << "testing with neg_rosen and the start point: " << trans(p);

        total_count = 0;
        x = p;
        val=find_max(
            bfgs_search_strategy(),
            objective_delta_stop_strategy(eps), neg_rosen, der_neg_rosen, x, maxf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
        DLIB_TEST(approx_equal(val , neg_rosen(x)));
        dlog << LINFO << "find_max() bfgs: got neg_rosen in " << total_count;

        total_count = 0;
        x = p;
        val=find_max(
            lbfgs_search_strategy(5),
            objective_delta_stop_strategy(eps), neg_rosen, der_neg_rosen, x, maxf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
        DLIB_TEST(approx_equal(val , neg_rosen(x)));
        dlog << LINFO << "find_max() lbfgs-5: got neg_rosen in " << total_count;

        total_count = 0;
        x = p;
        val=find_max(
            lbfgs_search_strategy(5),
            objective_delta_stop_strategy(eps), neg_rosen, derivative(neg_rosen), x, maxf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
        DLIB_TEST(approx_equal(val , neg_rosen(x)));
        dlog << LINFO << "find_max() lbfgs-5: got neg_rosen/noder in " << total_count;

        total_count = 0;
        x = p;
        val=find_max_using_approximate_derivatives(
            cg_search_strategy(),
            objective_delta_stop_strategy(eps), neg_rosen, x, maxf);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x);
        DLIB_TEST(approx_equal(val , neg_rosen(x)));
        dlog << LINFO << "find_max() cg: got neg_rosen/noder2 in " << total_count;

        total_count = 0;
        x = p;
        val=find_max_bobyqa(neg_rosen, x, 2*x.size()+1,
                        uniform_matrix<double>(x.size(),1,-1e100),
                        uniform_matrix<double>(x.size(),1,1e100),
                        (max(abs(x))+1)/10,
                        1e-6,
                        10000);
        DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x);
        DLIB_TEST(approx_equal(val , neg_rosen(x)));
        dlog << LINFO << "find_max_bobyqa(): got neg_rosen in " << total_count;
    }

    void test_single_variable_function (
        const double p
    )
    {
        const double eps = 1e-7;

        dlog << LINFO << "testing with single_variable_function and the start point: " << p;
        double out, x;

        total_count = 0;
        x = p;
        out = find_min_single_variable(single_variable_function, x, -1e100, 1e100, eps, 1000);
        DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5);
        DLIB_TEST_MSG(std::abs(x) < 1e-6, x);
        dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count;

        total_count = 0;
        x = p;
        out = -find_max_single_variable(negate_function(single_variable_function), x, -1e100, 1e100, eps, 1000);
        DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5);
        DLIB_TEST_MSG(std::abs(x) < 1e-6, x);
        dlog << LINFO << "find_max_single_variable(): got single_variable_function in " << total_count;

        if (p > 0)
        {
            total_count = 0;
            x = p;
            out = find_min_single_variable(single_variable_function, x, -1e-4, 1e100, eps, 1000);
            DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5);
            DLIB_TEST_MSG(std::abs(x) < 1e-6, x);
            dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count;

            if (p > 3)
            {
                total_count = 0;
                x = p;
                out = -find_max_single_variable(negate_function(single_variable_function), x, 3, 1e100, eps, 1000);
                DLIB_TEST_MSG(std::abs(out - (3*3*3+5)) < 1e-6, out-(3*3*3+5));
                DLIB_TEST_MSG(std::abs(x-3) < 1e-6, x);
                dlog << LINFO << "find_max_single_variable(): got single_variable_function in " << total_count;
            }
        }

        if (p < 0)
        {
            total_count = 0;
            x = p;
            out = find_min_single_variable(single_variable_function, x, -1e100, 1e-4, eps, 1000);
            DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5);
            DLIB_TEST_MSG(std::abs(x) < 1e-6, x);
            dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count;

            if (p < -3)
            {
                total_count = 0;
                x = p;
                out = find_min_single_variable(single_variable_function, x, -1e100, -3, eps, 1000);
                DLIB_TEST_MSG(std::abs(out - (3*3*3+5)) < 1e-6, out-(3*3*3+5));
                DLIB_TEST_MSG(std::abs(x+3) < 1e-6, x);
                dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count;
            }
        }

    }

    void optimization_test (
    )
    /*!
        ensures
            - runs tests on the optimization stuff compliance with the specs
    !*/
    {
        matrix<double,0,1> p;

        print_spinner();

        p.set_size(2);

        // test with single_variable_function
        test_single_variable_function(0);
        test_single_variable_function(1);
        test_single_variable_function(-10);
        test_single_variable_function(-100);
        test_single_variable_function(900.53);

        // test with the rosen function
        p(0) = 9;
        p(1) = -4.9;
        test_rosen(p);
        test_neg_rosen(p);

        p(0) = 0;
        p(1) = 0;
        test_rosen(p);

        p(0) = 5323;
        p(1) = 98248;
        test_rosen(p);

        // test with the simple function
        p(0) = 1;
        p(1) = 1;
        test_simple(p);

        p(0) = 0.5;
        p(1) = -9;
        test_simple(p);

        p(0) = 645;
        p(1) = 839485;
        test_simple(p);

        print_spinner();

        // test with the apq function
        p.set_size(5);

        p(0) = 1;
        p(1) = 1;
        p(2) = 1;
        p(3) = 1;
        p(4) = 1;
        test_apq(p);

        p(0) = 1;
        p(1) = 2;
        p(2) = 3;
        p(3) = 4;
        p(4) = 5;
        test_apq(p);

        p(0) = 1;
        p(1) = 2;
        p(2) = -3;
        p(3) = 4;
        p(4) = 5;
        test_apq(p);

        print_spinner();

        p(0) = 1;
        p(1) = 2324;
        p(2) = -3;
        p(3) = 4;
        p(4) = 534534;
        test_apq(p);

        p.set_size(10);
        p(0) = 1;
        p(1) = 2;
        p(2) = -3;
        p(3) = 4;
        p(4) = 5;
        p(5) = 1;
        p(6) = 2;
        p(7) = -3;
        p(8) = 4;
        p(9) = 5;
        test_apq(p);

        // test apq with a big vector
        p.set_size(500);
        dlib::rand rnd;
        for (long i = 0; i < p.size(); ++i)
        {
            p(i) = rnd.get_random_double()*20 - 10;
        }
        test_apq(p);

        print_spinner();

        // test with the powell function
        p.set_size(4);

        p(0) = 3;
        p(1) = -1;
        p(2) = 0;
        p(3) = 1;
        test_powell(p);

        {
            matrix<double,2,1> m;
            m(0) = -0.43;
            m(1) = 0.919;
            DLIB_TEST(dlib::equal(der_rosen(m) , derivative(rosen)(m),1e-5));

            DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) -
                                  make_line_search_function(derivative(rosen),m,m)(0)) < 1e-5,"");
            DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) -
                                  make_line_search_function(derivative(rosen),m,m)(1)) < 1e-5,"");

            DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) -
                                  make_line_search_function(der_rosen,m,m)(0)) < 1e-5,"");
            DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) -
                                  make_line_search_function(der_rosen,m,m)(1)) < 1e-5,"");
        }
        {
            matrix<double,2,1> m;
            m(0) = 1;
            m(1) = 2;
            DLIB_TEST(dlib::equal(der_rosen(m) , derivative(rosen)(m),1e-5));

            DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) -
                                  make_line_search_function(derivative(rosen),m,m)(0)) < 1e-5,"");
            DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) -
                                  make_line_search_function(derivative(rosen),m,m)(1)) < 1e-5,"");

            DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) -
                                  make_line_search_function(der_rosen,m,m)(0)) < 1e-5,"");
            DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) -
                                  make_line_search_function(der_rosen,m,m)(1)) < 1e-5,"");
        }

        {
            matrix<double,2,1> m;
            m = 1,2;
            DLIB_TEST(std::abs(neg_rosen(m) - negate_function(rosen)(m) ) < 1e-16);
        }

    }

    template <typename der_funct, typename T>
    double unconstrained_gradient_magnitude (
        const der_funct& grad,
        const T& x,
        const T& lower,
        const T& upper
    )
    {
        T g = grad(x);

        double unorm = 0;

        for (long i = 0; i < g.size(); ++i)
        {
            if (lower(i) < x(i) && x(i) < upper(i))
                unorm += g(i)*g(i);
            else if (x(i) == lower(i) && g(i) < 0)
                unorm += g(i)*g(i);
            else if (x(i) == upper(i) && g(i) > 0)
                unorm += g(i)*g(i);
        }

        return unorm;
    }

    template <typename der_funct, typename T>
    double unconstrained_gradient_magnitude_neg_funct (
        const der_funct& grad,
        const T& x,
        const T& lower,
        const T& upper
    )
    {
        T g = grad(x);

        double unorm = 0;

        for (long i = 0; i < g.size(); ++i)
        {
            if (lower(i) < x(i) && x(i) < upper(i))
                unorm += g(i)*g(i);
            else if (x(i) == lower(i) && g(i) > 0)
                unorm += g(i)*g(i);
            else if (x(i) == upper(i) && g(i) < 0)
                unorm += g(i)*g(i);
        }

        return unorm;
    }

    template <typename search_strategy_type>
    double test_bound_solver_neg_rosen (dlib::rand& rnd, search_strategy_type search_strategy)
    {
        using namespace dlib::test_functions;
        print_spinner();
        matrix<double,2,1> starting_point, lower, upper, x;

        // pick random bounds
        lower = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1;
        upper = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1;
        while (upper(0) < lower(0)) upper(0) = rnd.get_random_gaussian()+1;
        while (upper(1) < lower(1)) upper(1) = rnd.get_random_gaussian()+1;

        starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0),
                       rnd.get_random_double()*(upper(1)-lower(1))+lower(1);

        dlog << LINFO << "lower: "<< trans(lower);
        dlog << LINFO << "upper: "<< trans(upper);
        dlog << LINFO << "starting: "<< trans(starting_point);

        x = starting_point;
        double val = find_max_box_constrained(
            search_strategy,
            objective_delta_stop_strategy(1e-16, 500),
            neg_rosen, der_neg_rosen, x,
            lower,
            upper
        );

        DLIB_TEST_MSG(std::abs(val - neg_rosen(x)) < 1e-11, std::abs(val - neg_rosen(x)));
        dlog << LINFO << "neg_rosen solution:\n" << x;

        dlog << LINFO << "neg_rosen gradient: "<< trans(der_neg_rosen(x));
        const double gradient_residual = unconstrained_gradient_magnitude_neg_funct(der_neg_rosen, x, lower, upper);
        dlog << LINFO << "gradient_residual: "<< gradient_residual;

        return gradient_residual;
    }

    template <typename search_strategy_type>
    double test_bound_solver_rosen (dlib::rand& rnd, search_strategy_type search_strategy)
    {
        using namespace dlib::test_functions;
        print_spinner();
        matrix<double,2,1> starting_point, lower, upper, x;

        // pick random bounds and sometimes put the upper bound at zero so we can have
        // a test where the optimal value has a bound active at 0 so make sure this case
        // works properly.
        if (rnd.get_random_double() > 0.2)
        {
            lower = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1;
            upper = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1;
            while (upper(0) < lower(0)) upper(0) = rnd.get_random_gaussian()+1;
            while (upper(1) < lower(1)) upper(1) = rnd.get_random_gaussian()+1;
        }
        else
        {
            upper = 0,0;
            if (rnd.get_random_double() > 0.5)
                upper(0) = -rnd.get_random_double();
            if (rnd.get_random_double() > 0.5)
                upper(1) = -rnd.get_random_double();

            lower = rnd.get_random_double()+1, rnd.get_random_double()+1;
            lower = upper - lower;
        }
        const bool pick_uniform_bounds = rnd.get_random_double() > 0.9;
        if (pick_uniform_bounds)
        {
            double x = rnd.get_random_gaussian()*2;
            double y = rnd.get_random_gaussian()*2;
            lower = min(x,y);
            upper = max(x,y);
        }

        starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0),
                       rnd.get_random_double()*(upper(1)-lower(1))+lower(1);

        dlog << LINFO << "lower: "<< trans(lower);
        dlog << LINFO << "upper: "<< trans(upper);
        dlog << LINFO << "starting: "<< trans(starting_point);

        x = starting_point;
        double val;
        if (!pick_uniform_bounds)
        {
            val = find_min_box_constrained(
                search_strategy,
                objective_delta_stop_strategy(1e-16, 500),
                rosen, der_rosen, x,
                lower,
                upper
            );
        }
        else
        {
            val = find_min_box_constrained(
                search_strategy,
                objective_delta_stop_strategy(1e-16, 500),
                rosen, der_rosen, x,
                lower(0),
                upper(0)
            );
        }

        DLIB_TEST_MSG(std::abs(val - rosen(x)) < 1e-11, std::abs(val - rosen(x)));
        dlog << LINFO << "rosen solution:\n" << x;

        dlog << LINFO << "rosen gradient: "<< trans(der_rosen(x));
        const double gradient_residual = unconstrained_gradient_magnitude(der_rosen, x, lower, upper);
        dlog << LINFO << "gradient_residual: "<< gradient_residual;

        return gradient_residual;
    }

    template <typename search_strategy_type>
    double test_bound_solver_brown (dlib::rand& rnd, search_strategy_type search_strategy)
    {
        using namespace dlib::test_functions;
        print_spinner();
        matrix<double,4,1> starting_point(4), lower(4), upper(4), x;

        const matrix<double,0,1> solution = brown_solution();

        // pick random bounds
        lower = rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian();
        lower = lower*10 + solution;
        upper = rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian();
        upper = upper*10 + solution;
        for (int i = 0; i < lower.size(); ++i)
        {
            if (upper(i) < lower(i))
                swap(upper(i),lower(i));
        }

        starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0),
                       rnd.get_random_double()*(upper(1)-lower(1))+lower(1),
                       rnd.get_random_double()*(upper(2)-lower(2))+lower(2),
                       rnd.get_random_double()*(upper(3)-lower(3))+lower(3);

        dlog << LINFO << "lower: "<< trans(lower);
        dlog << LINFO << "upper: "<< trans(upper);
        dlog << LINFO << "starting: "<< trans(starting_point);

        x = starting_point;
        double val = find_min_box_constrained(
            search_strategy,
            objective_delta_stop_strategy(1e-16, 500),
            brown, brown_derivative, x,
            lower,
            upper
        );

        DLIB_TEST(std::abs(val - brown(x)) < 1e-14);
        dlog << LINFO << "brown solution:\n" << x;
        return unconstrained_gradient_magnitude(brown_derivative, x, lower, upper);
    }

    template <typename search_strategy_type>
    void test_box_constrained_optimizers(search_strategy_type search_strategy)
    {
        dlib::rand rnd;
        running_stats<double> rs;

        dlog << LINFO << "test find_min_box_constrained() on rosen";
        for (int i = 0; i < 10000; ++i)
            rs.add(test_bound_solver_rosen(rnd, search_strategy));
        dlog << LINFO << "mean rosen gradient: " << rs.mean();
        dlog << LINFO << "max rosen gradient:  " << rs.max();
        DLIB_TEST(rs.mean() < 1e-12);
        DLIB_TEST(rs.max() < 1e-9);

        dlog << LINFO << "test find_min_box_constrained() on brown";
        rs.clear();
        for (int i = 0; i < 1000; ++i)
            rs.add(test_bound_solver_brown(rnd, search_strategy));
        dlog << LINFO << "mean brown gradient: " << rs.mean();
        dlog << LINFO << "max brown gradient:  " << rs.max();
        dlog << LINFO << "min brown gradient:  " << rs.min();
        DLIB_TEST(rs.mean() < 4e-5);
        DLIB_TEST_MSG(rs.max() < 3e-2, rs.max());
        DLIB_TEST(rs.min() < 1e-10);

        dlog << LINFO << "test find_max_box_constrained() on neg_rosen";
        rs.clear();
        for (int i = 0; i < 1000; ++i)
            rs.add(test_bound_solver_neg_rosen(rnd, search_strategy));
        dlog << LINFO << "mean neg_rosen gradient: " << rs.mean();
        dlog << LINFO << "max neg_rosen gradient:  " << rs.max();
        DLIB_TEST(rs.mean() < 1e-12);
        DLIB_TEST(rs.max() < 1e-9);

    }

    void test_poly_min_extract_2nd()
    {
        double off;

        off = 0.0; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 0.1; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 0.2; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 0.3; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 0.4; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 0.5; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 0.6; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 0.8; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 0.9; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
        off = 1.0; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13);
    }

    void test_solve_trust_region_subproblem_bounded()
    {
        print_spinner();
        matrix<double> H(2,2);
        H = 1, 0,
        0, 1;
        matrix<double,0,1> g, lower, upper, p, true_p;
        g = {0, 0};

        double radius = 0.5;
        lower = {0.5, 0};
        upper = {10, 10};

        solve_trust_region_subproblem_bounded(H,g, radius, p,  0.001, 500, lower, upper);
        true_p = { 0.5, 0};
        DLIB_TEST_MSG(length(p-true_p) < 1e-12, p);

    }

    void test_find_min_single_variable()
    {
        auto f = [](double x) { return (x-0.2)*(x-0.2); };
        double x = 0.8;

    }

    class optimization_tester : public tester
    {
    public:
        optimization_tester (
        ) :
            tester ("test_optimization",
                    "Runs tests on the optimization component.")
        {}

        void perform_test (
        )
        {
            dlog << LINFO << "test_box_constrained_optimizers(bfgs_search_strategy())";
            test_box_constrained_optimizers(bfgs_search_strategy());
            dlog << LINFO << "test_box_constrained_optimizers(lbfgs_search_strategy(5))";
            test_box_constrained_optimizers(lbfgs_search_strategy(5));
            test_poly_min_extract_2nd();
            optimization_test();
            test_solve_trust_region_subproblem_bounded();
            test_find_min_single_variable();
        }
    } a;

}


try
        {
            X::throw_now = true;
            opt = std::move(opt2);
            assert(false);
        }
        catch (int i)
        {
            assert(i == 6);
            assert(static_cast<bool>(opt) == false);
        }

// From LWG2451:

#include <optional>
#include <type_traits>
#include <memory>
#include <cassert>

#include "test_macros.h"
#include "archetypes.h"

using std::optional;

struct X
{
    static bool throw_now;

    X() = default;
    X(int &&)
    {
        if (throw_now)
            TEST_THROW(6);
    }
};

bool X::throw_now = false;

struct Y1
{
    Y1() = default;
    Y1(const int&) {}
    Y1& operator=(const Y1&) = delete;
};

struct Y2
{
    Y2() = default;
    Y2(const int&) = delete;
    Y2& operator=(const int&) { return *this; }
};

class B {};
class D : public B {};

template <class T>
struct AssignableFrom {
  static int type_constructed;
  static int type_assigned;
static int int_constructed;
  static int int_assigned;

  static void reset() {
      type_constructed = int_constructed = 0;
      type_assigned = int_assigned = 0;
  }

  AssignableFrom() = default;

  explicit AssignableFrom(T) { ++type_constructed; }
  AssignableFrom& operator=(T) { ++type_assigned; return *this; }

  AssignableFrom(int) { ++int_constructed; }
  AssignableFrom& operator=(int) { ++int_assigned; return *this; }
private:
  AssignableFrom(AssignableFrom const&) = delete;
  AssignableFrom& operator=(AssignableFrom const&) = delete;
};

template <class T> int AssignableFrom<T>::type_constructed = 0;
template <class T> int AssignableFrom<T>::type_assigned = 0;
template <class T> int AssignableFrom<T>::int_constructed = 0;
template <class T> int AssignableFrom<T>::int_assigned = 0;

void test_with_test_type() {
    using T = TestTypes::TestType;
    T::reset();
    { // non-empty to empty
        T::reset_constructors();
        optional<T> opt;
        optional<int> other(42);
        opt = std::move(other);
        assert(T::alive == 1);
        assert(T::constructed == 1);
        assert(T::value_constructed == 1);
        assert(T::assigned == 0);
        assert(T::destroyed == 0);
        assert(static_cast<bool>(other) == true);
        assert(*other == 42);
        assert(static_cast<bool>(opt) == true);
        assert(*opt == T(42));
    }
    assert(T::alive == 0);
    { // non-empty to non-empty
        optional<T> opt(101);
        optional<int> other(42);
        T::reset_constructors();
        opt = std::move(other);
        assert(T::alive == 1);
        assert(T::constructed == 0);
        assert(T::assigned == 1);
        assert(T::value_assigned == 1);
        assert(T::destroyed == 0);
        assert(static_cast<bool>(other) == true);
        assert(*other == 42);
        assert(static_cast<bool>(opt) == true);
        assert(*opt == T(42));
    }
    assert(T::alive == 0);
    { // empty to non-empty
        optional<T> opt(101);
        optional<int> other;
        T::reset_constructors();
        opt = std::move(other);
        assert(T::alive == 0);
        assert(T::constructed == 0);
        assert(T::assigned == 0);
        assert(T::destroyed == 1);
        assert(static_cast<bool>(other) == false);
        assert(static_cast<bool>(opt) == false);
    }
    assert(T::alive == 0);
    { // empty to empty
        optional<T> opt;
        optional<int> other;
        T::reset_constructors();
        opt = std::move(other);
        assert(T::alive == 0);
        assert(T::constructed == 0);
        assert(T::assigned == 0);
        assert(T::destroyed == 0);
        assert(static_cast<bool>(other) == false);
        assert(static_cast<bool>(opt) == false);
    }
    assert(T::alive == 0);
}

void test_ambiguous_assign() {
    using OptInt = std::optional<int>;
    {
        using T = AssignableFrom<OptInt&&>;
        T::reset();
        {
            OptInt a(42);
            std::optional<T> t;
            t = std::move(a);
            assert(T::type_constructed == 1);
            assert(T::type_assigned == 0);
            assert(T::int_constructed == 0);
            assert(T::int_assigned == 0);
        }
        {
            using Opt = std::optional<T>;
            static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, "");
            static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
            static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
        }
    }
    {
        using T = AssignableFrom<OptInt const&&>;
        T::reset();
        {
            const OptInt a(42);
            std::optional<T> t;
            t = std::move(a);
            assert(T::type_constructed == 1);
            assert(T::type_assigned == 0);
            assert(T::int_constructed == 0);
            assert(T::int_assigned == 0);
        }
        T::reset();
        {
            OptInt a(42);
            std::optional<T> t;
            t = std::move(a);
            assert(T::type_constructed == 1);
            assert(T::type_assigned == 0);
            assert(T::int_constructed == 0);
            assert(T::int_assigned == 0);
        }
        {
            using Opt = std::optional<T>;
            static_assert(std::is_assignable<Opt&, OptInt&&>::value, "");
            static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
            static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
        }
    }
}

int main(int, char**)
{
    test_with_test_type();
    test_ambiguous_assign();
    {
        optional<int> opt;
        optional<short> opt2;
        opt = std::move(opt2);
        assert(static_cast<bool>(opt2) == false);
        assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
    }
    {
        optional<int> opt;
        optional<short> opt2(short{2});
        opt = std::move(opt2);
        assert(static_cast<bool>(opt2) == true);
        assert(*opt2 == 2);
        assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
        assert(*opt == *opt2);
    }
    {
        optional<int> opt(3);
        optional<short> opt2;
        opt = std::move(opt2);
        assert(static_cast<bool>(opt2) == false);
        assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
    }
    {
        optional<int> opt(3);
        optional<short> opt2(short{2});
        opt = std::move(opt2);
        assert(static_cast<bool>(opt2) == true);
        assert(*opt2 == 2);
        assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
        assert(*opt == *opt2);
    }
    {
        optional<std::unique_ptr<B>> opt;
        optional<std::unique_ptr<D>> other(new D());
        opt = std::move(other);
        assert(static_cast<bool>(opt) == true);
        assert(static_cast<bool>(other) == true);
        assert(opt->get() != nullptr);
        assert(other->get() == nullptr);
    }
#ifndef TEST_HAS_NO_EXCEPTIONS
    {
        optional<X> opt;
        optional<int> opt2(42);
        assert(static_cast<bool>(opt2) == true);


int CFontMakerApp::ExitInstance()
{
    DestroyCursor( m_hWaitCursor );

    return CWinApp::ExitInstance();
}

// Name: FontMaker.cpp
// Desc: Defines the class behaviors for the application.
// Hist: 09.06.02 - Revised Fontmaker sample
#include "stdafx.h"
#include "FontMaker.h"
#include "Glyphs.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CTextureFont       g_Font;
extern BOOL        g_bIsGlyphSelected;
extern int         g_iSelectedGlyphNum;
extern GLYPH_ATTR* g_pSelectedGylph;
extern WCHAR       g_cSelectedGlyph;

// CFontMakerApp

BEGIN_MESSAGE_MAP(CFontMakerApp, CWinApp)
    ON_COMMAND(IDM_FILE_NEWFONT, OnNewFontButton)
    ON_BN_CLICKED(IDC_EFFECTSOUTLINED_CHECK, OnEffectsCheck)
    ON_BN_CLICKED(IDC_EFFECTSSHADOWED_CHECK, OnEffectsCheck)
    ON_BN_CLICKED(IDC_EFFECTSBLURRED_CHECK, OnEffectsCheck)
    ON_BN_CLICKED(IDC_EFFECTSSCANLINES_CHECK, OnEffectsCheck)
	ON_BN_CLICKED(IDC_EFFECTSANTIALIAS_CHECK, OnEffectsCheck)
	ON_BN_CLICKED(IDC_GLYPHSFROMRANGE_RADIO, OnGlyphsFromRangeRadio)
    ON_EN_CHANGE(IDC_GLYPHSRANGEFROM_EDIT, OnChangeGlpyhsRangeEdit)
    ON_BN_CLICKED(IDC_GLYPHSFROMFILE_RADIO, OnGlyphsFromFileRadio)
    ON_EN_KILLFOCUS(IDC_GLYPHSFILE_EDIT, OnChangeGlyphsFileEdit)
    ON_BN_CLICKED(IDC_GLYPHSFILESELECTOR_BUTTON, OnGlyphsFileSelectorButton)
    ON_BN_CLICKED(IDC_GLYPHSCUSTOM_RADIO, OnGlyphsCustom)
	ON_BN_CLICKED(IDC_TEXTURESIZE_BUTTON, OnTextureSizeButton)
    ON_BN_CLICKED(IDC_MAGNIFY_BUTTON, OnMagnifyButton)
    ON_BN_CLICKED(IDC_GLYPH_SPECIAL, OnGlyphSpecial)
    ON_UPDATE_COMMAND_UI(IDC_MAGNIFY_BUTTON, OnUpdateButton)
	ON_COMMAND(IDM_FILE_LOADFONTFILE, OnLoadButton)
	ON_COMMAND(IDM_FILE_SAVEFONTFILES, OnSaveButton)
	ON_COMMAND(IDM_FILE_LOADFONTLAYOUT, OnLoadCustomFontButton)
    ON_COMMAND(IDM_FILE_EXIT, OnExit)
    ON_COMMAND(ID_APP_ABOUT, OnAbout)
    ON_COMMAND(ID_HELP, OnHelp)
    ON_EN_CHANGE(IDC_GLYPHSRANGETO_EDIT, OnChangeGlpyhsRangeEdit)
    ON_UPDATE_COMMAND_UI(IDC_TEXTURESIZE_BUTTON, OnUpdateButton)
    ON_UPDATE_COMMAND_UI(IDC_GLYPHSFILESELECTOR_BUTTON, OnUpdateButton)
    ON_UPDATE_COMMAND_UI(IDM_FILE_NEWFONT, OnUpdateButton)
    ON_UPDATE_COMMAND_UI(IDM_FILE_LOADFONTFILE, OnUpdateButton)
    ON_UPDATE_COMMAND_UI(IDM_FILE_LOADFONTLAYOUT, OnUpdateButton)
    ON_UPDATE_COMMAND_UI(IDM_FILE_SAVEFONTFILES, OnUpdateButton)
    ON_UPDATE_COMMAND_UI(IDM_FILE_EXIT, OnUpdateButton)
    ON_UPDATE_COMMAND_UI(ID_APP_ABOUT, OnUpdateButton)
    ON_UPDATE_COMMAND_UI(ID_HELP, OnUpdateButton)
END_MESSAGE_MAP()

// The one and only CFontMakerApp object
CFontMakerApp theApp;

// Desc: App initialization
BOOL CFontMakerApp::InitInstance()
{
    // Create the main frame window for the app
    CFontMakerFrameWnd* pFrameWnd = new CFontMakerFrameWnd;
    m_pMainWnd = pFrameWnd;

    // Associate the view with the frame
    CCreateContext context;
    context.m_pCurrentFrame   = NULL;
    context.m_pCurrentDoc     = NULL;
    context.m_pNewViewClass   = RUNTIME_CLASS(CFontMakerView);
    context.m_pNewDocTemplate = NULL;

    // Create the frame and load resources (menu, accelerator, etc.)
    pFrameWnd->LoadFrame( IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,
                          NULL, &context );

    // Call OnInitialUpdate() to be called for the view
    pFrameWnd->InitialUpdateFrame( NULL, TRUE );

    // The one and only window has been initialized, so show and update it.
    m_pMainWnd->ShowWindow( SW_SHOW );
    m_pMainWnd->UpdateWindow();

    // Load the hourglass cursor
    m_hWaitCursor = LoadCursor( IDC_WAIT );

    // Get access the the dialog controls and the view
    m_pDialogBar = pFrameWnd->GetDialogBar();
    m_pView      = (CFontMakerView*)pFrameWnd->GetActiveView();

    // Initially, no font is selected
    m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->SetWindowText( _T("<Choose font>") );
    m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->SetWindowText( _T("") );
    m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->SetWindowText( _T("") );

    return TRUE;
}

// Desc: This function is needed to override some internal mucking with button
//       states. Without it, button and menu enabling will make you crazy.
void CFontMakerApp::OnUpdateButton( CCmdUI* pCmdUI )
{
	BOOL bEnable;

    switch( pCmdUI->m_nID )
    {
        // Controls which are active all the time
        case IDM_FILE_NEWFONT:
		case IDM_FILE_LOADFONTLAYOUT:
		case IDM_FILE_LOADFONTFILE:
        case IDM_FILE_EXIT:
        case ID_APP_ABOUT:
        case ID_HELP:
            bEnable = TRUE;
            break;

		case IDC_TEXTURESIZE_BUTTON:
		case IDM_FILE_SAVEFONTFILES:
		case IDC_MAGNIFY_BUTTON:
			bEnable =  g_Font.m_hFont ? TRUE : FALSE;
			if ( !bEnable )
				bEnable = g_Font.m_pCustomFilename ? TRUE : FALSE;
			break;

        // Controls which are active only when a font is available
        default:
            bEnable = g_Font.m_hFont ? TRUE : FALSE;
            break;
    }

	pCmdUI->Enable( bEnable );
}

BOOL g_bFirstTime = TRUE;

// Desc: Called when the user hits the "New Font" button, this loads the font
//       and enables all the other windows controls.
void CFontMakerApp::OnNewFontButton()
{
    // Initialize the LOGFONT structure. It's static so it's state is remembered
    if ( g_Font.m_LogFont.lfHeight == 0 )
	{
		// first time init
		strcpy( g_Font.m_LogFont.lfFaceName, "Arial" );	// Arial font for a default
		g_Font.m_LogFont.lfHeight  = 16;				// 16 height font for a default
		g_Font.m_LogFont.lfWeight  = 400;				// 400 = normal, 700 = bold, etc.
		g_Font.m_LogFont.lfItalic  = 0;					//   0 = normal, 255 = italic
		g_Font.m_LogFont.lfQuality = ANTIALIASED_QUALITY;
	}

	// convert to point size for dialog purposes
	HDC hDC = GetDC( m_pMainWnd->m_hWnd );
	// Current point size unit=1/10 pts
	INT iPointSize = g_Font.m_LogFont.lfHeight * 10;
	g_Font.m_LogFont.lfHeight= -MulDiv( iPointSize, GetDeviceCaps( hDC, LOGPIXELSY ), 720 );
	ReleaseDC( m_pMainWnd->m_hWnd, hDC );

    // Create the CHOOSEFONT structure
    static CHOOSEFONT cf = {0};
    cf.lStructSize = sizeof(CHOOSEFONT);
    cf.lpLogFont   = &g_Font.m_LogFont;
    cf.Flags       = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
    cf.nFontType   = SCREEN_FONTTYPE;

    if ( 0 == ChooseFont( &cf ) )
        return;

	g_Font.m_pCustomFilename = NULL;

	// NOT using point sizes, but cell heights
	g_Font.m_LogFont.lfHeight = cf.iPointSize/10;

    // Reset the selected glpyh
    UpdateSelectedGlyph( FALSE );

    if( FAILED( CalculateAndRenderGlyphs() ) )
    {
        // Could not create new font
        MessageBox( m_pMainWnd->m_hWnd, "Could not create the requested font!", "Error", MB_ICONERROR|MB_OK );
        return;
    }

	char tempName[256];
    sprintf( tempName, "%s_%d", g_Font.m_LogFont.lfFaceName, cf.iPointSize/10 );

	// remove any spaces in the font name
	for (unsigned int i=0,j=0; i<strlen( tempName )+1; i++)
	{
		if ( tempName[i] != ' ' )
		{
			g_Font.m_strFontName[j++] = tempName[i];
		}
	}

    if ( g_bFirstTime )
    {
        CString str;

        // Set font properties
        m_pDialogBar->GetDlgItem( IDC_FONT_GROUPBOX )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_FONTNAME_LABEL )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_LABEL )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_FONTSIZE_LABEL )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_EFFECTSOUTLINED_CHECK )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_EFFECTSSHADOWED_CHECK )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_BLUR_EDIT )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_SCANLINES_EDIT )->EnableWindow( TRUE );

		if ( g_Font.m_bAntialiasEffect )
		{
			((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK ))->SetCheck( TRUE );
		}
		else
		{
			((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK ))->SetCheck( FALSE );
		}

		str.Format( "%d", g_Font.m_nBlur );
		m_pDialogBar->GetDlgItem( IDC_BLUR_EDIT )->SetWindowText( str );

		str.Format( "%d", g_Font.m_nScanlines );
		m_pDialogBar->GetDlgItem( IDC_SCANLINES_EDIT )->SetWindowText( str );

        str.Format( "%s", g_Font.m_LogFont.lfFaceName );
        m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->SetWindowText( str );
        if( g_Font.m_LogFont.lfItalic )
            str.Format( "Italic", g_Font.m_LogFont.lfWeight < 550 ? "" : "Bold " );
        else
            str.Format( "%s", g_Font.m_LogFont.lfWeight < 550 ? "Regular" : "Bold" );
        m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->SetWindowText( str );
        str.Format( "%ld", cf.iPointSize/10 );
        m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->SetWindowText( str );

        // Set texture properties
        m_pDialogBar->GetDlgItem( IDC_TEXTURE_GROUPBOX )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_LABEL )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_LABEL )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_STATIC )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_STATIC )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_TEXTURESIZE_BUTTON )->EnableWindow( TRUE );

		SetTextureSize( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight );

        // Set glyph range properties
        m_pDialogBar->GetDlgItem( IDC_GLYPHS_GROUPBOX )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_LABEL )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_LABEL )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->EnableWindow( FALSE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSFILESELECTOR_BUTTON )->EnableWindow( FALSE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO )->EnableWindow( TRUE );

        // Set a default range of glyphs to use
        ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( TRUE );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->SetWindowText( "32" );
        m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->SetWindowText( "127" );
        g_Font.ExtractValidGlyphsFromRange( 32, 127 );

        m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_LABEL )->EnableWindow( TRUE );
        m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_EDIT )->EnableWindow( TRUE );
    }
    else
    {
        CString str;

        str.Format( "%s", g_Font.m_LogFont.lfFaceName );
        m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->SetWindowText( str );
        if ( g_Font.m_LogFont.lfItalic )
            str.Format( "Italic", g_Font.m_LogFont.lfWeight < 550 ? "" : "Bold " );
        else
            str.Format( "%s", g_Font.m_LogFont.lfWeight < 550 ? "Regular" : "Bold" );
        m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->SetWindowText( str );
        str.Format( "%ld", cf.iPointSize/10 );
        m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->SetWindowText( str );
    }

	g_bFirstTime = FALSE;
}

// Desc: User will be specifying a glyph range manually
void CFontMakerApp::OnGlyphsFromRangeRadio()
{
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_LABEL )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_LABEL )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSFILESELECTOR_BUTTON )->EnableWindow( FALSE );

	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO ))->SetCheck( false );
	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( true );
	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO ))->SetCheck( false );

    OnChangeGlpyhsRangeEdit();
}

// Desc: User changed the range of glpyhs
void CFontMakerApp::OnChangeGlpyhsRangeEdit()
{
    if( NULL == g_Font.m_hFont )
        return;

    CEdit* pGlyphRangeFromEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT );
    CEdit* pGlyphRangeToEdit   = (CEdit*)m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT );

    CString strFrom;
    CString strTo;
    pGlyphRangeFromEdit->GetWindowText( strFrom );
    pGlyphRangeToEdit->GetWindowText( strTo );

    WORD wFrom = (WORD)max( 0, atoi( strFrom ) );
    WORD wTo   = (WORD)min( 65535, atoi( strTo ) );
    g_Font.ExtractValidGlyphsFromRange( wFrom, wTo );

    // Draw the new font glyphs
    CalculateAndRenderGlyphs();
}

void CFontMakerApp::OnGlyphsCustom()
{
	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO ))->SetCheck( false );
	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( false );
	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO ))->SetCheck( true );
}

// Desc: User want to extract glyphs that are used in a text file
void CFontMakerApp::OnGlyphsFromFileRadio()
{
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_LABEL )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_LABEL )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSFILESELECTOR_BUTTON )->EnableWindow( TRUE );

	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO ))->SetCheck( true );
	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( false );
	((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO ))->SetCheck( false );

    OnChangeGlyphsFileEdit();
}

// Desc: Handle change in name of file to extract glyphs from
void CFontMakerApp::OnChangeGlyphsFileEdit()
{
    CEdit* pGlyphFileNameEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT );

    CString strFileName;
    pGlyphFileNameEdit->GetWindowText( strFileName );

    if( strFileName.IsEmpty() )
        return;

    g_Font.ExtractValidGlyphsFromFile( (const TCHAR*)strFileName );

    // Draw the new font glyphs
    CalculateAndRenderGlyphs();
}

// Desc: Handle change in name of file to extract glyphs from
void CFontMakerApp::OnGlyphsFileSelectorButton()
{
    static TCHAR strFileName[MAX_PATH]   = _T("");
    static TCHAR strFileName2[MAX_PATH]  = _T("");
    static TCHAR strInitialDir[MAX_PATH] = _T("c:\\");

    // Display the OpenFileName dialog. Then, try to load the specified file
    OPENFILENAME ofn = { sizeof(OPENFILENAME), NULL, NULL,
                         _T("Text files (.txt)\0*.txt\0\0"),
                         NULL, 0, 1, strFileName, MAX_PATH, strFileName2, MAX_PATH,
                         strInitialDir, _T("Open Text File"),
                         OFN_FILEMUSTEXIST, 0, 1, NULL, 0, NULL, NULL };

    if( TRUE == GetOpenFileName( &ofn ) )
    {
        m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->SetWindowText( ofn.lpstrFile);
        OnChangeGlyphsFileEdit();
    }
}

// Desc: User changed font rendering options
void CFontMakerApp::OnEffectsCheck()
{
    g_Font.m_bOutlineEffect   = ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSOUTLINED_CHECK ))->GetCheck();
    g_Font.m_bShadowEffect    = ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSSHADOWED_CHECK ))->GetCheck();
	g_Font.m_bAntialiasEffect = ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK ))->GetCheck();

	bool bValveEffects = false;
    if ( g_Font.m_bOutlineEffect || g_Font.m_bShadowEffect )
	{
		m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK )->EnableWindow( false );
		m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK )->EnableWindow( false );
		((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK ))->SetCheck( false );
		((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK ))->SetCheck( false );
	}
	else
	{
		m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK )->EnableWindow( true );
		m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK )->EnableWindow( true );
		bValveEffects = true;
	}

	if ( bValveEffects && ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK ))->GetCheck() )
	{
	    CEdit* pBlurEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_BLUR_EDIT );

		CString strBlur;
	    pBlurEdit->GetWindowText( strBlur );

		g_Font.m_nBlur = max( 2, atoi( strBlur ) );

		strBlur.Format( "%d", g_Font.m_nBlur );
		pBlurEdit->SetWindowText( strBlur );
	}
	else
	{
		g_Font.m_nBlur = 0;
	}

    if ( bValveEffects && ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK ))->GetCheck() )
	{
		CEdit* pScanlineEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_SCANLINES_EDIT );

		CString strScanlines;
	    pScanlineEdit->GetWindowText( strScanlines );

		g_Font.m_nScanlines = max( 2, atoi( strScanlines ) );

		strScanlines.Format( "%d", g_Font.m_nScanlines );
		pScanlineEdit->SetWindowText( strScanlines );
	}
	else
	{
		g_Font.m_nScanlines = 0;
	}

    // Draw the new font glyphs
    CalculateAndRenderGlyphs();
}

// Desc: User wants to run the Windows "magnify" tool
void CFontMakerApp::OnMagnifyButton()
{
    // Run the Windows "magnify" tool
    WinExec( "magnify.exe", TRUE );
}

// Desc: Simple dialog to change the font texture size
class CTextureSizeDlg : public CDialog
{
public:
    CTextureSizeDlg();

// Dialog Data
    enum { IDD = IDD_TEXTURESIZE };

    // ClassWizard generated virtual function overrides
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
        // No message handlers
    DECLARE_MESSAGE_MAP()
};

CTextureSizeDlg::CTextureSizeDlg() : CDialog(CTextureSizeDlg::IDD)
{
}

void CTextureSizeDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);

    DDX_Text( pDX, IDC_WIDTH, g_Font.m_dwTextureWidth );
    DDV_MinMaxInt( pDX, g_Font.m_dwTextureWidth, 16, 2048 );

    DDX_Text( pDX, IDC_HEIGHT, g_Font.m_dwTextureHeight );
    DDV_MinMaxInt( pDX, g_Font.m_dwTextureHeight, 16, 2048 );
}

BEGIN_MESSAGE_MAP(CTextureSizeDlg, CDialog)
END_MESSAGE_MAP()

void CFontMakerApp::SetTextureSize( int width, int height )
{
	g_Font.m_dwTextureWidth = width;
	g_Font.m_dwTextureHeight = height;

	CString str;
    str.Format( "%ld", g_Font.m_dwTextureWidth );
    m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_STATIC )->SetWindowText( str );
    str.Format( "%ld", g_Font.m_dwTextureHeight );
    m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_STATIC )->SetWindowText( str );
}

// Desc: User wants to change the font texture size
void CFontMakerApp::OnTextureSizeButton()
{
    if ( !g_Font.m_hFont && !g_Font.m_pCustomFilename )
        return;

    CTextureSizeDlg dlgTextureSize;
    dlgTextureSize.DoModal();

	SetTextureSize( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight );

    // Draw the new font glyphs
    CalculateAndRenderGlyphs();
}

void CFontMakerApp::InsertGlyph()
{
	CEdit* pGlyphInsert = (CEdit*)m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_EDIT );

    CString strInsert;
    pGlyphInsert->GetWindowText( strInsert );

	WORD wGlyph = atoi( strInsert );
	if ( wGlyph < 0 )
		wGlyph = 0;
	else if ( wGlyph > 65535 )
		wGlyph = 65535;

    g_Font.InsertGlyph( wGlyph );
}

// Desc: User changed (via mouse or keyboard) which glyph is selected
void CFontMakerApp::UpdateSelectedGlyph( BOOL bGlyphSelected, int iSelectedGlyph )
{
    // Handle case where no glyph is selected
    g_bIsGlyphSelected  = FALSE;
    g_iSelectedGlyphNum = 0;
    g_pSelectedGylph    = NULL;
    g_cSelectedGlyph    = L'\0';

    if ( bGlyphSelected )
    {
        for ( DWORD i=0; i<=g_Font.m_cMaxGlyph; i++ )
        {
            if ( g_Font.m_TranslatorTable[i] == iSelectedGlyph )
            {
                g_bIsGlyphSelected  = TRUE;
                g_iSelectedGlyphNum = iSelectedGlyph;
                g_pSelectedGylph    = &g_Font.m_pGlyphs[iSelectedGlyph];
                g_cSelectedGlyph    = (WCHAR)i;
                break;
            }
        }
    }

    // Enable/disable/set-text-of the appropriate controls
    if ( g_bIsGlyphSelected )
    {
        CString str;
        str.Format( "%d", g_cSelectedGlyph ); m_pDialogBar->GetDlgItem( IDC_GLYPH_VALUE_STATIC )->SetWindowText( str );
        str.Format( "%d", g_pSelectedGylph->x ); m_pDialogBar->GetDlgItem( IDC_GLYPH_X_STATIC )->SetWindowText( str );
        str.Format( "%d", g_pSelectedGylph->y ); m_pDialogBar->GetDlgItem( IDC_GLYPH_Y_STATIC )->SetWindowText( str );
        str.Format( "%d", g_pSelectedGylph->w ); m_pDialogBar->GetDlgItem( IDC_GLYPH_W_STATIC )->SetWindowText( str );
        str.Format( "%d", g_pSelectedGylph->h ); m_pDialogBar->GetDlgItem( IDC_GLYPH_H_STATIC )->SetWindowText( str );
        str.Format( "%d", g_pSelectedGylph->a ); m_pDialogBar->GetDlgItem( IDC_GLYPH_A_STATIC )->SetWindowText( str );
        str.Format( "%d", g_pSelectedGylph->b ); m_pDialogBar->GetDlgItem( IDC_GLYPH_B_STATIC )->SetWindowText( str );
        str.Format( "%d", g_pSelectedGylph->c ); m_pDialogBar->GetDlgItem( IDC_GLYPH_C_STATIC )->SetWindowText( str );
        ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPH_SPECIAL ))->SetCheck( g_Font.m_ValidGlyphs[g_cSelectedGlyph] == 2 );
    }
    else
    {
        CString str("");
        m_pDialogBar->GetDlgItem( IDC_GLYPH_VALUE_STATIC )->SetWindowText( str );
        m_pDialogBar->GetDlgItem( IDC_GLYPH_X_STATIC )->SetWindowText( str );
        m_pDialogBar->GetDlgItem( IDC_GLYPH_Y_STATIC )->SetWindowText( str );
        m_pDialogBar->GetDlgItem( IDC_GLYPH_W_STATIC )->SetWindowText( str );
        m_pDialogBar->GetDlgItem( IDC_GLYPH_H_STATIC )->SetWindowText( str );
        m_pDialogBar->GetDlgItem( IDC_GLYPH_A_STATIC )->SetWindowText( str );
        m_pDialogBar->GetDlgItem( IDC_GLYPH_B_STATIC )->SetWindowText( str );
        m_pDialogBar->GetDlgItem( IDC_GLYPH_C_STATIC )->SetWindowText( str );
        ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPH_SPECIAL ))->SetCheck( FALSE );
    }

    m_pDialogBar->GetDlgItem( IDC_SELECTEDGLYPH_GROUPBOX )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_VALUE_LABEL )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_X_LABEL )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_Y_LABEL )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_W_LABEL )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_H_LABEL )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_A_LABEL )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_B_LABEL )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_C_LABEL )->EnableWindow( g_bIsGlyphSelected );

    m_pDialogBar->GetDlgItem( IDC_GLYPH_VALUE_STATIC )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_X_STATIC )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_Y_STATIC )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_W_STATIC )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_H_STATIC )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_A_STATIC )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_B_STATIC )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_C_STATIC )->EnableWindow( g_bIsGlyphSelected );
    m_pDialogBar->GetDlgItem( IDC_GLYPH_SPECIAL )->EnableWindow( g_bIsGlyphSelected );
}

// Desc: User changed the status of the selected glyph
void CFontMakerApp::OnGlyphSpecial()
{
    if( g_bIsGlyphSelected )
    {
        if( ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPH_SPECIAL ))->GetCheck() )
            g_Font.m_ValidGlyphs[g_cSelectedGlyph] = 2;
        else
            g_Font.m_ValidGlyphs[g_cSelectedGlyph] = 1;

        // Draw the font glyphs, which may have changed layout
        CalculateAndRenderGlyphs();
    }
}

// Desc: User wants to load a font file
void CFontMakerApp::OnLoadButton()
{
    CHAR strVBFFileName[MAX_PATH];
    sprintf( strVBFFileName, "%s.vbf", g_Font.m_strFontName );

    OPENFILENAME ofnVBF;       // common dialog box structure
    ZeroMemory( &ofnVBF, sizeof(OPENFILENAME) );
    ofnVBF.lStructSize     = sizeof(OPENFILENAME);
    ofnVBF.hwndOwner       = m_pMainWnd->m_hWnd;
    ofnVBF.lpstrFilter     = "Font files (*.vbf)\0*.vbf\0\0";
    ofnVBF.nFilterIndex    = 1;
    ofnVBF.lpstrFile       = strVBFFileName;
    ofnVBF.nMaxFile        = sizeof(strVBFFileName);
    ofnVBF.lpstrFileTitle  = NULL;
    ofnVBF.nMaxFileTitle   = 0;
    ofnVBF.lpstrInitialDir = NULL;
    ofnVBF.lpstrTitle      = "Load Font (VBF) File...";
    ofnVBF.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_READONLY;

    // Display the Load dialog box for the VBF file
    if ( FALSE == GetOpenFileName( &ofnVBF ) )
        return;

    if ( FAILED( g_Font.ReadFontInfoFile( strVBFFileName ) ) )
    {
        m_pMainWnd->MessageBox( "Could not load the Valve bitmap font info file.",
                                "Error", MB_ICONERROR|MB_OK );
        return;
    }
}

// OnLoadCustomFontButton
void CFontMakerApp::OnLoadCustomFontButton()
{
    CHAR strVCFFileName[MAX_PATH];
    strVCFFileName[0] = '\0';

    OPENFILENAME ofnVCF;       // common dialog box structure
    ZeroMemory( &ofnVCF, sizeof(OPENFILENAME) );
    ofnVCF.lStructSize     = sizeof(OPENFILENAME);
    ofnVCF.hwndOwner       = m_pMainWnd->m_hWnd;
    ofnVCF.lpstrFilter     = "Custom Font files (*.vcf)\0*.vcf\0\0";
    ofnVCF.nFilterIndex    = 1;
    ofnVCF.lpstrFile       = strVCFFileName;
    ofnVCF.nMaxFile        = sizeof(strVCFFileName);
    ofnVCF.lpstrFileTitle  = NULL;
    ofnVCF.nMaxFileTitle   = 0;
    ofnVCF.lpstrInitialDir = NULL;
    ofnVCF.lpstrTitle      = "Load Custom Font (VCF) File...";
    ofnVCF.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_READONLY;

    // Display the Load dialog box for the VBF file
    if ( FALSE == GetOpenFileName( &ofnVCF ) )
        return;

    if ( FAILED( g_Font.ReadCustomFontFile( strVCFFileName ) ) )
    {
        m_pMainWnd->MessageBox( "Could not load the Valve bitmap custom font file.",
                                "Error", MB_ICONERROR|MB_OK );
        return;
    }

    // Reset the selected glpyh
    UpdateSelectedGlyph( FALSE );

    if ( FAILED( CalculateAndRenderGlyphs() ) )
    {
        // Could not create new font
        MessageBox( m_pMainWnd->m_hWnd, "Could not create the requested font!", "Error", MB_ICONERROR|MB_OK );
        return;
    }

    m_pDialogBar->GetDlgItem( IDC_FONT_GROUPBOX )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_FONTNAME_LABEL )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_LABEL )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_FONTSIZE_LABEL )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_EFFECTSOUTLINED_CHECK )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_EFFECTSSHADOWED_CHECK )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_BLUR_EDIT )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_SCANLINES_EDIT )->EnableWindow( FALSE );

	CString str;
	str.Format( "%s", g_Font.m_strFontName );
	m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->SetWindowText( str );

	str.Format( "%d", g_Font.m_maxCustomCharHeight );
	m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->SetWindowText( str );

	// Set texture properties
    m_pDialogBar->GetDlgItem( IDC_TEXTURE_GROUPBOX )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_LABEL )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_LABEL )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_STATIC )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_STATIC )->EnableWindow( TRUE );
    m_pDialogBar->GetDlgItem( IDC_TEXTURESIZE_BUTTON )->EnableWindow( TRUE );

	SetTextureSize( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight );

    // Set glyph range properties
    m_pDialogBar->GetDlgItem( IDC_GLYPHS_GROUPBOX )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_LABEL )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_LABEL )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSFILESELECTOR_BUTTON )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO )->EnableWindow( TRUE );

    ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( FALSE );
    ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO ))->SetCheck( FALSE );
    ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO ))->SetCheck( TRUE );

    m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_LABEL )->EnableWindow( FALSE );
    m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_EDIT )->EnableWindow( FALSE );
}

// Desc: User wants to save the font files
void CFontMakerApp::OnSaveButton()
{
    CHAR strTGAFileName[MAX_PATH];
    CHAR strVBFFileName[MAX_PATH];

	if ( !g_Font.m_hFont && !g_Font.m_pCustomFilename )
		return;

    sprintf( strTGAFileName, "%s.tga", g_Font.m_strFontName );

    OPENFILENAME ofnTGA;       // common dialog box structure
    ZeroMemory( &ofnTGA, sizeof(OPENFILENAME) );
    ofnTGA.lStructSize     = sizeof(OPENFILENAME);
    ofnTGA.hwndOwner       = m_pMainWnd->m_hWnd;
    ofnTGA.lpstrFilter     = "Targa files (*.tga)\0*.tga\0\0";
    ofnTGA.nFilterIndex    = 1;
    ofnTGA.lpstrFile       = strTGAFileName;
    ofnTGA.nMaxFile        = sizeof(strTGAFileName);
    ofnTGA.lpstrFileTitle  = NULL;
    ofnTGA.nMaxFileTitle   = 0;
    ofnTGA.lpstrInitialDir = NULL;
    ofnTGA.lpstrTitle      = "Save Font Texture Image (TGA) File...";
    ofnTGA.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_EXPLORER;

    // Display the Save As dialog box for the TGA file
    if ( FALSE == GetSaveFileName( &ofnTGA ) )
        return;

	// use the tga name, but replace the extension
	CHAR *ptr;
	CHAR temp[MAX_PATH];
	int len;
    strcpy( temp, strTGAFileName );
	len = strlen( temp );
	if ( len > 4 && temp[len-4] == '.' )
	{
		temp[len-3] = 'v';
		temp[len-2] = 'b';
		temp[len-1] = 'f';

		// strip the path
		ptr = strrchr( temp, '\\' );
		if ( ptr )
		{
			strcpy( strVBFFileName, ptr+1 );
		}
		else
		{
			strcpy( strVBFFileName, temp );
		}
	}
	else
	{
	    sprintf( strVBFFileName, "%s.vbf", g_Font.m_strFontName );
	}

	// place the VBF files in the materials directory
	CHAR materialsDir[MAX_PATH];
	strcpy( materialsDir, strTGAFileName );
	strlwr( materialsDir );
	ptr = strstr( materialsDir, "\\content\\hl2x\\materialsrc\\" );
	if ( ptr )
	{
		// need the final dirs, skip past
		CHAR *ptr2 = ptr + strlen( "\\content\\hl2x\\materialsrc\\" );
		strcpy( temp, ptr2 );

		*ptr = '\0';
		strcat( materialsDir, "\\game\\hl2x\\materials\\" );
		strcat( materialsDir, temp );

		// strip terminal filename
		ptr = materialsDir + strlen( materialsDir ) - 1;
		while ( ptr > materialsDir )
		{
			if ( *ptr == '\\' )
			{
				*ptr = '\0';
				break;
			}
			ptr--;
		}
	}
	else
	{
		materialsDir[0] = '\0';
	}

    // Initialize OPENFILENAME
    OPENFILENAME ofnVBF;       // common dialog box structure
    ZeroMemory( &ofnVBF, sizeof(OPENFILENAME) );
    ofnVBF.lStructSize     = sizeof(OPENFILENAME);
    ofnVBF.hwndOwner       = m_pMainWnd->m_hWnd;
    ofnVBF.lpstrFilter     = "Font files (*.vbf)\0*.vbf\0\0";
    ofnVBF.nFilterIndex    = 1;
    ofnVBF.lpstrFile       = strVBFFileName;
    ofnVBF.nMaxFile        = sizeof(strVBFFileName);
    ofnVBF.lpstrFileTitle  = NULL;
    ofnVBF.nMaxFileTitle   = 0;
	ofnVBF.lpstrInitialDir = materialsDir[0] ? materialsDir : NULL;
    ofnVBF.lpstrTitle      = "Save Valve Bitmap Font (VBF) File...";
    ofnVBF.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_EXPLORER;

    // Display the Save As dialog box for the ABC file
    if ( FALSE == GetSaveFileName( &ofnVBF ) )
        return;

    // Make sure the names are valid
    if ( !lstrcmp( strVBFFileName, strTGAFileName ) )
    {
        m_pMainWnd->MessageBox( "Cannot have VBF and TGA filenames be the same!\nFiles not saved.",
                                "Error", MB_ICONERROR|MB_OK );
        return;
    }

    // Add an extension, if there was not one
    if ( 0 == ofnVBF.nFileExtension )
        lstrcat( strVBFFileName, ".vbf" );
    if ( 0 == ofnTGA.nFileExtension )
        lstrcat( strTGAFileName, ".tga" );

    // Save the valve bitmap font info file (.vbf)
    if ( FAILED( g_Font.WriteFontInfoFile( strVBFFileName ) ) )
    {
        m_pMainWnd->MessageBox( "Could not write the Valve bitmap font info file.",
                                "Error", MB_ICONERROR|MB_OK );
        return;
    }

	// blur or scanline effects require special processing to ensure
	// they can be used in additive mode
	bool bAdditiveMode = ( g_Font.m_nBlur || g_Font.m_nScanlines );

	// a custom font requires special processing
	bool bCustomFont = g_Font.m_pCustomFilename != NULL;

    // Save the font image file (.tga)
    if ( FAILED( g_Font.WriteFontImageFile( strTGAFileName, bAdditiveMode, bCustomFont ) ) )
    {
        m_pMainWnd->MessageBox( "Could not write the font texture image file.",
                                "Error", MB_ICONERROR|MB_OK );
    }
}

// Desc: Display about box
void CFontMakerApp::OnAbout()
{
    CDialog dlg(IDD_ABOUT);
    dlg.DoModal();
}

// Desc: Display app help
void CFontMakerApp::OnHelp()
{
    HKEY hRegKey;

    if( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
                                       _T("SOFTWARE\\Microsoft\\XboxSDK"),
                                       0, KEY_QUERY_VALUE, &hRegKey ) )
    {
        DWORD dwSize = MAX_PATH;
        CHAR  InstallPath[MAX_PATH];

        if( ERROR_SUCCESS == RegQueryValueEx( hRegKey, _T("InstallPath"), NULL,
                                              NULL, (unsigned char *)InstallPath, &dwSize ) )
        {
            CString path = InstallPath;
            path += _T("\\doc\\xboxsdk.chm::/xbox_jbh_tool_fontmaker.htm");

            ::HtmlHelp( m_pMainWnd->GetSafeHwnd(), path, HH_DISPLAY_TOPIC, NULL );
            RegCloseKey( hRegKey );
            return;
        }
        RegCloseKey( hRegKey );
    }

    MessageBox( m_pMainWnd->GetSafeHwnd(),
                "Unable to find the Xbox SDK Help file xboxsdk.chm.",
                "Help file error", MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL );
}

// Desc: User chose to exit the app
void CFontMakerApp::OnExit()
{
    // Send a close message to the main window
    m_pMainWnd->SendMessage( WM_CLOSE );
}

// Desc: Do some cleanup before exitting the app

// Desc: User changed the status of the selected glyph
HRESULT CFontMakerApp::CalculateAndRenderGlyphs()
{
    HRESULT hr;

    // This may take some time, so display a wait cursor
    HCURSOR hOldCursor = GetCursor();
    SetCursor( m_hWaitCursor );

    // Draw the font glyphs, which may have changed layout
    if( FAILED( hr = g_Font.CalculateAndRenderGlyphs() ) )
        return hr;

    // Re-select the current glyph since the font data may have changed
    theApp.UpdateSelectedGlyph( g_bIsGlyphSelected, g_iSelectedGlyphNum );

    // Inform the view of the new font glyphs
    m_pView->OnNewFontGlyphs();

    // Restore the cursor
    SetCursor( hOldCursor );

    return S_OK;
}