void AdvancedCB(long ID, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;

    C_Window *win;

    win = gMainHandler->FindWindow(SETUP_ADVANCED_WIN);

    if ( not win) return;

    gMainHandler->ShowWindow(win);
    gMainHandler->WindowToFront(win);
}

#include "falclib.h"
#include "chandler.h"
#include "userids.h"
#include "PlayerOp.h"
#include <mmsystem.h>
#include "sim/include/stdhdr.h"
#include "sim/include/simio.h"
#include "Graphics/Include/render3d.h"
#include "Graphics/Include/renderow.h"
#include "Graphics/Include/drawBSP.h"
#include "Graphics/Include/matrix.h"
#include "Graphics/Include/loader.h"
#include "objectiv.h"
#include "cbsplist.h"
#include "c3dview.h"
#include "ui_setup.h"
#include "Graphics/Include/RViewPnt.h"
#include "dispcfg.h"
#include "f4find.h"
#include "Graphics/Include/draw2d.h"
#include "Graphics/Include/devmgr.h"
#include "dispopts.h"
#include "sim/include/sinput.h"
#include "classtbl.h"
#include "Campaign/include/Cmpclass.h"
#include "TimeMgr.h"

//JAM 18Nov03
#include "Weather.h"

#pragma warning(disable : 4706) // assignment within conditional expression
extern C_Handler *gMainHandler;
extern int GraphicSettingMult;

extern int HighResolutionHackFlag; // Used in WinMain.CPP

//extern SkyColorDataType* skycolor;

extern int MainLastGroup;
extern bool g_bAlwaysAnisotropic; // to always turn on Anisotropic label (workaround for the GF 3)
extern bool g_bForceDXMultiThreadedCoopLevel;
extern bool g_bEnableNonPersistentTextures;
extern bool g_bEnableStaticTerrainTextures;
extern bool g_bCheckBltStatusBeforeFlip;
//extern bool g_bForceSoftwareGUI; // not switchable inside the game
extern bool g_bVoodoo12Compatible;

#ifdef _DEBUG
bool g_bEnumSoftwareDevices = true;
#else
bool g_bEnumSoftwareDevices = false;
#endif

C_3dViewer *SetupViewer = NULL;
RViewPoint *tmpVpoint = NULL;
ObjectPos *Objects = NULL;
FeaturePos *Features = NULL;
short NumObjects = 0, NumFeatures = 0;

extern const Trotation IMatrix;

//defined in this file
void ChangeViewpointCB(long ID, short hittype, C_Base *control);

//defined in another file
void PositandOrientSetData(float x, float y, float z, float pitch, float roll, float yaw,
                           Tpoint* simView, Trotation* viewRotation);
void STPSetupControls(void);

const int SMOKE = 1000;
Drawable2D *Smoke = NULL;

void STPEnterCrit()
{
    F4EnterCriticalSection(SetupCritSection);
}

void STPLeaveCrit()
{
    F4LeaveCriticalSection(SetupCritSection);
}

void STPMoveRendererCB(C_Window *win)
{
    if (SetupViewer)
        SetupViewer->Viewport(win, 2);
}//MoveRendererCB

void STPViewTimerCB(long, short, C_Base *control)
{
    control->SetReady(1);

    if (control->GetFlags() bitand C_BIT_ABSOLUTE)
    {
        control->Parent_->RefreshWindow();
    }
    else
        control->Parent_->RefreshClient(control->GetClient());
}//ViewTimerCB

void STPDisplayCB(long, short, C_Base *)
{
    F4EnterCriticalSection(SetupCritSection);

    if (SetupViewer)
        SetupViewer->ViewOTW();

    F4LeaveCriticalSection(SetupCritSection);
}//DisplayCB

void InitializeViewer(C_Window *win, RenderOTW *renderer)
{
    C_Slider *slider;
    C_Button *button;

    slider = (C_Slider *)win->FindControl(OBJECT_DETAIL);

    if (slider not_eq NULL)
    {
        renderer->SetObjectDetail((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 1.5f + 0.5f);
    }

    /* slider=(C_Slider *)win->FindControl(TEXTURE_DISTANCE);
     if(slider not_eq NULL)
     {
     float sliderPos;
     sliderPos = (float)slider->GetSliderPos()/(slider->GetSliderMax()-slider->GetSliderMin());
     renderer->SetTerrainTextureLevel( (int)floor(sliderPos * 4.0f) );
     }
    */
    /* button=(C_Button *)win->FindControl(OBJECT_TEXTURES);
     if(button not_eq NULL)
     {
     renderer->SetObjectTextureState( button->GetState() );
     }
    */

    //JAM 16Jan04
    button = (C_Button *)win->FindControl(SETUP_SPECULAR_LIGHTING);

    if (button not_eq NULL)
    {
        if (button->GetState() == C_STATE_1)
            DisplayOptions.bSpecularLighting = true;
        else
            DisplayOptions.bSpecularLighting = false;
    }

    //JAM 07Dec03
    button = (C_Button *)win->FindControl(SETUP_REALWEATHER_SHADOWS);

    if (button not_eq NULL)
    {
        if (button->GetState() == C_STATE_1)
            PlayerOptions.SetDispFlag(DISP_SHADOWS);
        else
            PlayerOptions.ClearDispFlag(DISP_SHADOWS);
    }

    /*
     button=(C_Button *)win->FindControl(BILINEAR_FILTERING);
     if(button not_eq NULL)
     {
     renderer->SetFilteringMode( button->GetState() );
     }
    */
    button = (C_Button *)win->FindControl(HAZING);

    if (button not_eq NULL)
    {
        renderer->SetHazeMode(button->GetState());
    }

    /* button=(C_Button *)win->FindControl(GOUROUD);
     if(button not_eq NULL)
     {
     renderer->SetSmoothShadingMode(button->GetState());
     }

     button=(C_Button *)win->FindControl(ALPHA_BLENDING);
     if(button not_eq NULL)
     {
     renderer->SetAlphaMode( button->GetState() );
     }*/
}

void InsertSmokeCloud()
{
    FILE *fp;
    char filename[MAX_PATH];

    sprintf(filename, "%s\\config\\viewer.dat", FalconDataDirectory);
    fp = fopen(filename, "rb");

    if (fp)
    {
        ViewPos View;
        Trotation rot = IMatrix;
        Tpoint pos = {0.0f};
        float scale = 100.0F;
        RViewPoint *VP;

        fread(&View, sizeof(ViewPos), 1, fp);
        fclose(fp);
        fp = NULL;

        VP = SetupViewer->GetVP();

        PositandOrientSetData(View.Xpos * FEET_PER_KM + 300, View.Ypos * FEET_PER_KM - 100,
                              View.CamZ + View.Zpos + 100, 0, 0, 0, &pos, &rot);

        Smoke = new Drawable2D(DRAW2D_SMOKECLOUD1, scale, &pos);

        VP->InsertObject(Smoke);
    }
}

void LoadObjects(ViewPos &View , C_Window *win)
{
    FILE *fp;
    BSPLIST *list;
    float Temp;
    Trotation rot = IMatrix;
    Tpoint pos = {0.0f};
    char filename[MAX_PATH];
    float scale = 1.0F;
    C_Slider *slider;

    sprintf(filename, "%s\\config\\viewer.dat", FalconDataDirectory);
    fp = fopen(filename, "rb");

    if (fp)
    {
        fread(&View, sizeof(ViewPos), 1, fp);

        fread(&Temp, sizeof(float), 1, fp);

        if (Objects)
            delete [] Objects;

        NumObjects = static_cast<short>(FloatToInt32(Temp));

        Objects = new ObjectPos[NumObjects];

        fread(Objects, sizeof(ObjectPos), NumObjects, fp);

        fread(&Temp, sizeof(float), 1, fp);

        if (Features)
            delete [] Features;

        NumFeatures = static_cast<short>(FloatToInt32(Temp));

        Features = new FeaturePos[NumFeatures];

        fread(Features, sizeof(FeaturePos), NumFeatures, fp);

        fclose(fp);

        fp = NULL;

        slider = (C_Slider *)win->FindControl(VEHICLE_SIZE);

        if (slider not_eq NULL)
        {
            scale = ((float)slider->GetSliderPos() / (float)(slider->GetSliderMax() - slider->GetSliderMin()) * 4.0F + 1.0F);
        }

        if (NumObjects)
        {
            for (int i = 0; i < NumObjects; i++)
            {
                PositandOrientSetData(View.Xpos * FEET_PER_KM + Objects[i].Xpos , View.Ypos * FEET_PER_KM + Objects[i].Ypos,
                                      Objects[i].Zpos, Objects[i].Pitch, Objects[i].Roll, Objects[i].Yaw, &pos, &rot);
                list = SetupViewer->LoadBSP(i, FloatToInt32(Objects[i].VisID), TRUE);
                ((DrawableBSP*)list->object)->Update(&pos, &rot);

                if (Objects[i].VisID == MapVisId(VIS_F16C))
                    ((DrawableBSP*)list->object)->SetSwitchMask(10, TRUE);

                list->object->SetScale(scale);
            }
        }

        if (NumFeatures)
        {
            for (int i = 0; i < NumFeatures; i++)
            {
                PositandOrientSetData(View.Xpos * FEET_PER_KM + Features[i].Xpos , View.Ypos * FEET_PER_KM + Features[i].Ypos,
                                      Features[i].Zpos, 0.0f, 0.0f, Features[i].Facing, &pos, &rot);
                list = SetupViewer->LoadBuilding(i + 100, FloatToInt32(Features[i].VisID), &pos, 0.0f);
                ((DrawableBSP*)list->object)->Update(&pos, &rot);
            }
        }

    }
}

void STPRender(C_Base *control)
{
    C_Text *text = NULL;

    if (SetupViewer == NULL)
    {
        SetCursor(gCursors[CRSR_WAIT]);

        RenderOTW *renderer = NULL;
        RViewPoint *viewpt = NULL;
        ViewPos View = {0.0f};
        C_Slider *slider = NULL;
        Tpoint pos = {0.0F};
        int objdetail = 0;

        F4EnterCriticalSection(SetupCritSection);

        SetupViewer = new C_3dViewer;
        SetupViewer->Setup();
        SetupViewer->Viewport(control->Parent_, 2); // use client 2 for this window

        short terrlvl = 0;
        float terrdist = 40.0F;

        slider = (C_Slider *)control->Parent_->FindControl(TERRAIN_DETAIL);

        if (slider not_eq NULL)
        {
            int mid;
            mid = (slider->GetSliderMax() - slider->GetSliderMin()) / 2;

            if (slider->GetSliderPos() > mid)
            {
                terrdist = (40.0f + ((float)slider->GetSliderPos() - mid) / mid * 40.0f);
                terrlvl = 0;
            }
            else
            {
                terrdist = 40.0f;
                terrlvl = static_cast<short>(FloatToInt32(2 - ((float)slider->GetSliderPos() / mid * 2)));
            }
        }

        SetupViewer->SetTextureLevels(terrlvl, 4);
        SetupViewer->SetViewDistance(terrdist * FEET_PER_KM);

        LoadObjects(View, control->Parent_);
        SetupViewer->SetPosition(View.Xpos * FEET_PER_KM, View.Ypos * FEET_PER_KM, View.Zpos);
        SetupViewer->SetCamera(View.CamX, View.CamY, View.CamZ, View.CamYaw, View.CamPitch, View.CamRoll);
        SetupViewer->InitOTW(30.0f, FALSE);

        viewpt = SetupViewer->GetVP();
        viewpt->GetPos(&pos);

        renderer = SetupViewer->GetRendOTW();
        InitializeViewer((C_Window *)control->Parent_, renderer);

        slider = (C_Slider *)control->Parent_->FindControl(DISAGG_LEVEL);

        if (slider not_eq NULL)
        {
            objdetail = FloatToInt32((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 5 + 0.5F);
        }

        if (NumObjects)
        {
            for (int i = 0; i < NumObjects; i++)
            {
                SetupViewer->AddToView(i);
            }
        }

        if (NumFeatures)
        {
            for (int i = 0; i < NumFeatures; i++)
            {
                if (Features[i].Priority <= objdetail)
                    SetupViewer->AddToView(i + 100);
            }
        }

        InsertSmokeCloud();

        TheLoader.WaitForLoader();

        F4LeaveCriticalSection(SetupCritSection);

        text = (C_Text *)control->Parent_->FindControl(LOADING);

        if (text)
        {
            text->SetFlagBitOn(C_BIT_INVISIBLE);
            text->Refresh();
        }

        if ( not tmpVpoint)
        {
            tmpVpoint = new RViewPoint;
            tmpVpoint->Setup(80.0f * FEET_PER_KM, 0, 4, DisplayOptions.bZBuffering);
            tmpVpoint->Update(&pos);
        }

        SetCursor(gCursors[CRSR_F16]);
        control->Parent_->RefreshClient(2);
        ready = TRUE;
    }
}//STPRender

void RenderViewCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;

    C_Text *text;

    if (((C_Button *)control)->GetState())
    {
        text = (C_Text *)control->Parent_->FindControl(LOADING);

        if (text)
        {
            text->SetFlagBitOff(C_BIT_INVISIBLE);
            text->Refresh();
        }

        PostMessage(gMainHandler->GetAppWnd(), FM_STP_START_RENDER, 0, (LPARAM)control);
    }
    else
    {
        if (SetupViewer)
        {
            if ( not ready)
            {
                ((C_Button *)control)->SetState(C_STATE_1);
                ((C_Button *)control)->Refresh();
                return;
            }

            ready = FALSE;
            F4EnterCriticalSection(SetupCritSection);

            RViewPoint *viewpt;
            viewpt = SetupViewer->GetVP();
            viewpt->RemoveObject(Smoke);
            delete Smoke;
            Smoke = NULL;
            SetupViewer->Cleanup();
            delete SetupViewer;
            SetupViewer = NULL;

            F4LeaveCriticalSection(SetupCritSection);
            control->Parent_->RefreshWindow();
        }
    }
}

void ChangeViewpointCB(long, short, C_Base *)
{
    static int count = 0;

    C_Window *win;

    if (ready)
    {
        // Update the Joystick control
        GetJoystickInput();

        if (IO.digital[0] or ((count %= 3) == 0))
        {
            win = gMainHandler->FindWindow(SETUP_WIN);

            if (win not_eq NULL)
            {
                F4EnterCriticalSection(SetupCritSection);

                if (SetupViewer == NULL)
                {
                    F4LeaveCriticalSection(SetupCritSection);
                    return;
                }

                float pitchChg = 0.0f, yawChg = 0.0f;
                float altChg = 0.0f;
                float newPitch = 0.0f, newYaw = 0.0f, newAlt;

                // Retro 31Dec2003
                extern AxisMapping AxisMap;

                if (AxisMap.FlightControlDevice not_eq -1)
                    if (IO.digital[(AxisMap.FlightControlDevice - SIM_JOYSTICK1)*SIMLIB_MAX_DIGITAL])
                    {
                        pitchChg = IO.analog[AXIS_PITCH].engrValue * PITCH_CHG;
                        yawChg = IO.analog[AXIS_ROLL].engrValue * YAW_CHG;
                        altChg = 1.0f - IO.analog[AXIS_THROTTLE].engrValue;

                        if (IO.digital[((AxisMap.FlightControlDevice - SIM_JOYSTICK1)*SIMLIB_MAX_DIGITAL) + 1])
                        {
                            altChg = altChg * altChg * ALT_CHG;
                        }
                        else
                        {
                            altChg = altChg * altChg * ALT_CHG * -1;
                        }
                    }

                if (fabs(pitchChg) < 0.5)
                    pitchChg = 0.0f;

                newPitch = SetupViewer->GetCameraPitch() + pitchChg;

                if (newPitch > 90.0f)
                    newPitch = 90.0f;
                else if (newPitch < -90.0f)
                    newPitch = -90.0f;

                if (fabs(yawChg) < 0.5)
                    yawChg = 0.0f;

                newYaw = SetupViewer->GetCameraHeading() + yawChg;

                if (fabs(altChg) < .5f)
                    altChg = 0.0f;

                newAlt = altChg + SetupViewer->GetCameraZ();

                if (newAlt > MIN_ALT)
                    newAlt = MIN_ALT;
                else if (newAlt < MAX_ALT)
                    newAlt = MAX_ALT;

                SetupViewer->SetCamera(SetupViewer->GetCameraX(), SetupViewer->GetCameraY(),
                                       newAlt, newYaw, newPitch, 0.0f);

                F4LeaveCriticalSection(SetupCritSection);
                win->RefreshWindow();
            }

        }

        count++;
    }
}//ChangeViewpointCB

void ScalingCB(long, short hittype, C_Base *)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;
}

void GouraudCB(long, short hittype, C_Base *control)
{
    /* if(hittype not_eq C_TYPE_LMOUSEUP)
     return;

     if(SetupViewer == NULL)
     return;

     RenderOTW *renderer;

     renderer = SetupViewer->GetRendOTW();

     if(((C_Button *)control)->GetState())
     renderer->SetSmoothShadingMode( 1 );
     else
     renderer->SetSmoothShadingMode( 0 );

     control->Parent_->RefreshClient(2);

     control->Parent_->RefreshClient(2);
     //have the rendered view update with new settings
    */
}//GouraudCB

void HazingCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;

    if (SetupViewer == NULL)
        return;

    RenderOTW *renderer;

    renderer = SetupViewer->GetRendOTW();

    if (((C_Button *)control)->GetState())
        renderer->SetHazeMode(1);
    else
        renderer->SetHazeMode(0);

    control->Parent_->RefreshClient(2);

    //have the rendered view update with new settings

}//HazingCB

//JAM 07Dec03
void RealWeatherShadowsCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;

    if (SetupViewer == NULL)
        return;

    RenderOTW *renderer;

    renderer = SetupViewer->GetRendOTW();

    if (((C_Button *)control)->GetState())
        PlayerOptions.SetDispFlag(DISP_SHADOWS);
    else
        PlayerOptions.ClearDispFlag(DISP_SHADOWS);

    control->Parent_->RefreshClient(2);
}

void BilinearFilterCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;

    if (SetupViewer == NULL)
        return;

    RenderOTW *renderer;

    renderer = SetupViewer->GetRendOTW();

    if (((C_Button *)control)->GetState())
        renderer->SetFilteringMode(TRUE);
    else
        renderer->SetFilteringMode(FALSE);

    control->Parent_->RefreshClient(2);

    //have the rendered view update with new settings

}//BilinearFilterCB

/*void ObjectTextureCB(long,short hittype,C_Base *control)
{
 if(hittype not_eq C_TYPE_LMOUSEUP)
 return;

 if(SetupViewer == NULL)
 return;

 RenderOTW *renderer;

 renderer = SetupViewer->GetRendOTW();

 if(((C_Button *)control)->GetState())
 renderer->SetObjectTextureState( TRUE );
 else
 renderer->SetObjectTextureState( FALSE );

 control->Parent_->RefreshClient(2);

 //have the rendered view update with new settings

}//ObjectTextureCB
*/
void RemoveObjFromView(int objID)
{
    C_BSPList *bsplist;
    BSPLIST   *list;

    F4EnterCriticalSection(SetupCritSection);

    bsplist = SetupViewer->GetBSPList();

    // I don't think this will happen, but time is short so lets be safe...
    if ( not bsplist) return;

    list = bsplist->Root_;

    while (list)
    {
        if (list->ID == objID)
            break;

        list = list->Next;
    }

    if (list)
    {
        RViewPoint *tVP;

        tVP = SetupViewer->GetVP();

        tVP->RemoveObject(list->object);
    }

    F4LeaveCriticalSection(SetupCritSection);

}
void BuildingDetailCB(long, short hittype, C_Base *control)
{
    C_Slider *slider;
    int objdetail;
    static int prevdetail = -1;

    if (hittype not_eq C_TYPE_MOUSEMOVE)
        return;

    slider = (C_Slider *)control;
    objdetail = FloatToInt32((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 5 + 0.5F);

    C_EditBox *ebox;
    ebox = (C_EditBox *)control->Parent_->FindControl(slider->GetUserNumber(0));

    if (ebox)
    {
        ebox->SetInteger(objdetail + 1);
        ebox->Refresh();
    }

    F4EnterCriticalSection(SetupCritSection);

    if (SetupViewer == NULL)
    {
        F4LeaveCriticalSection(SetupCritSection);
        return;
    }

    if (NumFeatures)
    {

        if (prevdetail < objdetail)
        {
            if (NumFeatures)
            {
                for (int i = 0; i < NumFeatures; i++)
                {
                    if ((Features[i].Priority <= objdetail) and (Features[i].Priority > prevdetail))
                        SetupViewer->AddToView(i + 100);
                }
            }
        }
        else if (prevdetail > objdetail)
        {
            for (int i = 0; i < NumFeatures; i++)
            {
                if ((Features[i].Priority > objdetail) and (Features[i].Priority <= prevdetail))
                    RemoveObjFromView(i + 100);
            }
        }

        prevdetail = objdetail;
    }

    control->Parent_->RefreshWindow();
    F4LeaveCriticalSection(SetupCritSection);

}//BuildingDetailCB

void PlayerBubbleCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_MOUSEMOVE)
        return;

    C_Slider    *slider;
    slider = (C_Slider *)control;

    C_EditBox *ebox;
    ebox = (C_EditBox *)control->Parent_->FindControl(slider->GetUserNumber(0));

    if (ebox)
    {
        ebox->SetInteger(FloatToInt32((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 6 * GraphicSettingMult + 1.5f));
        ebox->Refresh();
    }
}

void ObjectDetailCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_MOUSEMOVE)
        return;

    float detail;
    C_Slider    *slider;
    slider = (C_Slider *)control;

    C_EditBox *ebox;
    ebox = (C_EditBox *)control->Parent_->FindControl(slider->GetUserNumber(0));

    if (ebox)
    {
        ebox->SetInteger(FloatToInt32((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 6 * GraphicSettingMult + 1.5f));
        ebox->Refresh();
    }

    if (SetupViewer == NULL)
        return;

    RenderOTW *renderer;
    renderer = SetupViewer->GetRendOTW();
    detail = ((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 1.5f * GraphicSettingMult);
    renderer->SetObjectDetail(detail);

    //have the rendered view update with new settings
    control->Parent_->RefreshWindow();

}//VehicleDetailCB

void VehicleSizeCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_MOUSEMOVE)
        return;

    C_Slider *slider;
    BSPLIST *list;
    int scale;

    slider = (C_Slider *)control;
    scale = FloatToInt32((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 4 + 1);

    C_EditBox *ebox;
    ebox = (C_EditBox *)control->Parent_->FindControl(slider->GetUserNumber(0));

    if (ebox)
    {
        ebox->SetInteger(scale);
        ebox->Refresh();
    }

    if (SetupViewer == NULL)
        return;

    static int prevscale;

    if (prevscale not_eq scale)
    {
        list = ((C_BSPList *)SetupViewer->GetBSPList())->Root_;

        while (list)
        {
            if (list->ID < 100)
                list->object->SetScale((float)scale);

            list = list->Next;
        }

        prevscale = scale;
    }

    //have the rendered view update with new settings
    control->Parent_->RefreshWindow();

}//VehicleSizeCB

void TerrainDetailCB(long, short hittype, C_Base *control)
{
    C_Slider *slider;
    static int prevpos = -1;

    if (hittype not_eq C_TYPE_MOUSEMOVE)
        return;

    slider = (C_Slider *)control;

    C_EditBox *ebox;
    ebox = (C_EditBox *)control->Parent_->FindControl(slider->GetUserNumber(0));

    if (ebox)
    {
        ebox->SetInteger(FloatToInt32((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 6.0F * GraphicSettingMult  + 1.5F));
        ebox->Refresh();
    }

    if (SetupViewer == NULL)
        return;

    int step;
    step = (slider->GetSliderMax() - slider->GetSliderMin()) / (6 * GraphicSettingMult);

    if (abs(slider->GetSliderPos() - prevpos) > step - 1)
    {
        SetCursor(gCursors[CRSR_WAIT]);

        int disagglvl;
        short terrlvl;
        float terrdist;
        RenderOTW *renderer;
        RViewPoint *viewpt;
        C_BSPList *bsplist;
        BSPLIST *cur;
        Tpoint pos;

        prevpos = slider->GetSliderPos();

        if (slider->GetSliderPos() > 2 * step)
        {
            terrdist = 40.0f + ((float)slider->GetSliderPos() / step - 2) * 10.0f;
            terrlvl = 0;
        }
        else
        {
            terrdist = 40.0f;
            terrlvl = static_cast<short>(FloatToInt32(2.0F - ((float)slider->GetSliderPos() / step)));
        }

        F4EnterCriticalSection(SetupCritSection);

        if (SetupViewer)
        {
            C_Slider *tslider;
            C_Button *button;

            renderer = SetupViewer->GetRendOTW();
            viewpt = SetupViewer->GetVP();

            viewpt->GetPos(&pos);

            bsplist = SetupViewer->GetBSPList();
            cur = bsplist->GetFirst();

            while (cur)
            {
                if (((DrawableBSP*)cur->object)->InDisplayList())
                    viewpt->RemoveObject(cur->object);

                cur = cur->Next;
            }

            viewpt->RemoveObject(Smoke);
            delete Smoke;
            Smoke = NULL;
            viewpt->Cleanup();
            viewpt->Setup(terrdist * FEET_PER_KM, terrlvl, 4, DisplayOptions.bZBuffering);
            viewpt->Update(&pos);

            renderer->Cleanup();

            renderer->Setup(gMainHandler->GetFront(), viewpt);

            //reset all values for new renderer
            tslider = (C_Slider *)control->Parent_->FindControl(OBJECT_DETAIL);

            if (tslider)
            {
                renderer->SetObjectDetail((float)tslider->GetSliderPos() / (tslider->GetSliderMax() - tslider->GetSliderMin()) * 1.5f + 0.5f);
            }

            /* tslider = (C_Slider *)control->Parent_->FindControl(TEXTURE_DISTANCE);
             if(tslider)
             {
             renderer->SetTerrainTextureLevel(FloatToInt32((float)tslider->GetSliderPos()/(tslider->GetSliderMax()-tslider->GetSliderMin())* 4.0f));
             }

             button = (C_Button *)control->Parent_->FindControl(OBJECT_TEXTURES);
             if(button)
             {
             if(button->GetState())
             renderer->SetObjectTextureState( TRUE );
             else
             renderer->SetObjectTextureState( FALSE );
             }
             button = (C_Button *)control->Parent_->FindControl(BILINEAR_FILTERING);

             if(button)
             {
             if(button->GetState())
             renderer->SetFilteringMode( TRUE );
             else
             renderer->SetFilteringMode( FALSE );
             }
            */

            /* button = (C_Button *)control->Parent_->FindControl(ALPHA_BLENDING);
             if(button)
             {
             if(button->GetState())
             renderer->SetAlphaMode( TRUE );
             else
             renderer->SetAlphaMode( FALSE );
             }
            */
            button = (C_Button *)control->Parent_->FindControl(HAZING);

            if (button)
            {
                if (button->GetState())
                    renderer->SetHazeMode(TRUE);
                else
                    renderer->SetHazeMode(FALSE);
            }

            /* button = (C_Button *)control->Parent_->FindControl(GOUROUD);
             if(button)
             {
             if(button->GetState())
             renderer->SetSmoothShadingMode( TRUE );
             else
             renderer->SetSmoothShadingMode( FALSE );
             }
            */

            InitializeViewer((C_Window *)control->Parent_, renderer);

            SetupViewer->Viewport((C_Window *)control->Parent_, 2);

            slider = (C_Slider *)control->Parent_->FindControl(DISAGG_LEVEL);

            if (slider not_eq NULL)
            {
                disagglvl = FloatToInt32((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 5 + 0.5F);

                if (NumFeatures)
                {
                    for (int i = 0; i < NumFeatures; i++)
                    {
                        if (Features[i].Priority <= disagglvl)
                            SetupViewer->AddToView(i + 100);
                    }
                }
            }

            if (NumObjects)
            {
                for (int i = 0; i < NumObjects; i++)
                {
                    SetupViewer->AddToView(i);
                }
            }

            InsertSmokeCloud();

            SetCursor(gCursors[CRSR_F16]);
        }

        F4LeaveCriticalSection(SetupCritSection);

        control->Parent_->RefreshWindow();
    }
}

/*void TextureDistanceCB(long,short hittype,C_Base *control)
{
 if(hittype not_eq C_TYPE_MOUSEMOVE)
 return;

 C_Slider *slider;
 slider = (C_Slider *)control;
 int pos;
 pos = FloatToInt32((float)slider->GetSliderPos()/(slider->GetSliderMax()-slider->GetSliderMin()) * 4.0f);

 C_EditBox *ebox;
 ebox = (C_EditBox *)control->Parent_->FindControl(slider->GetUserNumber(0));
 if(ebox)
 {
 ebox->SetInteger(pos + 1);
 ebox->Refresh();
 }

 if(SetupViewer)
 {
 RenderOTW *renderer;
 int TexLev;

 renderer = SetupViewer->GetRendOTW();

 TexLev = renderer->GetTerrainTextureLevel();

 //have the rendered view update with new settings
 if(pos not_eq TexLev)
 {
 renderer->SetTerrainTextureLevel(pos);
 }
 control->Parent_->RefreshWindow();

 }
}//TextureDistanceCB
*/
void SfxLevelCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_MOUSEMOVE)
        return;

    C_Slider *slider;
    slider = (C_Slider *)control;
    int pos;
    pos = FloatToInt32((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin()) * 4.0f);

    C_EditBox *ebox;
    ebox = (C_EditBox *)control->Parent_->FindControl(slider->GetUserNumber(0));

    if (ebox)
    {
        ebox->SetInteger(pos + 1);
        ebox->Refresh();
    }

}//SfxLevelCB

void BuildVideoCardList(C_ListBox *lbox)
{
    const char *buf;
    int i = 0;
    int Driver;
    char buf2[256];
    long value;

    C_ListBox *VidCardList = (C_ListBox *)lbox->Parent_->FindControl(SET_VIDEO_DRIVER);
    Driver = VidCardList->GetTextID() - 1;

    DeviceManager::DDDriverInfo *pDI = FalconDisplay.devmgr.GetDriver(Driver);

    if ( not pDI) return;

    value = lbox->GetTextID();
    lbox->RemoveAllItems();

    while (buf = FalconDisplay.devmgr.GetDeviceName(Driver, i))
    {
        if ( not g_bEnumSoftwareDevices)
        {
            // check for software device
            DeviceManager::DDDriverInfo::D3DDeviceInfo *pD3DDI = pDI->GetDevice(i);

            if (pD3DDI and not pD3DDI->IsHardware())
            {
                i++;
                continue;
            }
        }

        strcpy(buf2, buf);
        i++;

        lbox->AddItem(i, C_TYPE_ITEM, buf2);
    }

    ShiAssert(i > 0);
    lbox->SetValue(value);
    lbox->Refresh();
}

void BuildVideoDriverList(C_ListBox *lbox)
{
    char buf2[256];
    const char *buf;
    int i = 0;

    lbox->RemoveAllItems();

    while (buf = FalconDisplay.devmgr.GetDriverName(i))
    {
        if (FalconDisplay.devmgr.GetDeviceName(i, 0))
        {
            strcpy(buf2, buf);
            lbox->AddItem(i + 1, C_TYPE_ITEM, buf2);
        }

        i++;
    }

    ShiAssert(i > 0);
    lbox->Refresh();
}

void BuildResolutionList(C_ListBox *lbox)
{
    int i = 0, Card, Driver;
    char buf2[256];
    long value;
    UINT width, height, depth;
    int isel = -1;
    int nNumItems = 0;

    C_ListBox *VidDriverList = (C_ListBox *)lbox->Parent_->FindControl(SET_VIDEO_DRIVER);
    Driver = VidDriverList->GetTextID() - 1;

    C_ListBox *VidCardList = (C_ListBox *)lbox->Parent_->FindControl(SET_VIDEO_CARD);
    Card = VidCardList->GetTextID() - 1;

    value = lbox->GetTextID();
    lbox->RemoveAllItems();

    DeviceManager::DDDriverInfo *pDI = FalconDisplay.devmgr.GetDriver(Driver);

    if ( not pDI) return;

    DeviceManager::DDDriverInfo::D3DDeviceInfo *pD3DDI = pDI->GetDevice(Card);

    if ( not pD3DDI) return;

    // OW
#if 1

    while (FalconDisplay.devmgr.GetMode(Driver, Card, i++, &width, &height, &depth))
    {
        // For now we only allow 640x480, 800x600, 1280x960, 1600x1200
        // (MPR already does the 4:3 aspect ratio check for us)
        if (height > 400 and ((width == 640 or width == 800 or width == 1024 or
                              (width == 1280 and height == 960) or width == 1600 or HighResolutionHackFlag)))
        {
            if (depth == 8 or depth == 24)
                continue;

            // if(depth == 16 and not (pD3DDI->m_devDesc.dwDeviceRenderBitDepth bitand DDBD_16))
            if (depth == 16)
                continue;
            else if (depth == 32 and not (pD3DDI->m_devDesc.dwDeviceRenderBitDepth bitand DDBD_32))
                continue;

            sprintf(buf2, "%0dx%0d - %d Bit", width, height, depth);
            lbox->AddItem(i - 1, C_TYPE_ITEM, buf2);

            // remember index for current mode
            if (width == DisplayOptions.DispWidth and height == DisplayOptions.DispHeight and depth == DisplayOptions.DispDepth)
                isel = i - 1;

            nNumItems++;
        }
    }

    ShiAssert(i > 0);

    if (isel not_eq -1) lbox->SetValue(isel);
    else lbox->SetValue(value);

    lbox->Refresh();
#else

    while (buf = FalconDisplay.devmgr.GetModeName(Driver, Card, i))
    {
        strcpy(buf2, buf);
        i++;
        sscanf(buf2, "%d x %d", &width, &height);

        lbox->AddItem(width, C_TYPE_ITEM, buf2);
    }

    ShiAssert(i > 0);
    lbox->SetValue(value);
    lbox->Refresh();
#endif
}

void DisableEnableDrivers(C_ListBox *)
{

}

void DisableEnableResolutions(C_ListBox*)
{
}

void SetAdvanced()
{
    C_Window *win;
    C_Button *button;
    C_ListBox *lbox;

    win = gMainHandler->FindWindow(SETUP_WIN);

    if (win == NULL) return;

    lbox = (C_ListBox *)win->FindControl(SET_VIDEO_DRIVER);

    if ( not lbox) return;

    int nDriver = lbox->GetTextID() - 1;
    lbox = (C_ListBox *)win->FindControl(SET_VIDEO_CARD);

    if ( not lbox) return;

    int nDevice = lbox->GetTextID() - 1;
    DeviceManager::DDDriverInfo *pDI = FalconDisplay.devmgr.GetDriver(nDriver);

    if ( not pDI) return;

    DeviceManager::DDDriverInfo::D3DDeviceInfo *pD3DDI = pDI->GetDevice(nDevice);

    if ( not pD3DDI) return;

    win = gMainHandler->FindWindow(SETUP_ADVANCED_WIN);

    if ( not win) return;

    // FRB - Force Z-Buffering
    DisplayOptions.bZBuffering = TRUE;
    // FRB - Force Specular Lighting
    // DDS textures only

    //JAM 12Oct03
    button = (C_Button *) win->FindControl(SETUP_ADVANCED_ANISOTROPIC_FILTERING);

    if (button) button->SetState(DisplayOptions.bAnisotropicFiltering ? C_STATE_1 : C_STATE_0);

    button = (C_Button *) win->FindControl(SETUP_ADVANCED_LINEAR_MIPMAP_FILTERING);

    if (button) button->SetState(DisplayOptions.bLinearMipFiltering ? C_STATE_1 : C_STATE_0);

    button = (C_Button *) win->FindControl(SETUP_ADVANCED_RENDER_2DCOCKPIT);

    if (button) button->SetState(DisplayOptions.bRender2DCockpit ? C_STATE_1 : C_STATE_0);

    button = (C_Button *) win->FindControl(SETUP_ADVANCED_SCREEN_COORD_BIAS_FIX);

    if (button) button->SetState(DisplayOptions.bScreenCoordinateBiasFix ? C_STATE_1 : C_STATE_0); //Wombat778 4-01-04

    button = (C_Button *) win->FindControl(SETUP_ADVANCED_MIPMAPPING);

    if (button) button->SetState(DisplayOptions.bMipmapping ? C_STATE_1 : C_STATE_0);

    button = (C_Button *) win->FindControl(SETUP_ADVANCED_RENDER_TO_TEXTURE);

    if (button)
    {
        if (pDI->SupportsSRT()) button->SetFlagBitOn(C_BIT_ENABLED);
        else
        {
            button->SetFlagBitOff(C_BIT_ENABLED);
            DisplayOptions.bRender2Texture = false;
        }

        button->SetState(DisplayOptions.bRender2Texture ? C_STATE_1 : C_STATE_0);
    }

    //JAM
}

static void LoadBitmap(long ID, C_Button *btn, char filename[])
{
    char file[MAX_PATH];

    btn->ClearImage(0, ID);
    gImageMgr->RemoveImage(ID);
    strcpy(file, filename);
    strcat(file, ".tga");
    gImageMgr->LoadImage(ID, file, 0, 0);
    btn->Refresh();
    btn->SetImage(0, ID);
    btn->Refresh();

}

/*void SetSkyColor()
{
 C_Window *win;
 C_Button *btn;
 C_ListBox *lbox;

 win=gMainHandler->FindWindow(SETUP_SKY_WIN);
 if( not win) return;

 lbox=(C_ListBox *)win->FindControl(SETUP_SKY_COLOR);
 if (lbox)
 {
 lbox->SetValue(PlayerOptions.skycol);
 lbox->Refresh();
 }
 btn=(C_Button*)win->FindControl(SKY_COLOR_PIC);
 if(btn)
 {
 switch(skycolortime)
 {
 case 0:
 LoadBitmap(SKYCOLOR_BITMAP_ID,btn,skycolor[PlayerOptions.skycol-1].image1);
 break;
 case 1:
 LoadBitmap(SKYCOLOR_BITMAP_ID,btn,skycolor[PlayerOptions.skycol-1].image2);
 break;
 case 2:
 LoadBitmap(SKYCOLOR_BITMAP_ID,btn,skycolor[PlayerOptions.skycol-1].image3);
 break;
 case 3:
 LoadBitmap(SKYCOLOR_BITMAP_ID,btn,skycolor[PlayerOptions.skycol-1].image4);
 break;
 default:
 MonoPrint("Not allowed skycolortime found ");
 break;
 }
 }
 win->RefreshWindow();
}

void SelectSkyColorCB(long ID,short hittype,C_Base *control)
{
 C_ListBox *lbox=(C_ListBox*)control;

 if(hittype not_eq C_TYPE_SELECT)
 return;

 ID=lbox->GetTextID();
 PlayerOptions.skycol = lbox->GetTextID();
 SetSkyColor();
}

void SkyColTimeCB(long ID,short hittype,C_Base *control)
{
 if(hittype not_eq C_TYPE_LMOUSEUP)
 return;

 if( not control)
 return;

 switch(control->GetID())
 {
 case SKY_COLOR_TIME_1: // 7:00
 skycolortime = 0;
 break;
 case SKY_COLOR_TIME_2: // 12:00
 skycolortime = 1;
 break;
 case SKY_COLOR_TIME_3: // 19:00
 skycolortime = 2;
 break;
 case SKY_COLOR_TIME_4: // 0:00
 skycolortime = 3;
 break;
 default:
 MonoPrint("Not allowed button type");
 }
 SetSkyColor();
}
*/

void VideoCardCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_SELECT)
        return;

    C_ListBox *lbox;

    lbox = (C_ListBox *)control->Parent_->FindControl(SET_RESOLUTION);

    if (lbox)
        BuildResolutionList(lbox);

    SetAdvanced();
}

void VideoDriverCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_SELECT)
        return;

    C_ListBox *lbox = (C_ListBox *)control->Parent_->FindControl(SET_VIDEO_CARD);

    if (lbox)
        BuildVideoCardList(lbox);

    lbox = (C_ListBox *)control->Parent_->FindControl(SET_RESOLUTION);

    if (lbox)
        BuildResolutionList(lbox);

    // JB 011124 No relevance for the DX7 engine
    /*
     C_Button *button;
     if( ((C_ListBox*)control)->GetTextID() > 1)
     {
     button=(C_Button *)control->Parent_->FindControl(ALPHA_BLENDING);
     if(button not_eq NULL)
     {
     button->SetState(C_STATE_1);
     button->Refresh();
     }

     button=(C_Button *)control->Parent_->FindControl(BILINEAR_FILTERING);
     if(button not_eq NULL)
     {
     button->SetState(C_STATE_1);
     button->Refresh();
     }
     }
     else
     {
     button=(C_Button *)control->Parent_->FindControl(ALPHA_BLENDING);
     if(button not_eq NULL)
     {
     button->SetState(C_STATE_0);
     button->Refresh();
     }

     button=(C_Button *)control->Parent_->FindControl(BILINEAR_FILTERING);
     if(button not_eq NULL)
     {
     button->SetState(C_STATE_0);
     button->Refresh();
     }
     }
    */
}

void ResolutionCB(long, short hittype, C_Base *)
{
    if (hittype not_eq C_TYPE_SELECT)
        return;
}

//JAM 21Nov03
void RealWeatherCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_SELECT) return;

    C_ListBox *lbox = (C_ListBox*)control;

    if (TheCampaign.InMainUI or not ((WeatherClass *)realWeather)->lockedCondition)
    {
        PlayerOptions.weatherCondition = lbox->GetTextID() - 70207;
        ((WeatherClass *)realWeather)->UpdateCondition(PlayerOptions.weatherCondition, true);
        ((WeatherClass *)realWeather)->Init(true);
    }
    else if (((WeatherClass *)realWeather)->unlockableCondition == 0)
    {
        if (lbox->GetTextID() == 70213)
        {
            lbox->RemoveAllItems();

            lbox->AddItem(70208, C_TYPE_ITEM, "Sunny");
            lbox->AddItem(70209, C_TYPE_ITEM, "Fair");
            lbox->AddItem(70210, C_TYPE_ITEM, "Poor");
            lbox->AddItem(70211, C_TYPE_ITEM, "Inclement");

            lbox->SetValue(realWeather->weatherCondition + 70207);
            lbox->Refresh();

            ((WeatherClass *)realWeather)->lockedCondition = FALSE;
        }
    }
    else if (lbox->GetTextID() == 70213)
    {
        lbox->RemoveAllItems();

        lbox->AddItem(70208, C_TYPE_ITEM, "Sunny");
        lbox->AddItem(70209, C_TYPE_ITEM, "Fair");
        lbox->AddItem(70210, C_TYPE_ITEM, "Poor");
        lbox->AddItem(70211, C_TYPE_ITEM, "Inclement");

        lbox->SetValue(realWeather->weatherCondition + 70207);
        lbox->Refresh();

        ((WeatherClass *)realWeather)->lockedCondition = FALSE;
    }
}
//JAM

void SeasonCB(long, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_SELECT) return;

    C_ListBox *lbox = (C_ListBox*)control;
    PlayerOptions.Season = lbox->GetTextID() - 70313;
}
//THW

void SetupGraphicsControls(void)
{
    C_Window *win;
    C_Button *button;
    C_ListBox *lbox;
    C_Slider *slider;
    C_EditBox *ebox;

    win = gMainHandler->FindWindow(SETUP_WIN);

    if (win == NULL)
        return;

    lbox = (C_ListBox *)win->FindControl(SET_VIDEO_CARD);

    if (lbox not_eq NULL)
    {
        BuildVideoCardList(lbox);

        lbox->SetValue(DisplayOptions.DispVideoCard + 1);
        lbox->Refresh();
    }

    lbox = (C_ListBox *)win->FindControl(SET_VIDEO_DRIVER);

    if (lbox not_eq NULL)
    {
        BuildVideoDriverList(lbox);

        DisableEnableDrivers(lbox);
        lbox->SetValue(DisplayOptions.DispVideoDriver + 1);
        lbox->Refresh();
    }

    lbox = (C_ListBox *)win->FindControl(SET_RESOLUTION);

    if (lbox not_eq NULL)
    {
        DisableEnableResolutions(lbox);
        lbox->SetValueText(DisplayOptions.DispWidth);
        lbox->Refresh();
    }

    button = (C_Button *)win->FindControl(70136); //GOUROUD

    if (button not_eq NULL)
    {
        if (PlayerOptions.GouraudOn())
            button->SetState(C_STATE_1);
        else
            button->SetState(C_STATE_0);

        button->Refresh();
    }

    button = (C_Button *)win->FindControl(HAZING);

    if (button not_eq NULL)
    {
        if (PlayerOptions.HazingOn())
            button->SetState(C_STATE_1);
        else
            button->SetState(C_STATE_0);

        button->Refresh();
    }

    //JAM 16Jan04
    button = (C_Button *)win->FindControl(SETUP_SPECULAR_LIGHTING);

    if (button not_eq NULL)
    {
        if (DisplayOptions.bSpecularLighting)
            button->SetState(C_STATE_1);
        else
            button->SetState(C_STATE_0);

        button->Refresh();
    }

    //JAM 07Dec03
    button = (C_Button *)win->FindControl(SETUP_REALWEATHER_SHADOWS);

    if (button not_eq NULL)
    {
        if (PlayerOptions.ShadowsOn())
            button->SetState(C_STATE_1);
        else
            button->SetState(C_STATE_0);

        button->Refresh();
    }

    /*
     button=(C_Button *)win->FindControl(BILINEAR_FILTERING);
     if(button not_eq NULL)
     {
     if(PlayerOptions.FilteringOn())
     button->SetState(C_STATE_1);
     else
     button->SetState(C_STATE_0);
     button->Refresh();
     }
    */
    /* button=(C_Button *)win->FindControl(OBJECT_TEXTURES);
     if(button not_eq NULL)
     {
     if(PlayerOptions.ObjectTexturesOn())
     button->SetState(C_STATE_1);
     else
     button->SetState(C_STATE_0);
     button->Refresh();
     }
    */
    slider = (C_Slider *)win->FindControl(OBJECT_DETAIL);

    if (slider not_eq NULL)
    {
        slider->Refresh();
        ebox = (C_EditBox *)win->FindControl(OBJECT_DETAIL_READOUT);

        if (ebox)
        {
            ebox->SetInteger(FloatToInt32(PlayerOptions.ObjDetailLevel * 4.0F - 1.0F));
            ebox->Refresh();
            slider->SetUserNumber(0, OBJECT_DETAIL_READOUT);
        }

        slider->SetSliderPos(FloatToInt32((slider->GetSliderMax() - slider->GetSliderMin()) * (PlayerOptions.ObjDetailLevel - 0.5f) / 1.5f));
        slider->Refresh();
    }

    slider = (C_Slider *)win->FindControl(DISAGG_LEVEL);

    if (slider not_eq NULL)
    {
        slider->Refresh();
        ebox = (C_EditBox *)win->FindControl(DISAGG_LEVEL_READOUT);

        if (ebox)
        {
            ebox->SetInteger(PlayerOptions.BldDeaggLevel + 1);
            ebox->Refresh();
            slider->SetUserNumber(0, DISAGG_LEVEL_READOUT);
        }

        slider->SetSliderPos((slider->GetSliderMax() - slider->GetSliderMin())*PlayerOptions.ObjDeaggLevel / 100);
        slider->Refresh();
    }

    slider = (C_Slider *)win->FindControl(VEHICLE_SIZE);

    if (slider not_eq NULL)
    {
        slider->Refresh();
        slider->SetSliderPos(FloatToInt32((slider->GetSliderMax() - slider->GetSliderMin()) * (PlayerOptions.ObjMagnification - 1.0F) / 4.0F));
        ebox = (C_EditBox *)win->FindControl(VEHICLE_SIZE_READOUT);

        if (ebox)
        {
            ebox->SetInteger(FloatToInt32(PlayerOptions.ObjMagnification));
            ebox->Refresh();
            slider->SetUserNumber(0, VEHICLE_SIZE_READOUT);
        }

        slider->Refresh();
    }

    /* slider=(C_Slider *)win->FindControl(TEXTURE_DISTANCE);
     if(slider not_eq NULL)
     {
     slider->Refresh();
     ebox = (C_EditBox *)win->FindControl(TEX_DISTANCE_READOUT);
     if(ebox)
     {
     ebox->SetInteger(PlayerOptions.DispTextureLevel + 1);
     ebox->Refresh();
     slider->SetUserNumber(0,TEX_DISTANCE_READOUT);
     }
     slider->SetSliderPos((slider->GetSliderMax()-slider->GetSliderMin())*(PlayerOptions.DispTextureLevel)/4);
     slider->Refresh();
     }
    */
    slider = (C_Slider *)win->FindControl(TERRAIN_DETAIL);

    if (slider not_eq NULL)
    {
        int step;
        step = (slider->GetSliderMax() - slider->GetSliderMin()) / 6;

        slider->Refresh();

        if (PlayerOptions.DispTerrainDist > 40)
            slider->SetSliderPos(FloatToInt32(step * (2 + (PlayerOptions.DispTerrainDist - 40.0F) / 10.0F)));
        else
            slider->SetSliderPos((2 - PlayerOptions.DispMaxTerrainLevel)*step);

        slider->Refresh();

        ebox = (C_EditBox *)win->FindControl(TEX_DETAIL_READOUT);

        if (ebox)
        {
            ebox->SetInteger(FloatToInt32(((float)slider->GetSliderPos() / (slider->GetSliderMax() - slider->GetSliderMin())) * 6.0F + 1.5F));
            ebox->Refresh();
            slider->SetUserNumber(0, TEX_DETAIL_READOUT);
        }
    }

    win = gMainHandler->FindWindow(SETUP_ADVANCED_WIN);

    if ( not win) return;

    // M.N. SkyColor stuff
    // M.N. end SkyColor stuff
}

void GraphicsDefaultsCB(long, short hittype, C_Base *)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;

    PlayerOptionsClass Player;
    DisplayOptionsClass Display;

    if (Display.LoadOptions("display")) // JB 011124 Why load the wrong file?
    {
        DisplayOptions.DispWidth = Display.DispWidth;
        DisplayOptions.DispHeight = Display.DispHeight;
        DisplayOptions.DispDepth = Display.DispDepth; // OW
        DisplayOptions.DispVideoCard = Display.DispVideoCard;
        DisplayOptions.DispVideoDriver = Display.DispVideoDriver;
        DisplayOptions.DispDepth = 32; // Cobra - Always use 32-bit
    }
    else
    {
        DisplayOptions.DispWidth = 1024; // JB 011124
        DisplayOptions.DispHeight = 768; // JB 011124
        DisplayOptions.DispDepth = 32; // Cobra - Always use 32-bit
        DisplayOptions.DispVideoCard = 0;
        DisplayOptions.DispVideoDriver = 0;
    }

    if (Player.LoadOptions("default"))
    {
        /* PlayerOptions.DispFlags = DISP_HAZING|DISP_GOURAUD|DISP_SHADOWS;
         PlayerOptions.DispTerrainDist = 80.0; // JB 011124
         PlayerOptions.DispMaxTerrainLevel = 0;
         PlayerOptions.ObjFlags = DISP_OBJ_TEXTURES;
         PlayerOptions.SfxLevel = 5.0F; // JB 011124
         PlayerOptions.ObjDetailLevel = 2; // JB 011124
         PlayerOptions.ObjMagnification = 1;
         PlayerOptions.ObjDeaggLevel = 100; // 2001-11-09 M.N. from 60
         PlayerOptions.BldDeaggLevel = 5; // 2001-11-09 M.N. from 3, Realism Patch default
         PlayerOptions.PlayerBubble = 1.0F;

         DisplayOptions.bRender2Texture = false;
         DisplayOptions.bAnisotropicFiltering = false;
         DisplayOptions.bLinearMipFiltering = false;
         DisplayOptions.bMipmapping = false;
         DisplayOptions.bZBuffering = false;
         DisplayOptions.bRender2DCockpit = false;
         DisplayOptions.bFontTexelAlignment = false;
         DisplayOptions.m_texMode = DisplayOptionsClass::TEX_MODE_DDS;*/
    }

    SetupGraphicsControls();
}

// OW

// JPO - select advanced features
void AdvancedGameCB(long ID, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;

    C_Window *win;

    win = gMainHandler->FindWindow(ADVANCED_GAME_OPTIONS_WIN); // JPOLOOK - not finished yet

    if ( not win) return;

    gMainHandler->ShowWindow(win);
    gMainHandler->WindowToFront(win);
}

// M.N. Skyfix
void SkyColorCB(long ID, short hittype, C_Base *control)
{
    if (hittype not_eq C_TYPE_LMOUSEUP)
        return;

    C_Window *win;

    win = gMainHandler->FindWindow(SETUP_SKY_WIN);

    if ( not win) return;

    gMainHandler->ShowWindow(win);
    gMainHandler->WindowToFront(win);
}


TCA emitSmashableCall(CodeBlock& cb, CGMeta& meta, TCA target) {
  align(cb, &meta, Alignment::SmashCall, AlignContext::Live);

  vixl::MacroAssembler a { cb };

  auto const the_start = cb.frontier();
  meta.smashableLocations.insert(the_start);

  assertx((makeTarget32(target) & 3) == 0);
  addVeneer(meta, the_start, target);
  vixl::Label veneer_addr;
  a.bind(&veneer_addr);
  a.bl(&veneer_addr);

  cb.sync(the_start);
  return the_start;
}

/*
   +----------------------------------------------------------------------+
   | HipHop for PHP                                                       |
   +----------------------------------------------------------------------+
   +----------------------------------------------------------------------+
   +----------------------------------------------------------------------+
*/

#include "hphp/runtime/vm/jit/smashable-instr-arm.h"

#include "hphp/runtime/vm/jit/abi-arm.h"
#include "hphp/runtime/vm/jit/alignment.h"
#include "hphp/runtime/vm/jit/align-arm.h"
#include "hphp/runtime/vm/jit/cg-meta.h"

#include "hphp/util/asm-x64.h"
#include "hphp/util/data-block.h"

#include "hphp/vixl/a64/constants-a64.h"
#include "hphp/vixl/a64/macro-assembler-a64.h"

namespace HPHP { namespace jit { namespace arm {

/*
 * For smashable jmps and calls in ARM, we emit the target address straight
 * into the instruction stream, and then do a pc-relative load to read it.
 *
 * This neatly sidesteps the problem of concurrent modification and execution,
 * as well as the problem of 19- and 26-bit jump offsets (not big enough).  It
 * does, however, entail an indirect jump.
 */

TCA emitSmashableMovq(CodeBlock& cb, CGMeta& meta, uint64_t imm,
                      PhysReg d) {
  align(cb, &meta, Alignment::SmashMovq, AlignContext::Live);

  vixl::MacroAssembler a { cb };
  vixl::Label imm_data;

  auto const the_start = cb.frontier();
  meta.smashableLocations.insert(the_start);

  poolLiteral(cb, meta, (uint64_t)imm, 64, true);
  a.    bind (&imm_data);
  a.    Ldr  (x2a(d), &imm_data);

  cb.sync(the_start);
  return the_start;
}

// SmashableCalls don't embed the target at the end, because the
// BLR must be the last instruction of the sequence.

TCA emitSmashableJmp(CodeBlock& cb, CGMeta& meta, TCA target) {
  align(cb, &meta, Alignment::SmashJmp, AlignContext::Live);

  vixl::MacroAssembler a { cb };

  auto const the_start = cb.frontier();
  meta.smashableLocations.insert(the_start);

  assertx((makeTarget32(target) & 3) == 0);
  addVeneer(meta, the_start, target);
  vixl::Label veneer_addr;
  a.bind(&veneer_addr);
  a.b(&veneer_addr);

  cb.sync(the_start);
  return the_start;
}

TCA emitSmashableJcc(CodeBlock& cb, CGMeta& meta, TCA target,
                     ConditionCode cc) {
  align(cb, &meta, Alignment::SmashJcc, AlignContext::Live);

  vixl::MacroAssembler a { cb };

  auto const the_start = cb.frontier();
  meta.smashableLocations.insert(the_start);

  assertx((makeTarget32(target) & 3) == 0);
  addVeneer(meta, the_start, target);
  vixl::Label veneer_addr;
  a.bind(&veneer_addr);
  a.b(&veneer_addr, arm::convertCC(cc));

  cb.sync(the_start);
  return the_start;
}

namespace {
// The vasm instruction after a smashable may have had nops inserted before it.
// In that case the branch jumping over its immediate will point after the nop
// sequence rather than immediately after the smashable.  This helper is used
// to check the branch is pointing to an appropriate address.
// Returns true if target points to inst or a chain of Nops leading to inst.
// Otherwise it returns false.
bool targetsInst(vixl::Instruction* target, vixl::Instruction* inst) {
  while (target != inst && inst->IsNop()) {
    inst = inst->NextInstruction();
  }
  return target == inst;
}
}

bool possiblySmashableMovq(TCA inst) {
  using namespace vixl;
  Instruction* ldr = Instruction::Cast(inst);
  return (ldr->IsLoadLiteral() &&
          ldr->Mask(LoadLiteralMask) == LDR_x_lit);
}

bool isVeneer(vixl::Instruction* ldr) {
  using namespace vixl;

  auto const br = ldr->NextInstruction();
  auto const rd = ldr->Rd();

  return (ldr->IsLoadLiteral() &&
          ldr->Mask(LoadLiteralMask) == LDR_w_lit &&
          br->Mask(UnconditionalBranchToRegisterMask) == BR &&
          br->Rn() == rd);
}

bool possiblySmashableCall(TCA inst) {
  using namespace vixl;

  auto const bl = Instruction::Cast(inst);

  return (bl->Mask(UnconditionalBranchMask) == BL &&
          isVeneer(bl->ImmPCOffsetTarget()));
}

bool possiblySmashableJmp(TCA inst) {
  using namespace vixl;

  auto const b = Instruction::Cast(inst);

  return (b->Mask(UnconditionalBranchMask) == B &&
          isVeneer(b->ImmPCOffsetTarget()));
}

bool possiblySmashableJcc(TCA inst) {
  using namespace vixl;

  auto const b = Instruction::Cast(inst);

  return b->IsCondBranchImm() && isVeneer(b->ImmPCOffsetTarget());
}

void smashMovq(TCA inst, uint64_t target) {
  using namespace vixl;
  assertx(possiblySmashableMovq(inst));

  Instruction* ldr = Instruction::Cast(inst);
  patchTarget64(ldr->LiteralAddress(), reinterpret_cast<TCA>(target));
}

void smashCmpq(TCA /*inst*/, uint32_t /*target*/) {
  not_implemented();
}

void smashCall(TCA inst, TCA target) {
  using namespace vixl;

  if (!possiblySmashableCall(inst)) {
    // In repo authoritative mode only, the optimization performed at the end of
    // this function may have turned a smashable jmp into a direct one, for
    // which possiblySmashableJmp returns false.
    assertx(RuntimeOption::RepoAuthoritative);
    return;
  }

  auto const bl = Instruction::Cast(inst);
  auto const ldr = bl->ImmPCOffsetTarget();
  patchTarget32(ldr->LiteralAddress(), target);

  // If the target can be reached through a direct call, then patch the original
  // call.  Notice that this optimization prevents a debugger guard from being
  // installed later, so we only perform it in repo authoritative mode.
  int64_t offset = target - inst;
  if (RuntimeOption::RepoAuthoritative && is_int28(offset)) {
    CodeBlock cb;
    uint32_t newInst;
    cb.init((TCA)&newInst, kInstructionSize, "smashCall");
    MacroAssembler a{cb};
    a.bl(offset >> kInstructionSizeLog2);
    smashInst(inst, newInst);
  }
}

void smashJmp(TCA inst, TCA target) {
  using namespace vixl;
  if (!possiblySmashableJmp(inst)) {
    // In repo authoritative mode only, the optimization performed at the end of
    // this function may have turned a smashable jmp into a direct one, for
    // which possiblySmashableJmp returns false.
    assertx(RuntimeOption::RepoAuthoritative);
    return;
  }

  // If the target is within the smashable jmp, then set the target to the
  // end. This mirrors logic in x86_64 with the exception that ARM cannot
  // replace the entire smashable jmp with nops.
  if (target > inst && target - inst <= smashableJmpLen()) {
    target = inst + smashableJmpLen();
  }

  auto const b = Instruction::Cast(inst);
  auto const ldr = b->ImmPCOffsetTarget();
  patchTarget32(ldr->LiteralAddress(), target);

  // If the target can be reached through a direct jump, then patch the original
  // jump.  Notice that this optimization prevents a debugger guard from being
  // installed later, so we only perform it in repo authoritative mode.
  int64_t offset = target - inst;
  if (RuntimeOption::RepoAuthoritative && is_int28(offset)) {
    CodeBlock cb;
    uint32_t newInst;
    cb.init((TCA)&newInst, kInstructionSize, "smashJmp");
    MacroAssembler a{cb};
    if (offset == kInstructionSize) {
      a.nop();
    } else {
      a.b(offset >> kInstructionSizeLog2);
    }
    smashInst(inst, newInst);
  }
}

void smashJcc(TCA inst, TCA target) {
  using namespace vixl;

  if (!possiblySmashableJcc(inst)) {
    // In repo authoritative mode only, the optimization performed at the end of
    // this function may have turned a smashable jcc into a direct one, for
    // which possiblySmashableJcc returns false.
    assertx(RuntimeOption::RepoAuthoritative);
    return;
  }

  auto const b = Instruction::Cast(inst);
  auto const ldr = b->ImmPCOffsetTarget();
  patchTarget32(ldr->LiteralAddress(), target);

  // If the target can be reached through a direct branch, then patch the
  // original branch.  Notice that this optimization prevents a debugger guard
  // from being installed later, so we only perform it in repo authoritative
  int64_t offset = target - inst;
  if (RuntimeOption::RepoAuthoritative && is_int21(offset)) {
    CodeBlock cb;
    uint32_t newInst;
    cb.init((TCA)&newInst, kInstructionSize, "smashJcc");
    MacroAssembler a{cb};
    auto const cond = static_cast<Condition>(b->ConditionBranch());
    a.b(offset >> kInstructionSizeLog2, cond);
    smashInst(inst, newInst);
  }
}

uint64_t smashableMovqImm(TCA inst) {
  using namespace vixl;

  assertx(possiblySmashableMovq(inst));
  Instruction* ldr = Instruction::Cast(inst);
  return *reinterpret_cast<uint64_t*>(ldr->LiteralAddress());
}

uint32_t smashableCmpqImm(TCA /*inst*/) {
  not_implemented();
}

/*
 * Given an instruction `inst' that calls or jumps/branches to a veneer, return
 * the target address that the corresponding veneer jumps to.
 */
static TCA smashableTarget(TCA inst) {
  using namespace vixl;

  auto const b = Instruction::Cast(inst);
  auto const ldr = b->ImmPCOffsetTarget();
  assertx(isVeneer(ldr));
  auto const target32 = *reinterpret_cast<uint32_t*>(ldr->LiteralAddress());
  assertx((target32 & 3) == 0);
  return reinterpret_cast<TCA>(target32);
}

TCA smashableCallTarget(TCA inst) {
  return possiblySmashableCall(inst) ? smashableTarget(inst) : nullptr;
}

TCA smashableJmpTarget(TCA inst) {
  return possiblySmashableJmp(inst) ? smashableTarget(inst) : nullptr;
}

TCA smashableJccTarget(TCA inst) {
  return possiblySmashableJcc(inst) ? smashableTarget(inst) : nullptr;
}

ConditionCode smashableJccCond(TCA inst) {
  using namespace vixl;

  Instruction* b = Instruction::Cast(inst);

  assertx(possiblySmashableJcc(inst));

  return arm::convertCC(static_cast<Condition>(b->Bits(3, 0)));
}

bool optimizeSmashedCall(TCA inst) {
  return false;
}

bool optimizeSmashedJmp(TCA inst) {
  return false;
}

bool optimizeSmashedJcc(TCA inst) {
  using namespace vixl;

  if (!possiblySmashableJcc(inst)) return false;

  // Notice that this optimization prevents a debugger guard from being
  // installed later, so we only perform it in repo authoritative mode.
  if (!RuntimeOption::RepoAuthoritative) return false;

  auto const b = Instruction::Cast(inst);
  auto const target = smashableJccTarget(inst);
  assertx(target);
  auto offset = (intptr_t)target - (intptr_t)b;
  assertx(!is_int21(offset)); // otherwise smashJcc would have optimized it

  auto const ldr = b->ImmPCOffsetTarget();
  assertx(ldr->IsLoadLiteral() && ldr->Mask(LoadLiteralMask) == LDR_w_lit);
  offset = (intptr_t)target - (intptr_t)ldr;

  if (is_int28(offset)) {
    CodeBlock tmpBlock;
    tmpBlock.init((TCA)ldr, 2 * kInstructionSize, "optimizeSmashedJcc");
    MacroAssembler a{tmpBlock};
    a.b(offset >> kInstructionSizeLog2); // replace the ldr
    a.nop(); // replace the br
    return true;
  }

  return false;
}

}}}


void DOMError(const std::string& message, const Token& token)
{
	throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
}

/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------

All rights reserved.

----------------------------------------------------------------------
*/

/** @file  FBXDocumentUtil.cpp
 *  @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
 */
#include "AssimpPCH.h"

#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER

#include "FBXParser.h"
#include "FBXDocument.h"
#include "FBXUtil.h"
#include "FBXDocumentUtil.h"
#include "FBXProperties.h"

namespace Assimp {
namespace FBX {
namespace Util {

// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.

void DOMError(const std::string& message, const Element* element /*= NULL*/)
{
	if(element) {
		DOMError(message,element->KeyToken());
	}
	throw DeadlyImportError("FBX-DOM " + message);
}

void DOMWarning(const std::string& message, const Token& token)
{
	if(DefaultLogger::get()) {
		DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
	}
}

void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
{
	if(element) {
		DOMWarning(message,element->KeyToken());
		return;
	}
	if(DefaultLogger::get()) {
		DefaultLogger::get()->warn("FBX-DOM: " + message);
	}
}

// fetch a property table and the corresponding property template
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
	const std::string& templateName,
	const Element &element,
	const Scope& sc,
	bool no_warn /*= false*/)
{
	const Element* const Properties70 = sc["Properties70"];
	boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
		static_cast<const PropertyTable*>(NULL));

	if(templateName.length()) {
		PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
		if(it != doc.Templates().end()) {
			templateProps = (*it).second;
		}
	}

	if(!Properties70) {
		if(!no_warn) {
			DOMWarning("property table (Properties70) not found",&element);
		}
		if(templateProps) {
			return templateProps;
		}
		else {
			return boost::make_shared<const PropertyTable>();
		}
	}
	return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
}
} // !Util
} // !FBX
} // !Assimp

#endif


cplus/github/sastava007/Tech-Interview-Preparation/Leetcode/Misclenaous/Insert Delete Get Random in O(1).cpp

bool insert(int val)
  {
    v.push_back(val);
    m[val].insert(v.size() - 1);
    return m[val].size() == 1;  //if not already present return true else return false
  }

/* Without duplicates */
class RandomizedSet {
public:
    RandomizedSet()
    {

    }

    bool insert(int val)
    {
        if(m.find(val) != m.end())
            return false;
        v.emplace_back(val);
        m[val]=v.size()-1;

        return true;
    }

    bool remove(int val)
    {
        if(m.find(val) == m.end())
            return false;

        int last = v.back();

        m[last] = m[val];
        v[m[val]] = last;

        v.pop_back();

        m.erase(val);
        return true;

    }

    int getRandom()
    {
        int r = rand() % v.size();
        return v[r];
    }

private:
    unordered_map<int, int> m;
    vector<int> v;
};

/* With duplicates */

  vector<int> v;
  unordered_map<int, unordered_set<int>> m;   // here we map all the indicies on which 'val' is stored

  bool remove(int val)
  {
    auto it = m.find(val);
    if (it != m.end())
    {
      auto free_pos = *it->second.begin();  //delete the first position
      it->second.erase(it->second.begin());
      v[free_pos] = v.back();
      m[v.back()].insert(free_pos);
      m[v.back()].erase(v.size() - 1);
      v.pop_back();
      if (it->second.size() == 0)
        m.erase(it);
      return true;
    }
    return false;
  }

int getRandom()
{
    return v[rand() % v.size()];
}


try {
		conv();
    }

    catch (error &e) {
        std::cerr << "status: " << e.status << std::endl;
        std::cerr << "message: " << e.message << std::endl;
    }

#include <chrono>
#include <iostream>
#include <fstream>
#include <numeric>
#include <math.h>
#include <string>
#include <time.h>
#include "mkldnn.hpp"
#include "configure.h"

using namespace mkldnn;
using namespace std;

void conv()
{
    srand(1);
    std::vector<double> duration_vector;
    double start, end;

    engine cpu_engine(engine::kind::cpu, 0);
    stream cpu_stream(cpu_engine);

    std::vector<primitive> net;
    std::vector<std::unordered_map<int, memory>> net_args;

    // Initialize user buffers
    memory::dims conv_strides = {1, 1};
    memory::dims conv_padding = {0, 0};

    std::vector<float> input_buf(BATCH_SIZE*FIn*(N + 2)*(N + 2));

    std::vector<float> conv_bias_buf(FOut);
    std::vector<float> conv_weights_buf(FOut*FIn*K*K);

    for (int i = 0; i < BATCH_SIZE*FIn*(N + 2)*(N + 2); i++)
        input_buf[i] = ((float)(rand()%256 - 128)) / 127.f;

    for (int fout = 0; fout < FOut; ++fout)
    {
		int zero_weights = 0;
		for (int fin = 0; fin < FIn; ++fin)
		{
			for (int k_y = 0; k_y < K; ++k_y)
				for (int k_x = 0; k_x < K; ++k_x)
				{
					int i = k_x + k_y*(K) + fin*(K*K) + fout*(FIn*K*K);

					if (zero_weights < zero_weight_filters_per_output_channel[fout])
						conv_weights_buf[i] = 0;
					else
						conv_weights_buf[i] = ((float)(rand()%256 - 128)) / 127.f;
				}

			zero_weights++;
		}
    }

    for (int i = 0; i < FOut; i++)
        conv_bias_buf[i] = ((float)(rand()%256 - 128)) / 127.f;

    // Create memory objects with user data format
    auto input_usr_md = memory::desc(
        {BATCH_SIZE, FIn, N + 2, N + 2},
        memory::data_type::f32,
        memory::format_tag::nchw
    );

    auto conv_weights_usr_md = memory::desc(
        {FOut, FIn, K, K},
        memory::data_type::f32,
        memory::format_tag::oihw
    );

    auto conv_bias_usr_md = memory::desc(
        {FOut},
        memory::data_type::f32,
        memory::format_tag::x
    );

    auto conv_weights_usr_mem = memory(conv_weights_usr_md, cpu_engine, conv_weights_buf.data());
    auto conv_bias_usr_mem = memory(conv_bias_usr_md, cpu_engine, conv_bias_buf.data());

    // Create memory objects with a data format selected by the convolution primitive
    auto conv_src_md = memory::desc(
        {BATCH_SIZE, FIn, N + 2, N + 2},
        memory::data_type::f32,
        memory::format_tag::any
    );

    auto conv_weights_md = memory::desc(
        {FOut, FIn, K, K},
        memory::data_type::f32,
        memory::format_tag::any
    );

    auto conv_bias_md = memory::desc(
        {FOut},
        memory::data_type::f32,
        memory::format_tag::any
    );

    auto output_md = memory::desc(
        {BATCH_SIZE, FOut, N, N},
        memory::data_type::f32,
        memory::format_tag::any
    );

    // Create the convolution primitive descriptor, so as to get
    // the data format selected by the primitive.
    auto conv_d = convolution_forward::desc(
        prop_kind::forward_inference,
        algorithm::convolution_direct,
        conv_src_md,
        conv_weights_md,
        conv_bias_md,
        output_md,
        conv_strides,
        conv_padding,
        conv_padding
    );

    auto conv_pd = convolution_forward::primitive_desc(
        conv_d,
        cpu_engine
    );

    auto conv_dst_mem = memory(conv_pd.dst_desc(), cpu_engine);

    // Edit user data format
    auto input_usr_mem = memory(input_usr_md, cpu_engine, input_buf.data());
    auto input_mem = memory(conv_pd.src_desc(), cpu_engine);

    reorder(input_usr_mem, input_mem)
        .execute(cpu_stream, input_usr_mem, input_mem);

    auto conv_weights_mem = conv_weights_usr_mem;
    if (conv_pd.weights_desc() != conv_weights_usr_mem.get_desc()) {
        conv_weights_mem = memory(conv_pd.weights_desc(), cpu_engine);
        reorder(conv_weights_usr_mem, conv_weights_mem)
            .execute(cpu_stream, conv_weights_usr_mem, conv_weights_mem);
    }

    // Add convolution to the network
    net.push_back(convolution_forward(conv_pd));
    net_args.push_back({
        {MKLDNN_ARG_SRC, input_mem},
        {MKLDNN_ARG_WEIGHTS, conv_weights_mem},
        {MKLDNN_ARG_BIAS, conv_bias_usr_mem},
        {MKLDNN_ARG_DST, conv_dst_mem}
    });

    // Execute the network
    for (int i = 0; i < NB_TESTS; ++i) {
        start = rtclock();

        for (size_t j = 0; j < net.size(); ++j)
            net[j].execute(cpu_stream, net_args[j]);

        cpu_stream.wait();

        end = rtclock();
        duration_vector.push_back((end - start) * 1000);
    }

    std::cout << "\n\n\tConv time : " << median(duration_vector) << " ms." << std::endl;

    // Convert convolution output to user data format
    auto output_usr_md = memory::desc(
        {BATCH_SIZE, FOut, N, N},
        memory::data_type::f32,
        memory::format_tag::nchw
    );

    auto output_mem = memory(output_usr_md, cpu_engine);
    reorder(conv_dst_mem, output_mem)
        .execute(cpu_stream, conv_dst_mem, output_mem);

    /* Write results to file */
    float* output = (float*)output_mem.get_data_handle();
    FILE* f = fopen("mkl_result.txt", "w");
    if (f == NULL) {
        std::cout << "Error creating mkl_result.txt" << std::endl;;
        return ;
    }

    for (int n = 0; n < BATCH_SIZE; ++n)
        for (int fout = 0; fout < FOut; ++fout)
            for (int y = 0; y < N; ++y)
                for (int x = 0; x < N; ++x)
                    fprintf(f, "%.10g\n", output[x + y*N + fout*N*N + n*N*N*FOut]);

    fclose(f);
}

int main(int argc, char **argv)
{


int DDFScanVariable( const char *pszRecord, int nMaxChars, int nDelimChar )

{
    int i = 0;  // Used after for.

    for( ; i < nMaxChars - 1 && pszRecord[i] != nDelimChar; i++ ) {}

    return i;
}

/************************************************************************/
/*                          DDFFetchVariable()                          */
/*                                                                      */
/*      Fetch a variable length string from a record, and allocate      */
/*      it as a new string (with CPLStrdup()).                          */
/************************************************************************/

char * DDFFetchVariable( const char *pszRecord, int nMaxChars,
                         int nDelimChar1, int nDelimChar2,
                         int *pnConsumedChars )

{
    int i = 0;  // Used after for.
    for( ;
         i < nMaxChars-1 && pszRecord[i] != nDelimChar1
         && pszRecord[i] != nDelimChar2;
         i++ )
    {}

    *pnConsumedChars = i;
    if( i < nMaxChars
        && (pszRecord[i] == nDelimChar1 || pszRecord[i] == nDelimChar2) )
        (*pnConsumedChars)++;

    char *pszReturn = static_cast<char *>(CPLMalloc(i + 1));
    pszReturn[i] = '\0';
    strncpy( pszReturn, pszRecord, i );

    return pszReturn;
}


inline PPERF_OBJECT_TYPE FirstObject( PPERF_DATA_BLOCK PerfData )
{
	return( (PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength) );
}

#include "stdafx.h"
#include "tier1/utldict.h"
#include <pdh.h>
#include <pdhmsg.h>
#include "perf_counters.h"

#if 1

class CPerfTracker : public IPerfTracker
{
public:

	CPerfTracker()
	{
		m_hProcessorTimeCounter = NULL;
		m_dwProcessID = 0;
		if ( PdhOpenQuery( NULL, 0, &m_hQuery ) != ERROR_SUCCESS )
			m_hQuery = NULL;

		SYSTEM_INFO info;
		GetSystemInfo( &info );
		m_nProcessors = (int)info.dwNumberOfProcessors;
	}

	~CPerfTracker()
	{
		if ( m_hQuery )
			PdhCloseQuery( m_hQuery );
	}

	virtual void Init( unsigned long dwProcessID )
	{
		Term();

		m_dwProcessID = dwProcessID;

		char instanceName[512];
		if ( GetInstanceNameFromProcessID( m_dwProcessID, instanceName, sizeof( instanceName ) ) )
		{
			// Create a counter to watch this process' time.
			char str[512];
			V_snprintf( str, sizeof( str ), "\\Process(%s)\\%% Processor Time", instanceName );
			if ( PdhAddCounter( m_hQuery, str, 0, &m_hProcessorTimeCounter ) != ERROR_SUCCESS )
			{
				m_hProcessorTimeCounter = NULL;
			}

			V_snprintf( str, sizeof( str ), "\\Process(%s)\\Private Bytes", instanceName );
			if ( PdhAddCounter( m_hQuery, str, 0, &m_hPrivateBytesCounter ) != ERROR_SUCCESS )
			{
				m_hPrivateBytesCounter = NULL;
			}
		}
	}

	void Term()
	{
		if ( m_hProcessorTimeCounter )
			PdhRemoveCounter( m_hProcessorTimeCounter );

		if ( m_hPrivateBytesCounter )
			PdhRemoveCounter( m_hPrivateBytesCounter );

		m_hProcessorTimeCounter = NULL;
		m_hPrivateBytesCounter = NULL;
	}

	virtual void Release()
	{
		delete this;
	}

	virtual unsigned long GetProcessID()
	{
		return m_dwProcessID;
	}

	virtual void GetPerfData( int &processorPercentage, int &memoryUsageMegabytes )
	{
		processorPercentage = 101;
		memoryUsageMegabytes = 0;

		// Collect query data..
		PDH_STATUS ret = PdhCollectQueryData( m_hQuery );
		if ( ret != ERROR_SUCCESS )
			return;

		// Check processor usage.
		DWORD dwType;
		PDH_FMT_COUNTERVALUE counterValue;
		if ( PdhGetFormattedCounterValue( m_hProcessorTimeCounter, PDH_FMT_LONG | PDH_FMT_NOCAP100, &dwType, &counterValue ) == ERROR_SUCCESS )
			processorPercentage = counterValue.longValue / m_nProcessors;
		else
			processorPercentage = 101;

		// Check memory usage.
		if ( PdhGetFormattedCounterValue( m_hPrivateBytesCounter, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &dwType, &counterValue ) == ERROR_SUCCESS )
			memoryUsageMegabytes = (int)(counterValue.doubleValue / (1024.0 * 1024.0));
		else
			memoryUsageMegabytes = 0;
	}

private:

	bool GetInstanceNameFromProcessID( DWORD processID, char *instanceName, int instanceNameLen )
	{
		instanceName[0] = 0;

		bool bRet = false;

		// This refreshes the object list. If we don't do this, it won't get new process IDs correctly.
		DWORD dummy = 0;
		PdhEnumObjects( NULL, NULL, NULL, &dummy, PERF_DETAIL_NOVICE, true );

		// Find out how much data we need.
		DWORD counterListLen=2, instanceListLen=2;
		char *counterList = new char[counterListLen];
		char *instanceList = new char[instanceListLen];
		PDH_STATUS stat = PdhEnumObjectItems( NULL, NULL, "Process", counterList, &counterListLen, instanceList, &instanceListLen, PERF_DETAIL_NOVICE, 0 );
		if ( stat == PDH_MORE_DATA )
		{
			delete [] counterList;
			delete [] instanceList;
			char *counterList = new char[counterListLen];
			char *instanceList = new char[instanceListLen];

			stat = PdhEnumObjectItems( NULL, NULL, "Process", counterList, &counterListLen, instanceList, &instanceListLen, PERF_DETAIL_NOVICE, 0 );
			if ( stat == ERROR_SUCCESS )
			{
				// We need the # of each one..
				CUtlDict<int,int> counts;

				// The instance name list is a bunch of strings terminated with nulls. The final one has two nulls after it.
				// Walk through the list and get the process ID associated with each instance name.
				const char *pCur = instanceList;
				while ( *pCur )
				{
					int index = counts.Find( pCur );
					if ( index == counts.InvalidIndex() )
						counts.Insert( pCur, 1 );
					else
						counts[index]++;

					pCur += strlen( pCur ) + 1;
				}

				// Each instance (like "vrad") might have multiple versions, like if you're running multiple vrad processes at the same time.
				for ( int i=counts.First(); i != counts.InvalidIndex(); i=counts.Next( i ) )
				{
					const char *pInstanceName = counts.GetElementName( i );
					int nInstances = counts[i];
					for ( int iInstance=0; iInstance < nInstances; iInstance++ )
					{
						char testInstanceName[256], fullObjectName[256];
						V_snprintf( testInstanceName, sizeof( testInstanceName ), "%s#%d", pInstanceName, iInstance );
						V_snprintf( fullObjectName, sizeof( fullObjectName ), "\\Process(%s)\\ID Process", testInstanceName );

						HCOUNTER hCounter = NULL;
						stat = PdhAddCounter( m_hQuery, fullObjectName, 0, &hCounter );
						if ( stat == ERROR_SUCCESS )
						{
							stat = PdhCollectQueryData( m_hQuery );
							if ( stat == ERROR_SUCCESS )
							{
								DWORD dwType;
								PDH_FMT_COUNTERVALUE counterValue;
								stat = PdhGetFormattedCounterValue( hCounter, PDH_FMT_LONG, &dwType, &counterValue );
								if ( stat == 0 && counterValue.longValue == (long)processID )
								{
									// Finall! We found it.
									V_strncpy( instanceName, testInstanceName, instanceNameLen );
									bRet = true;
									PdhRemoveCounter( hCounter );
									break;
								}
							}

							PdhRemoveCounter( hCounter );
						}
					}

					if ( bRet )
						break;
				}
			}

			delete [] counterList;
			delete [] instanceList;
		}

		return bRet;
	}

private:
	DWORD m_dwProcessID;
	PDH_HQUERY m_hQuery;
	HCOUNTER m_hProcessorTimeCounter;
	HCOUNTER m_hPrivateBytesCounter;
	int m_nProcessors;
};

IPerfTracker* CreatePerfTracker()
{
	return new CPerfTracker;
}

#else

#include <winperf.h>

// NOTE: THIS IS THE OLD, UGLY WAY TO DO IT.

class CPerfTracker
{
public:
	CPerfTracker();
	void Init( unsigned long dwProcessID );

	unsigned long GetProcessID();

	// Get the percentage of CPU time that the process is using.
	int GetCPUPercentage();

private:
	DWORD m_dwProcessID;
	LONGLONG m_lnOldValue;
	LARGE_INTEGER m_OldPerfTime100nSec;
	int m_nProcessors;
};

#define TOTALBYTES    100*1024
#define BYTEINCREMENT 10*1024

#define SYSTEM_OBJECT_INDEX					2		// 'System' object
#define PROCESS_OBJECT_INDEX				230		// 'Process' object
#define PROCESSOR_OBJECT_INDEX				238		// 'Processor' object
#define TOTAL_PROCESSOR_TIME_COUNTER_INDEX	240		// '% Total processor time' counter (valid in WinNT under 'System' object)
#define PROCESSOR_TIME_COUNTER_INDEX		6		// '% processor time' counter (for Win2K/XP)

//	The performance data is accessed through the registry key
//	However, although we use the registry to collect performance data,
//	the data is not stored in the registry database.
//	Instead, calling the registry functions with the HKEY_PEFORMANCE_DATA key
//	causes the system to collect the data from the appropriate system
//	object managers.
//	QueryPerformanceData allocates memory block for getting the
//	performance data.
void QueryPerformanceData(PERF_DATA_BLOCK **pPerfData, DWORD dwObjectIndex, DWORD dwCounterIndex)
{
	// Since i want to use the same allocated area for each query,
	// i declare CBuffer as static.
	// The allocated is changed only when RegQueryValueEx return ERROR_MORE_DATA
	static CUtlVector<char> Buffer;
	if ( Buffer.Count() == 0 )
		Buffer.SetSize( TOTALBYTES );

	DWORD BufferSize = Buffer.Count();
	LONG lRes;

	char keyName[32];
	V_snprintf(keyName, sizeof(keyName), "%d",dwObjectIndex);

	memset( Buffer.Base(), 0, Buffer.Count() );
	while( (lRes = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
							   keyName,
							   NULL,
							   NULL,
							   (LPBYTE)Buffer.Base(),
							   &BufferSize )) == ERROR_MORE_DATA )
	{
		// Get a buffer that is big enough.
		BufferSize += BYTEINCREMENT;
		Buffer.SetSize( BufferSize );
	}

	*pPerfData = (PPERF_DATA_BLOCK)Buffer.Base();
}

/*****************************************************************
 *                                                               *
 * Functions used to navigate through the performance data.      *
 *                                                               *
 *****************************************************************/

inline PPERF_OBJECT_TYPE NextObject( PPERF_OBJECT_TYPE PerfObj )
{
	return( (PPERF_OBJECT_TYPE)((PBYTE)PerfObj + PerfObj->TotalByteLength) );
}

inline PPERF_COUNTER_DEFINITION FirstCounter( PPERF_OBJECT_TYPE PerfObj )
{
	return( (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj + PerfObj->HeaderLength) );
}

inline PPERF_COUNTER_DEFINITION NextCounter( PPERF_COUNTER_DEFINITION PerfCntr )
{
	return( (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr + PerfCntr->ByteLength) );
}

inline PPERF_INSTANCE_DEFINITION FirstInstance( PPERF_OBJECT_TYPE PerfObj )
{
	return( (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj + PerfObj->DefinitionLength) );
}

inline PPERF_INSTANCE_DEFINITION NextInstance( PPERF_INSTANCE_DEFINITION PerfInst )
{
	PPERF_COUNTER_BLOCK PerfCntrBlk;

	PerfCntrBlk = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst + PerfInst->ByteLength);

	return( (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfCntrBlk + PerfCntrBlk->ByteLength) );
}

template<class T>
T GetCounterValueForProcessID(PPERF_OBJECT_TYPE pPerfObj, DWORD dwCounterIndex, DWORD dwProcessID)
{
	unsigned long PROC_ID_COUNTER = 784;

	BOOL	bProcessIDExist = FALSE;
	PPERF_COUNTER_DEFINITION pPerfCntr = NULL;
	PPERF_COUNTER_DEFINITION pTheRequestedPerfCntr = NULL;
	PPERF_COUNTER_DEFINITION pProcIDPerfCntr = NULL;
	PPERF_INSTANCE_DEFINITION pPerfInst = NULL;
	PPERF_COUNTER_BLOCK pCounterBlock = NULL;

	// Get the first counter.

	pPerfCntr = FirstCounter( pPerfObj );

	for( DWORD j=0; j < pPerfObj->NumCounters; j++ )
	{
		if (pPerfCntr->CounterNameTitleIndex == PROC_ID_COUNTER)
		{
			pProcIDPerfCntr = pPerfCntr;
			if (pTheRequestedPerfCntr)
				break;
		}

		if (pPerfCntr->CounterNameTitleIndex == dwCounterIndex)
		{
			pTheRequestedPerfCntr = pPerfCntr;
			if (pProcIDPerfCntr)
				break;
		}

		// Get the next counter.

		pPerfCntr = NextCounter( pPerfCntr );
	}

	if( pPerfObj->NumInstances == PERF_NO_INSTANCES )
	{
		pCounterBlock = (PPERF_COUNTER_BLOCK) ((LPBYTE) pPerfObj + pPerfObj->DefinitionLength);
	}
	else
	{
		pPerfInst = FirstInstance( pPerfObj );

		for( int k=0; k < pPerfObj->NumInstances; k++ )
		{
			pCounterBlock = (PPERF_COUNTER_BLOCK) ((LPBYTE) pPerfInst + pPerfInst->ByteLength);
			if (pCounterBlock)
			{
				DWORD processID = *(DWORD*)((LPBYTE) pCounterBlock + pProcIDPerfCntr->CounterOffset);
				if (processID == dwProcessID)
				{
					bProcessIDExist = TRUE;
					break;
				}
			}

			// Get the next instance.
			pPerfInst = NextInstance( pPerfInst );
		}
	}

	if (bProcessIDExist && pCounterBlock)
	{
		T *lnValue = NULL;
		lnValue = (T*)((LPBYTE) pCounterBlock + pTheRequestedPerfCntr->CounterOffset);
		return *lnValue;
	}
	return -1;
}

template<class T>
T GetCounterValueForProcessID(PERF_DATA_BLOCK **pPerfData, DWORD dwObjectIndex, DWORD dwCounterIndex, DWORD dwProcessID)
{
	QueryPerformanceData(pPerfData, dwObjectIndex, dwCounterIndex);

    PPERF_OBJECT_TYPE pPerfObj = NULL;
	T lnValue = {0};

	// Get the first object type.
	pPerfObj = FirstObject( *pPerfData );

	// Look for the given object index

	for( DWORD i=0; i < (*pPerfData)->NumObjectTypes; i++ )
	{

		if (pPerfObj->ObjectNameTitleIndex == dwObjectIndex)
		{
			lnValue = GetCounterValueForProcessID<T>(pPerfObj, dwCounterIndex, dwProcessID);
			break;
		}

		pPerfObj = NextObject( pPerfObj );
	}
	return lnValue;
}

// CPerfTracker implementation.

CPerfTracker::CPerfTracker()
{
	Init( 0 );

	SYSTEM_INFO info;
	GetSystemInfo( &info );
	m_nProcessors = (int)info.dwNumberOfProcessors;
}

void CPerfTracker::Init( unsigned long dwProcessID )
{
	m_dwProcessID = dwProcessID;
	m_lnOldValue = 0;
}

unsigned long CPerfTracker::GetProcessID()
{
	return m_dwProcessID;
}

int CPerfTracker::GetCPUPercentage()
{
	DWORD dwObjectIndex = PROCESS_OBJECT_INDEX;
	DWORD dwCpuUsageIndex = PROCESSOR_TIME_COUNTER_INDEX;

	PPERF_DATA_BLOCK pPerfData = NULL;
	LONGLONG lnNewValue = GetCounterValueForProcessID<LONGLONG>( &pPerfData, dwObjectIndex, dwCpuUsageIndex, m_dwProcessID );
	LARGE_INTEGER NewPerfTime100nSec = pPerfData->PerfTime100nSec;

	if ( m_lnOldValue == 0 )
	{
		m_lnOldValue = lnNewValue;
		m_OldPerfTime100nSec = NewPerfTime100nSec;
		return 0;
	}

	LONGLONG lnValueDelta = lnNewValue - m_lnOldValue;
	double DeltaPerfTime100nSec = (double)NewPerfTime100nSec.QuadPart - (double)m_OldPerfTime100nSec.QuadPart;

	m_lnOldValue = lnNewValue;
	m_OldPerfTime100nSec = NewPerfTime100nSec;

	double a = (double)lnValueDelta / DeltaPerfTime100nSec;

	int CpuUsage = (int) (a*100);
	if (CpuUsage < 0)
		return 0;

	return CpuUsage / m_nProcessors;
}

#endif


/* This source file must have a .cpp extension so that all C++ compilers
   recognize the extension without flags.  Borland does not know .cxx for
   example.  */
#ifndef __cplusplus
# error "A C compiler has been selected for C++."
#endif

/* Provide main() so the program can link.  */

#if defined(__COMO__)
# define COMPILER_ID "Comeau"

#elif defined(__INTEL_COMPILER) || defined(__ICC)
# define COMPILER_ID "Intel"

#elif defined(__BORLANDC__)
# define COMPILER_ID "Borland"

#elif defined(__WATCOMC__)
# define COMPILER_ID "Watcom"

#elif defined(__SUNPRO_CC)
# define COMPILER_ID "SunPro"

#elif defined(__HP_aCC)
# define COMPILER_ID "HP"

#elif defined(__DECCXX)
# define COMPILER_ID "Compaq"

#elif defined(__IBMCPP__)
# define COMPILER_ID "VisualAge"

#elif defined(__PGI)
# define COMPILER_ID "PGI"

#elif defined(__GNUC__)
# define COMPILER_ID "GNU"

#elif defined(_MSC_VER)
# define COMPILER_ID "MSVC"

#elif defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)
/* Analog Devices C++ compiler for Blackfin, TigerSHARC and
   SHARC (21000) DSPs */
# define COMPILER_ID "ADSP"

#elif defined(_COMPILER_VERSION)
# define COMPILER_ID "MIPSpro"

/* This compiler is either not known or is too old to define an
   identification macro.  Try to identify the platform and guess that
   it is the native compiler.  */
#elif defined(__sgi)
# define COMPILER_ID "MIPSpro"

#elif defined(__hpux) || defined(__hpua)
# define COMPILER_ID "HP"

#else /* unknown compiler */
# define COMPILER_ID ""

#endif

/* Construct the string literal in pieces to prevent the source from
   getting matched.  Store it in a pointer rather than an array
   because some compilers will just produce instructions to fill the
   array rather than assigning a pointer to a static array.  */
char* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";

/* Identify known platforms by name.  */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define PLATFORM_ID "Linux"

#elif defined(__CYGWIN__)
# define PLATFORM_ID "Cygwin"

#elif defined(__MINGW32__)
# define PLATFORM_ID "MinGW"

#elif defined(__APPLE__)
# define PLATFORM_ID "Darwin"

#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define PLATFORM_ID "Windows"

#elif defined(__FreeBSD__) || defined(__FreeBSD)
# define PLATFORM_ID "FreeBSD"

#elif defined(__NetBSD__) || defined(__NetBSD)
# define PLATFORM_ID "NetBSD"

#elif defined(__OpenBSD__) || defined(__OPENBSD)
# define PLATFORM_ID "OpenBSD"

#elif defined(__sun) || defined(sun)
# define PLATFORM_ID "SunOS"

#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
# define PLATFORM_ID "AIX"

#elif defined(__sgi) || defined(__sgi__) || defined(_SGI)
# define PLATFORM_ID "IRIX"

#elif defined(__hpux) || defined(__hpux__)
# define PLATFORM_ID "HP-UX"

#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
# define PLATFORM_ID "BeOS"

#elif defined(__QNX__) || defined(__QNXNTO__)
# define PLATFORM_ID "QNX"

#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
# define PLATFORM_ID "Tru64"

#elif defined(__riscos) || defined(__riscos__)
# define PLATFORM_ID "RISCos"

#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
# define PLATFORM_ID "SINIX"

#elif defined(__UNIX_SV__)
# define PLATFORM_ID "UNIX_SV"

#elif defined(__bsdos__)
# define PLATFORM_ID "BSDOS"

#elif defined(_MPRAS) || defined(MPRAS)
# define PLATFORM_ID "MP-RAS"

#elif defined(__osf) || defined(__osf__)
# define PLATFORM_ID "OSF1"

#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
# define PLATFORM_ID "SCO_SV"

#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
# define PLATFORM_ID "ULTRIX"

#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
# define PLATFORM_ID "Xenix"

#else /* unknown platform */
# define PLATFORM_ID ""

#endif

/* Construct the string literal in pieces to prevent the source from
   getting matched.  Store it in a pointer rather than an array
   because some compilers will just produce instructions to fill the
   array rather than assigning a pointer to a static array.  */
char* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";


Greater::Greater()
  : ComputeOperator("Greater", ID) {
}

//                             The ONNC Project
#include <onnc/IR/Compute/Greater.h>

using namespace onnc;

char Greater::ID = 0;

// Greater

Greater::Greater(const Greater& pCopy)
  : ComputeOperator(pCopy) /* shallow copy */ {
}

void Greater::printAttributes(std::ostream& pOS) const
{
  ;
}

bool Greater::classof(const ComputeOperator* pOp)
{
  if (nullptr == pOp)
    return false;
  return (pOp->getID() == &ID);
}


void CCrashHandler::SigillHandler(int)
{
	// Illegal instruction (SIGILL)

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

}

#include "stdafx.h"
#include "CrashHandler.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <new.h>
#include <signal.h>
#include <exception>
#include <sys/stat.h>
#include <psapi.h>
#include <rtcapi.h>
#include <Shellapi.h>
#include <dbghelp.h>

#pragma warning (disable : 4100)

#ifndef _AddressOfReturnAddress

#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif

// _ReturnAddress and _AddressOfReturnAddress should be prototyped before use
EXTERNC void * _AddressOfReturnAddress(void);
EXTERNC void * _ReturnAddress(void);

#endif

CCrashHandler::CCrashHandler()
{
}

CCrashHandler::~CCrashHandler()
{
}

void CCrashHandler::SetProcessExceptionHandlers()
{
	// Install top-level SEH handler
	SetUnhandledExceptionFilter(SehHandler);

	// Catch pure virtual function calls.
	// Because there is one _purecall_handler for the whole process,
	// calling this function immediately impacts all threads. The last
	// caller on any thread sets the handler.
	_set_purecall_handler(PureCallHandler);

	// Catch new operator memory allocation exceptions
	_set_new_handler(NewHandler);

	// Catch invalid parameter exceptions.
	_set_invalid_parameter_handler(InvalidParameterHandler);

	// Set up C++ signal handlers

	_set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT);

	// Catch an abnormal program termination
	signal(SIGABRT, SigabrtHandler);

	// Catch illegal instruction handler
	signal(SIGINT, SigintHandler);

	// Catch a termination request
	signal(SIGTERM, SigtermHandler);

}

void CCrashHandler::SetThreadExceptionHandlers()
{

	// In a multithreaded environment, terminate functions are maintained
	// separately for each thread. Each new thread needs to install its own
	// terminate function. Thus, each thread is in charge of its own termination handling.
	set_terminate(TerminateHandler);

	// In a multithreaded environment, unexpected functions are maintained
	// separately for each thread. Each new thread needs to install its own
	// unexpected function. Thus, each thread is in charge of its own unexpected handling.
	set_unexpected(UnexpectedHandler);

	// Catch a floating point error
	typedef void (*sigh)(int);
	signal(SIGFPE, (sigh)SigfpeHandler);

	// Catch an illegal instruction
	signal(SIGILL, SigillHandler);

	// Catch illegal storage access errors
	signal(SIGSEGV, SigsegvHandler);

}

// The following code gets exception pointers using a workaround found in CRT code.
void CCrashHandler::GetExceptionPointers(DWORD dwExceptionCode,
										 EXCEPTION_POINTERS** ppExceptionPointers)
{
	// The following code was taken from VC++ 8.0 CRT (invarg.c: line 104)

	EXCEPTION_RECORD ExceptionRecord;
	CONTEXT ContextRecord;
	memset(&ContextRecord, 0, sizeof(CONTEXT));

#ifdef _X86_

	__asm {
		mov dword ptr [ContextRecord.Eax], eax
			mov dword ptr [ContextRecord.Ecx], ecx
			mov dword ptr [ContextRecord.Edx], edx
			mov dword ptr [ContextRecord.Ebx], ebx
			mov dword ptr [ContextRecord.Esi], esi
			mov dword ptr [ContextRecord.Edi], edi
			mov word ptr [ContextRecord.SegSs], ss
			mov word ptr [ContextRecord.SegCs], cs
			mov word ptr [ContextRecord.SegDs], ds
			mov word ptr [ContextRecord.SegEs], es
			mov word ptr [ContextRecord.SegFs], fs
			mov word ptr [ContextRecord.SegGs], gs
			pushfd
			pop [ContextRecord.EFlags]
	}

	ContextRecord.ContextFlags = CONTEXT_CONTROL;
#pragma warning(push)
#pragma warning(disable:4311)
	ContextRecord.Eip = (ULONG)_ReturnAddress();
	ContextRecord.Esp = (ULONG)_AddressOfReturnAddress();
#pragma warning(pop)
	ContextRecord.Ebp = *((ULONG *)_AddressOfReturnAddress()-1);

#elif defined (_IA64_) || defined (_AMD64_)

	/* Need to fill up the Context in IA64 and AMD64. */
	RtlCaptureContext(&ContextRecord);

#else  /* defined (_IA64_) || defined (_AMD64_) */

	ZeroMemory(&ContextRecord, sizeof(ContextRecord));

#endif  /* defined (_IA64_) || defined (_AMD64_) */

	ZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD));

	ExceptionRecord.ExceptionCode = dwExceptionCode;
	ExceptionRecord.ExceptionAddress = _ReturnAddress();

	EXCEPTION_RECORD* pExceptionRecord = new EXCEPTION_RECORD;
	memcpy(pExceptionRecord, &ExceptionRecord, sizeof(EXCEPTION_RECORD));
	CONTEXT* pContextRecord = new CONTEXT;
	memcpy(pContextRecord, &ContextRecord, sizeof(CONTEXT));

	*ppExceptionPointers = new EXCEPTION_POINTERS;
	(*ppExceptionPointers)->ExceptionRecord = pExceptionRecord;
	(*ppExceptionPointers)->ContextRecord = pContextRecord;
}

// This method creates minidump of the process
void CCrashHandler::CreateMiniDump(EXCEPTION_POINTERS* pExcPtrs)
{
    HMODULE hDbgHelp = NULL;
    HANDLE hFile = NULL;
    MINIDUMP_EXCEPTION_INFORMATION mei;
    MINIDUMP_CALLBACK_INFORMATION mci;

    // Load dbghelp.dll
    hDbgHelp = LoadLibrary(_T("dbghelp.dll"));
    if(hDbgHelp==NULL)
    {
        // Error - couldn't load dbghelp.dll
		return;
    }

    // Create the minidump file
    hFile = CreateFile(
        _T("crashdump.dmp"),
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    if(hFile==INVALID_HANDLE_VALUE)
    {
        // Couldn't create file
		return;
    }

    // Write minidump to the file
    mei.ThreadId = GetCurrentThreadId();
    mei.ExceptionPointers = pExcPtrs;
    mei.ClientPointers = FALSE;
    mci.CallbackRoutine = NULL;
    mci.CallbackParam = NULL;

    typedef BOOL (WINAPI *LPMINIDUMPWRITEDUMP)(
        HANDLE hProcess,
        DWORD ProcessId,
        HANDLE hFile,
        MINIDUMP_TYPE DumpType,
        CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
        CONST PMINIDUMP_USER_STREAM_INFORMATION UserEncoderParam,
        CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);

    LPMINIDUMPWRITEDUMP pfnMiniDumpWriteDump =
        (LPMINIDUMPWRITEDUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
    if(!pfnMiniDumpWriteDump)
    {
        // Bad MiniDumpWriteDump function
        return;
    }

    HANDLE hProcess = GetCurrentProcess();
	DWORD dwProcessId = GetCurrentProcessId();

    BOOL bWriteDump = pfnMiniDumpWriteDump(
        hProcess,
        dwProcessId,
        hFile,
        MiniDumpNormal,
        &mei,
        NULL,
        &mci);

    if(!bWriteDump)
    {
        // Error writing dump.
        return;
    }

    // Close file
    CloseHandle(hFile);

    // Unload dbghelp.dll
    FreeLibrary(hDbgHelp);
}

// Structured exception handler
LONG WINAPI CCrashHandler::SehHandler(PEXCEPTION_POINTERS pExceptionPtrs)
{
	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

	// Unreacheable code
	return EXCEPTION_EXECUTE_HANDLER;
}

// CRT terminate() call handler
void __cdecl CCrashHandler::TerminateHandler()
{
	// Abnormal program termination (terminate() function was called)

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);
}

// CRT unexpected() call handler
void __cdecl CCrashHandler::UnexpectedHandler()
{
	// Unexpected error (unexpected() function was called)

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);
}

// CRT Pure virtual method call handler
void __cdecl CCrashHandler::PureCallHandler()
{
	// Pure virtual function call

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

}

// CRT invalid parameter handler
void __cdecl CCrashHandler::InvalidParameterHandler(
	const wchar_t* expression,
	const wchar_t* function,
	const wchar_t* file,
	unsigned int line,
	uintptr_t pReserved)
{
	pReserved;

	// Invalid parameter exception

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

}

// CRT new operator fault handler
int __cdecl CCrashHandler::NewHandler(size_t)
{
	// 'new' operator memory allocation exception

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

	// Unreacheable code
	return 0;
}

// CRT SIGABRT signal handler
void CCrashHandler::SigabrtHandler(int)
{
	// Caught SIGABRT C++ signal

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

}

// CRT SIGFPE signal handler
void CCrashHandler::SigfpeHandler(int /*code*/, int subcode)
{
	// Floating point exception (SIGFPE)

	EXCEPTION_POINTERS* pExceptionPtrs = (PEXCEPTION_POINTERS)_pxcptinfoptrs;

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

}

// CRT sigill signal handler

// CRT sigint signal handler
void CCrashHandler::SigintHandler(int)
{

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

}

// CRT SIGSEGV signal handler
void CCrashHandler::SigsegvHandler(int)
{
	// Invalid storage access (SIGSEGV)

	PEXCEPTION_POINTERS pExceptionPtrs = (PEXCEPTION_POINTERS)_pxcptinfoptrs;

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

}

// CRT SIGTERM signal handler
void CCrashHandler::SigtermHandler(int)
{
	// Termination request (SIGTERM)

	// Retrieve exception information
	EXCEPTION_POINTERS* pExceptionPtrs = NULL;
	GetExceptionPointers(0, &pExceptionPtrs);

	// Write minidump file
	CreateMiniDump(pExceptionPtrs);

	// Terminate process
	TerminateProcess(GetCurrentProcess(), 1);

}

BOOL CCrashHandler::Install()
{
	CCrashHandler ch;
	ch.SetProcessExceptionHandlers();
	ch.SetThreadExceptionHandlers();

	return TRUE;
}