#include "main.h"
#include <d3dx9tex.h>
#include "proxyIDirect3D9.h"
#include "proxyIDirect3DDevice9.h"
#include "proxyIDirect3DSwapChain9.h"
#include "d3drender.h"

/* Direct3D sucks hairy donkey balls. */

static CD3DFont *pD3DFont          = new CD3DFont("Verdana",        10, FCR_BOLD);
static CD3DFont *pD3DFontSAMP      = new CD3DFont("Arial",          10, FCR_BOLD|FCR_BORDER);
static CD3DFont *pD3DFontFixed     = new CD3DFont("Lucida Console", 8,  FCR_NONE);
static CD3DFont *pD3DFontSAMPFixed = new CD3DFont("Lucida Console", 8,  FCR_NONE|FCR_BORDER);


void proxyIDirect3DDevice9::LoadSpriteTexture(void)
{
   char filename[MAX_PATH];
   D3DLOCKED_RECT d3dlr;    
   FILE *fd = NULL;
   int x, y;
   uint8_t *surface;

   pSpriteTexture = NULL;

   /* XXX use a different texture format */
   if(FAILED(origIDirect3DDevice9->CreateTexture(256, 256, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pSpriteTexture, NULL)))
   {
      log_debug("Failed to create sprite texture!");
      goto out;
   }

   snprintf(filename, sizeof(filename), "%s\\%s", dll_working_dir, "s0beit_hack_a3v5.raw");
   if((fd = fopen(filename, "rb")) == NULL)
   {
      log_debug("Failed to open %s!", filename);
      goto out;
   }

   if(FAILED(pSpriteTexture->LockRect(0, &d3dlr, 0, 0)))
   {
      log_debug("Failed to lock texture!");
      goto out;
   }

   surface = (uint8_t *)d3dlr.pBits;

   for(y=0; y<120; y++)
   {
      uint8_t data[240];

      fread(data, 240, 1, fd);

      for(x=0; x<240; x++)
      {
         uint8_t alpha = (data[x] & 7) << 5;
         uint8_t value = data[x] & ~7;

         surface[x*4+0] = value;
         surface[x*4+1] = value;
         surface[x*4+2] = value;
         surface[x*4+3] = alpha;
      }

      surface += d3dlr.Pitch;
   }

   pSpriteTexture->UnlockRect(0);

   fclose(fd);

   log_debug("Sprite texture loaded.");

   return;

out:;
   SAFE_RELEASE(pSpriteTexture)
   if(fd != NULL)
      fclose(fd);
   return;
}


void proxyIDirect3DDevice9::DrawPlayerHPBar(float x, float y, float v, D3DCOLOR color)
{
   CD3DRender *render = pD3DFont->m_pRender;

   if(v > 100.0f)
      v = 100.0f;
   v /= 2.5f;

   render->D3DBox(x - 21.0f, y,        42.0f, 5.0f, D3DCOLOR_XRGB(0, 0, 0));
   render->D3DBox(x - 20.0f, y + 1.0f, v,     3.0f, color);
}


static void mmm_yummy_poop(const void *info, int *enabled, int *prev_enabled, int *render, const char *teh_name)
{
   if(info == NULL)
   {
      *prev_enabled = -1;
      *render = 0;
   }
   else
   {
      if(*prev_enabled == -1)
      {
         *prev_enabled = *enabled;
         *render = !*enabled;
      }

      if(!*prev_enabled && *enabled && *render)
      {
         *enabled = 0;
         *prev_enabled = 0;
         *render = 0;
         cheat_state_text("Disabled %s", teh_name);
      }
      else if(*prev_enabled && !*enabled)
      {
         cheat_state_text("Switched to s0beit %s", teh_name);
         *render = 1;
      }
      else if(!*prev_enabled && *enabled)
      {
         cheat_state_text("Switched to SA:MP %s", teh_name);
         *render = 0;
      }
      *prev_enabled = *enabled;
   }
}

void proxyIDirect3DDevice9::RenderSAMP(void)
{
   static int chat_last = -1, kill_last = -1;
   static int chat_render, kill_render, name_tags_render;
   struct actor_info *self = actor_info_get(ACTOR_SELF, ACTOR_ALIVE);
   struct samp_chat_info *chat = samp_chat_info_get();
   struct samp_kill_info *kill = samp_kill_info_get();
   CD3DRender *render = pD3DFont->m_pRender;

   mmm_yummy_poop(chat, &chat->enabled, &chat_last, &chat_render, "chat text");
   mmm_yummy_poop(kill, &kill->enabled, &kill_last, &kill_render, "kill list");
   
   /* XXX - why the fuck is this required? */
   name_tags_render = (samp_is_chatting()) ? false : set.d3dtext_tags;

   samp_name_tags_status(!name_tags_render);

   if(GetAsyncKeyState(VK_TAB) < 0)
      return;

   if(name_tags_render && self != NULL)   /* XXX don't get coords from self->base.matrix */
   {
      struct samp_player_list *spl = samp_player_list_get();

      if(spl != NULL)
      {
         int i, j;

         /* XXX todo: sort by z depth */
         for(i=0; i<SAMP_PLAYER_MAX; i++)
         {
            struct actor_info *actor = NULL;
            D3DVIEWPORT9 vp;
            float pos[4];
            float w, h;

            if(spl->alloc_map[i] != 1 || spl->player_info[i] == NULL)
               continue;

            if(spl->player_info[i]->actor == NULL)
               continue;
      
            if((actor = *spl->player_info[i]->actor) == NULL)
               continue;

            if(!samp_player_position_get(i, pos))
               continue;

            if(vect3_dist(pos, &self->base.matrix[4*3]) > set.d3dtext_tags_dist)
               continue;

            pos[2] += 1.0f;   /* put teh name tag above the head */
            pos[3] = 1.0f;

            /* 3d -> 2d coordinates */
            /* the world matrix is always an identity matrix in this case, so ignore it */
            /*matrix_vect4_mult((float *)origWorldMatrix.m, pos, pos);*/
            matrix_vect4_mult((float *)origViewMatrix.m, pos, pos);
            matrix_vect4_mult((float *)origProjMatrix.m, pos, pos);

            if(pos[3] == 0.0f || pos[2] < 0.0f)
               continue;   /* not visible, or screwy coords */

            for(j=0; j<3; j++)
               pos[j] /= pos[3];

            /* convert to viewport coordinates */
            GetViewport(&vp);
            pos[0] = (float)vp.X +                    ((1.0f + pos[0]) * (float)vp.Width)  / 2.0f;
            pos[1] = (float)vp.Y + (float)vp.Height - ((1.0f + pos[1]) * (float)vp.Height) / 2.0f;

            /* draw teh text! */
            w = pD3DFontSAMP->DrawLength(spl->name[i]);
            h = pD3DFontSAMP->DrawHeight();
            pD3DFontSAMP->Print(pos[0] - w / 2.0f, pos[1] - h - 12.0f,
               samp_color_get(spl->player_info[i]->color_id),
               spl->name[i], 0);

            /* and teh hp/armor bars */
            DrawPlayerHPBar(pos[0], pos[1] - 6.0f,
               spl->player_info[i]->actor_hitpoints, D3DCOLOR_XRGB(255,0,0));
            if(spl->player_info[i]->actor_armor > 0.0f)
            {
               DrawPlayerHPBar(pos[0], pos[1] - 12.0f,
                  spl->player_info[i]->actor_armor, D3DCOLOR_XRGB(255,255,255));
            }
         }
      }
   }

   if(chat_render && !gta_menu_active())
   {
      float pw, y = 9.0f;
      int i;

      for(i=0; i<10; i++)
      {
         struct samp_chat_entry *ent = &chat->chat_entry[i];

         switch(ent->type)
         {
         case 1:
            pw = pD3DFontSAMP->DrawLength(ent->prefix) + pD3DFontSAMP->DrawLength(" ");
            pD3DFontSAMP->Print(19.0f,      y, ent->prefix_color, ent->prefix, 0);
            pD3DFontSAMP->Print(19.0f + pw, y, ent->text_color,   ent->text, 0);
            break;

         case 2:
         case 3:
            pD3DFontSAMP->Print(19.0f, y, ent->text_color, ent->text, 0);
            break;
         }
         y += 4.0f + pD3DFontSAMP->DrawHeight();
      }
   }

   if(kill_render && !gta_menu_active())
   {
      float x = (float)pPresentParam.BackBufferWidth - 140.0f;
      float y = 220.0f;
      float w, h;
      int i;

      render->D3DBindTexture(pSpriteTexture);

      for(i=0; i<5; i++)
      {
         struct samp_kill_entry *ent = &kill->kill_entry[i];
         float u = 0.0f, v = 0.0f;

         if(strlen(ent->victim) > 0)
         {
            int type = ent->type;

            if(ent->type == 49)
               type = 20;  /* run over */
            else if(ent->type == 54)
               type = 21;  /* fall */
            else if((ent->type >= 18 && ent->type <= 20) || ent->type >= 47)
               type = 19;  /* suicide */

            u = (float)((type % 10) * 24) / 256.0f;
            v = (float)((type / 10) * 24) / 256.0f;

            render->D3DTexQuad(
               x - 12.0f, y - 12.0f, x + 12.0f, y + 12.0f,
               u, v, u + 23.0f / 256.0f, v + 23.0f / 256.0f);

            h = pD3DFontSAMP->DrawHeight() / 2.0f;
            if(strlen(ent->killer) == 0)
            {
               w = pD3DFontSAMP->DrawLength(ent->victim);
               pD3DFontSAMP->Print(x - 16.0f - w, y - h, ent->victim_color, ent->victim, 0);
            }
            else
            {
               w = pD3DFontSAMP->DrawLength(ent->killer);
               pD3DFontSAMP->Print(x - 16.0f - w, y - h, ent->killer_color, ent->killer, 0);
               pD3DFontSAMP->Print(x + 16.0f,     y - h, ent->victim_color, ent->victim, 0);
            }
         }

         y += 24.0f;
      }
 
      render->D3DBindTexture(NULL);
   }

}


void proxyIDirect3DDevice9::RenderMapDot(const float self_pos[3], const float pos[16], DWORD color, const char *name)
{
   static int init;
   CD3DRender *render = pD3DFont->m_pRender;
   float vect[3], rvect[2];
   float a, u, v, x, y, ts;


   vect3_vect3_sub(pos, self_pos, vect);

   if(vect3_length(vect) > 1000.0f)
      return;

   color = (color & 0x00FFFFFF) | 0xDF000000;

   a = -atan2f(cam_matrix[4*0+0], cam_matrix[4*0+1]) - M_PI / 2.0f;

   rvect[0] = vect[0] * cosf(a) - -vect[1] * sinf(a);
   rvect[1] = vect[0] * sinf(a) + -vect[1] * cosf(a);

   rvect[1] /= pPresentParam.BackBufferWidth / pPresentParam.BackBufferHeight;

   x = (float)pPresentParam.BackBufferWidth  / 2 + roundf(rvect[0]);
   y = (float)pPresentParam.BackBufferHeight / 2 + roundf(rvect[1]);

   /* the "^ v o" icons are 9x9 large, and located at 168x98 in the texture */

   u = 168.0f;
   v = 98.0f;

   if(vect[2] < -4.0f)
      u += 9.0f;
   else if(vect[2] <= 4.0f)
      u += 18.0f;

   u /= 256.0f;
   v /= 256.0f;
   ts = 9.0f / 256.0f;

   render->D3DBindTexture(pSpriteTexture);

   render->D3DTexQuad(
      x - 4.5f, y - 4.5f, x + 4.5f, y + 4.5f,
      u, v, u + ts, v + ts);

   render->D3DBindTexture(NULL);

   if(name != NULL)
      pD3DFontSAMPFixed->Print(x, y - 14.0f, color, name, FT_CENTER);
}


void proxyIDirect3DDevice9::RenderMap(void)
{
   struct samp_player_list *spl = samp_player_list_get();
   struct actor_info *self = actor_info_get(ACTOR_SELF, ACTOR_ALIVE);
   float pos[3];
   int i;

   if(self == NULL)
      return;

   if(spl == NULL && pool_actor != NULL)
   {
      for(int i=0; i<pool_actor->size; i++)
      {
         struct actor_info *info = actor_info_get(i, ACTOR_ALIVE);

         if(info == NULL)
            continue;

         RenderMapDot(
            &self->base.matrix[4*3],
            &info->base.matrix[4*3],
            D3DCOLOR_XRGB(255,255,255),
            NULL);
      }

      return;
   }

   if(spl == NULL)
      return;

   for(i=0; i<SAMP_PLAYER_MAX; i++)
   {
      if(!samp_player_position_get(i, pos))
         continue;

      RenderMapDot(
         &self->base.matrix[4*3],
         pos,
         samp_color_get(spl->player_info[i]->color_id),
         spl->name[i]);
   }

   /* self */
   RenderMapDot(
      &self->base.matrix[4*3],
      &self->base.matrix[4*3],
      D3DCOLOR_XRGB(255,255,255),
      NULL);
}


/* quick hack */
void debug_ptr_set(void *ptr)
{
   struct debug_info *debug = &cheat_state->debug;

   if(debug->hist_pos < DEBUG_HIST_LEN)
   {
      debug->hist_pos++;
   }
   else
   {
      memmove(debug->ptr, debug->ptr + 1, sizeof(debug->ptr) - sizeof(debug->ptr[0]));
      memmove(debug->offset, debug->offset + 1, sizeof(debug->offset) - sizeof(debug->offset[0]));
   }

   debug->ptr[debug->hist_pos] = (uint8_t *)ptr;
   debug->offset[debug->hist_pos] = 0;
   debug->data_prev_clear = 1;
}


/* quick hack */
void proxyIDirect3DDevice9::RenderDebug(void)
{
   static const int ROW_HEIGHT = (int)ceilf(pD3DFontFixed->DrawHeight());
   static const int CHAR_WIDTH  = (int)ceilf(pD3DFontFixed->DrawLength("W"));
   static const int ROWS = DEBUG_DATA_SIZE / 16;
   static const int data_size[4] = { 1, 2, 4, 4 };
   struct debug_info *debug = &cheat_state->debug;
   CD3DRender *render = pD3DFont->m_pRender;
   static char str_data[17], str[256];
   int x, y, row, col, i;
   int offset, offset16;
   uint8_t *ptr, *data;


   ptr = debug->ptr[debug->hist_pos] - DEBUG_DATA_SIZE;
   offset = debug->offset[debug->hist_pos];
   offset16 = (unsigned int)offset % 16;
   ptr += offset - offset16 + DEBUG_DATA_SIZE / 2;

   memset(debug->data, 0, DEBUG_DATA_SIZE);
   memcpy_safe(debug->data, ptr, DEBUG_DATA_SIZE);

   if(!debug->data_prev_clear)
   {
      for(i=0; i<DEBUG_DATA_SIZE; i++)
      {
         if(debug->data[i] != debug->data_prev[i])
            debug->modify_time[i] = time_get();
      }
   }
   else
   {
      memset(debug->modify_time, 0, sizeof(debug->modify_time));
   }
   debug->data_prev_clear = 0;

   x = 324;
   y = 4;

   /* blue box */
   render->D3DBoxi(x - 2, y - 2, CHAR_WIDTH * 75 + 4, ROW_HEIGHT * 27 + 4, D3DCOLOR_ARGB(191, 0, 0, 255));

   /* render selection */
   for(row=offset16; row<offset16+data_size[debug->data_type]; row++)
   {
      col = (ROWS / 2) + row / 16;
      render->D3DBoxi(
         x + CHAR_WIDTH * (10 + (row % 16) * 3), y + ROW_HEIGHT * col,
         CHAR_WIDTH * 3, ROW_HEIGHT, D3DCOLOR_ARGB(127, 0, 255, 0));
      render->D3DBoxi(
         x + CHAR_WIDTH * (59 + (row % 16)), y + ROW_HEIGHT * col,
         CHAR_WIDTH, ROW_HEIGHT, D3DCOLOR_ARGB(127, 0, 255, 0));
   }

   /* render hex view */
   for(row=0; row<ROWS; row++)
   {
      int red_text = 0;
      int len = 10;
      int xpos = x;

      snprintf(str, sizeof(str), "%p  ", ptr + row * 16);

      for(col=0; col<16; col++)
      {
         uint32_t mod_time = debug->modify_time[row*16+col];
         uint8_t ch = debug->data[row*16+col];
         int color_switch = 0;


         if(mod_time != 0 && time_get() < mod_time + MSEC_TO_TIME(2000))
            color_switch = !red_text;  /* switch color, unless red_text == 1 */
         else if(red_text)
            color_switch = 1;

         if(color_switch)
         {
            pD3DFontFixed->Print((float)xpos, (float)y,
               red_text ? D3DCOLOR_XRGB(255, 31, 31) : D3DCOLOR_XRGB(191, 191, 191),
               str, FT_NONE);

            xpos += CHAR_WIDTH * len;
            str[0] = 0;
            len = 0;

            red_text ^= 1;
         }

         snprintf(str + len, sizeof(str) - len, "%02x ", debug->data[row*16+col]);
         len += 3;

         str_data[col] = (char)((ch < 32) ? '.' : ch);
      }

      pD3DFontFixed->Print((float)xpos, (float)y,
         red_text ? D3DCOLOR_XRGB(255, 31, 31) : D3DCOLOR_XRGB(191, 191, 191),
         str, FT_NONE);

      pD3DFontFixed->Print((float)x + CHAR_WIDTH * 59, (float)y, D3DCOLOR_XRGB(191, 191, 191), str_data, FT_NONE);

      y += ROW_HEIGHT;
   }


   /* everything else \o/ */
   data = &debug->data[DEBUG_DATA_SIZE / 2 + offset16];
   memcpy(debug->cursor_data, data, sizeof(debug->cursor_data));

   /* data type info */
   snprintf(str, sizeof(str), "=>%c%02x(%-3d),%c%04x(%-5d),%c%08x(%d),%c%.4f, %s ptr",
      (debug->data_type == 0) ? '*' : ' ', *(uint8_t  *)data, *(uint8_t  *)data,
      (debug->data_type == 1) ? '*' : ' ', *(uint16_t *)data, *(uint16_t *)data,
      (debug->data_type == 2) ? '*' : ' ', *(uint32_t *)data, *(uint32_t *)data,
      (debug->data_type == 3) ? '*' : ' ', *(float *)data,
      IsBadReadPtr(*(void **)data, 1) ? "Bad" : "OK");
   pD3DFontFixed->Print((float)x, (float)y, D3DCOLOR_XRGB(191, 191, 191), str, FT_NONE);
   y += ROW_HEIGHT;

   /* ptr info */
   snprintf(str, sizeof(str), "Viewing: %s", debug_classify_pointer((void *)(debug->ptr[debug->hist_pos] + offset)));
   pD3DFontFixed->Print((float)x, (float)y, D3DCOLOR_XRGB(191, 191, 191), str, FT_NONE);
   y += ROW_HEIGHT;

   snprintf(str, sizeof(str), "Pointer: %s", debug_classify_pointer(*(void **)data));
   pD3DFontFixed->Print((float)x, (float)y, D3DCOLOR_XRGB(191, 191, 191), str, FT_NONE);
   y += ROW_HEIGHT;

   /* ptr stack info */
   snprintf(debug->ptr_hist_str, sizeof(debug->ptr_hist_str),
      "Ptr stack (%d): %s", debug->hist_pos, debug->hist_pos > 2 ? "... " : "");
   for(i=debug->hist_pos-2; i<=debug->hist_pos; i++)
   {
      int len = (int)strlen(debug->ptr_hist_str);

      if(i < 0)
         continue;
      snprintf(debug->ptr_hist_str + len, sizeof(debug->ptr_hist_str) - len, "%p+0x%x -> ",
         debug->ptr[i], debug->offset[i]);
   }
   debug->ptr_hist_str[strlen(debug->ptr_hist_str) - 4] = 0;
   pD3DFontFixed->Print((float)x, (float)y, D3DCOLOR_XRGB(191, 191, 191), debug->ptr_hist_str, FT_NONE);
   y += ROW_HEIGHT * 2;

   /* print help */
   pD3DFontFixed->Print((float)x, (float)y, D3DCOLOR_XRGB(191, 191, 191),
      "np4/6,8/2,9/3 = move   np7 = return   np1 = go to pointer", FT_NONE);
   y += ROW_HEIGHT;

   pD3DFontFixed->Print((float)x, (float)y, D3DCOLOR_XRGB(191, 191, 191),
      "np/ = data type   np-/+ = inc/dec   np* = ptr stack to clipboard", FT_NONE);

   memcpy(debug->data_prev, debug->data, DEBUG_DATA_SIZE);
}


#define MENU_ROWS  12
#define MENU_WIDTH 400

void proxyIDirect3DDevice9::RenderMenu(void)
{
   static const int ROW_HEIGHT = (int)ceilf(pD3DFont->DrawHeight());
   static const int MENU_HEIGHT = (int)ceilf(pD3DFont->DrawHeight() * (float)MENU_ROWS) + 2;
   CD3DRender *render = pD3DFont->m_pRender;
   char title[256];
   struct menu_item *item;
   struct menu *menu;
   int left, top;
   float x, y;
   int pos, top_pos, i;


   if(menu_active == NULL)
      return;

   /* find root menu */
   for(menu=menu_active; menu->parent!=NULL; menu=menu->parent);

   strlcpy(title, "m0d_s0beit", sizeof(title));
   while(menu != NULL)
   {
      if(menu->pos < 0 || menu->pos >= menu->count)
         break;
      item = &menu->item[menu->pos];
      if(item->submenu == NULL || menu == menu_active)
         break;
      snprintf(title + strlen(title), sizeof(title) - strlen(title), " > %s", item->name);
      menu = item->submenu;
   }

   /* draw titlebar */
   left = pPresentParam.BackBufferWidth / 2 - MENU_WIDTH / 2;
   top = pPresentParam.BackBufferHeight - MENU_HEIGHT - ROW_HEIGHT - 2 - 16 - 2;
   render->D3DBoxBorderi(left, top, (int)ceilf(pD3DFont->DrawLength(title)) + 2, ROW_HEIGHT + 2,
      D3DCOLOR_ARGB(223, 91, 91, 91), D3DCOLOR_ARGB(223, 63, 63, 63));
   pD3DFont->Print((float)(left + 1), (float)(top + 1), D3DCOLOR_XRGB(223, 223, 223), title, FT_NONE);

   /* draw window */
   left = pPresentParam.BackBufferWidth  / 2 - MENU_WIDTH / 2;
   top = pPresentParam.BackBufferHeight - MENU_HEIGHT - 1 - 16;
   render->D3DBoxBorderi(left, top, MENU_WIDTH, MENU_HEIGHT,
      D3DCOLOR_ARGB(223, 63, 63, 63), D3DCOLOR_ARGB(223, 31, 31, 31));

   /* calculate positions */
   pos = menu_active->pos;
   top_pos = menu_active->top_pos;

   if(pos - MENU_ROWS >= top_pos)
      top_pos = pos - MENU_ROWS + 1;
   if(pos < top_pos)
      top_pos = pos;

   if(top_pos < 0)
      top_pos = 0;
   else if(top_pos >= menu_active->count)
      top_pos = menu_active->count - 1;

   menu_active->top_pos = top_pos;

   /* draw menu items */
   y = (float)top;
   x = (float)(left + 2);
   for(i=top_pos; i<top_pos+MENU_ROWS; i++,y+=pD3DFont->DrawHeight())
   {
      int enabled;

      if(i < 0 || i >= menu_active->count)
         continue;

      item = &menu_active->item[i];
      enabled = menu_active->callback(MENU_OP_ENABLED, item);

      if(i == pos)
      {
         render->D3DBoxi(
            left + 1, (int)floorf(y) + 1,
            MENU_WIDTH - 1, ROW_HEIGHT + 1,
            D3DCOLOR_ARGB(223, 127, 63, 63));
      }

      if(item->name[0] == '\t')
      {
         pD3DFont->Print(x, y, item->color, item->name + 1, FT_NONE);
         render->D3DBoxi(left + 2, (int)floorf(y) + ROW_HEIGHT - 1,
            (int)ceilf(pD3DFont->DrawLength(item->name + 1)), 1,
            D3DCOLOR_ARGB(191, 127, 127, 127));
      }
      else
      {
         /* XXX ... */
         pD3DFont->Print(x, y, enabled ? D3DCOLOR_XRGB(157, 255, 157) : item->color, item->name, FT_NONE);
      }

      if(item->submenu != NULL)
      {
         pD3DFont->Print(
            x + (float)MENU_WIDTH - pD3DFont->DrawLength(">") - 4, y,
            D3DCOLOR_ARGB(191, 127, 127, 127), ">", FT_NONE);
      }
   }
}


void proxyIDirect3DDevice9::RenderVehicleHPBar(void)
{
   struct vehicle_info *info = vehicle_info_get(VEHICLE_SELF, 0);
   CD3DRender *render = pD3DFont->m_pRender;
   char text[32];
   int right, bottom;
   int hp;

   if(info == NULL)
      return;

   right = pPresentParam.BackBufferWidth - 1;
   bottom = pPresentParam.BackBufferHeight - 1;

   if(info->hitpoints > 1000.0f)
      hp = 100;
   else
      hp = (int)(info->hitpoints / 10.0f);

   render->D3DBoxi(right - 102, bottom - 10, 102, 10, D3DCOLOR_ARGB(127, 0, 0, 0));
   render->D3DBoxi(right - 101, bottom - 9, hp, 8, D3DCOLOR_ARGB(127, 191, 0, 0));
   snprintf(text, sizeof(text), "%d", (int)info->hitpoints);
   pD3DFontFixed->Print((float)(right - 100), (float)(bottom - 9), D3DCOLOR_XRGB(255, 255, 255), text, 0);
}


proxyIDirect3DDevice9::proxyIDirect3DDevice9(IDirect3DDevice9 *pOriginal)
{
   log_debug("proxyIDirect3DDevice9 constructor called. Original IDirect3DDevice9 interface address is 0x%p", pOriginal);

   origIDirect3DDevice9 = pOriginal;
   bD3DRenderInit = false;
}

proxyIDirect3DDevice9::~proxyIDirect3DDevice9(void)
{
   log_debug("proxyIDirect3DDevice9 destructor called.");
}

HRESULT proxyIDirect3DDevice9::QueryInterface(REFIID riid, void **ppvObj)
{
   HRESULT hRes;

   *ppvObj = NULL;
   hRes = origIDirect3DDevice9->QueryInterface(riid, ppvObj); 
   if(hRes == NOERROR)
      *ppvObj = this;

   return hRes;
}

ULONG proxyIDirect3DDevice9::AddRef(void)
{
   return origIDirect3DDevice9->AddRef();
}

ULONG proxyIDirect3DDevice9::Release(void)
{
   ULONG count = origIDirect3DDevice9->Release();

   if(count == 0)
   {
      pDirect3DDevice9 = NULL;
      delete(this);
   }

   return count;
}

HRESULT proxyIDirect3DDevice9::TestCooperativeLevel(void)
{
   return origIDirect3DDevice9->TestCooperativeLevel();
}

UINT proxyIDirect3DDevice9::GetAvailableTextureMem(void)
{
   return origIDirect3DDevice9->GetAvailableTextureMem();
}

HRESULT proxyIDirect3DDevice9::EvictManagedResources(void)
{
   return origIDirect3DDevice9->EvictManagedResources();
}

HRESULT proxyIDirect3DDevice9::GetDirect3D(IDirect3D9 **ppD3D9)
{
   return origIDirect3DDevice9->GetDirect3D(ppD3D9);
}

HRESULT proxyIDirect3DDevice9::GetDeviceCaps(D3DCAPS9 *pCaps)
{
   return origIDirect3DDevice9->GetDeviceCaps(pCaps);
}

HRESULT proxyIDirect3DDevice9::GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE *pMode)
{
   return origIDirect3DDevice9->GetDisplayMode(iSwapChain, pMode);
}

HRESULT proxyIDirect3DDevice9::GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters)
{
   return origIDirect3DDevice9->GetCreationParameters(pParameters);
}

HRESULT proxyIDirect3DDevice9::SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9 *pCursorBitmap)
{
   return origIDirect3DDevice9->SetCursorProperties(XHotSpot, YHotSpot, pCursorBitmap);
}

void proxyIDirect3DDevice9::SetCursorPosition(int X, int Y, DWORD Flags)
{
   origIDirect3DDevice9->SetCursorPosition(X, Y, Flags);
}

BOOL proxyIDirect3DDevice9::ShowCursor(BOOL bShow)
{
   return origIDirect3DDevice9->ShowCursor(bShow);
}

HRESULT proxyIDirect3DDevice9::CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **pSwapChain)
{
   return origIDirect3DDevice9->CreateAdditionalSwapChain(pPresentationParameters, pSwapChain);
}

HRESULT proxyIDirect3DDevice9::GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9 **pSwapChain)
{
   IDirect3DSwapChain9 *pOriginal = NULL;
   HRESULT hRes;


   if(iSwapChain != 0)
      return origIDirect3DDevice9->GetSwapChain(iSwapChain, pSwapChain);
   
   if(pDirect3DSwapChain9 != NULL)
   {
      *pSwapChain = pDirect3DSwapChain9;
      return D3D_OK;
   }

   pOriginal = NULL;
   hRes = origIDirect3DDevice9->GetSwapChain(iSwapChain, &pOriginal);

   pDirect3DSwapChain9 = new proxyIDirect3DSwapChain9(pOriginal, origIDirect3DDevice9);

   *pSwapChain = pDirect3DSwapChain9;

   return hRes;
}

UINT proxyIDirect3DDevice9::GetNumberOfSwapChains(void)
{
   return origIDirect3DDevice9->GetNumberOfSwapChains();
}

HRESULT proxyIDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS *pPresentationParameters)
{
   HRESULT hRet;


   log_debug("proxyIDirect3DDevice9::Reset called.");

   if(bD3DRenderInit)
   {
      log_debug("Invalidating D3D renderer.");
      pD3DFont->Invalidate();
      pD3DFontSAMP->Invalidate();
      pD3DFontFixed->Invalidate();
      pD3DFontSAMPFixed->Invalidate();
      bD3DRenderInit = false;
   }

   if(set.window_mode)
   {
      log_debug("Forcing window mode.");
      pPresentationParameters->Windowed = 1;
      pPresentationParameters->Flags = 0;
      pPresentationParameters->FullScreen_RefreshRateInHz = 0;
      pPresentationParameters->PresentationInterval = 0;
   }

   hRet = origIDirect3DDevice9->Reset(pPresentationParameters);

   if(SUCCEEDED(hRet))
   {
      log_debug("Initializing D3D renderer.");
      pD3DFont->Initialize(pDirect3DDevice9);
      pD3DFontSAMP->Initialize(pDirect3DDevice9);
      pD3DFontFixed->Initialize(pDirect3DDevice9);
      pD3DFontSAMPFixed->Initialize(pDirect3DDevice9);
      bD3DRenderInit = true;
      log_debug("Ok.");

      pPresentParam = *pPresentationParameters;

      if(set.window_mode                     &&
         pPresentParam.BackBufferWidth != 0  &&
         pPresentParam.BackBufferHeight != 0)
      {
         log_debug("Setting window parameters.");

         if(set.window_mode_titlebar)
         {
            RECT r;

            /* add caption bar, etc */
            SetWindowLong(pPresentParam.hDeviceWindow, GWL_STYLE,
               WS_POPUP | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE);

            /* update caption bar, etc */
            SetWindowPos(pPresentParam.hDeviceWindow, HWND_NOTOPMOST,
               0, 0, 0, 0,
               SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);

            /* the client area of the window must be the same size as the back buffer */
            GetClientRect(pPresentParam.hDeviceWindow, &r);
            SetWindowPos(pPresentParam.hDeviceWindow, HWND_NOTOPMOST,
               0, 0,
               pPresentParam.BackBufferWidth + (pPresentParam.BackBufferWidth - r.right),
               pPresentParam.BackBufferHeight + (pPresentParam.BackBufferHeight - r.bottom),
               SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE);
         }
         else
         {
            SetWindowPos(pPresentParam.hDeviceWindow, HWND_NOTOPMOST,
               0, 0, 0, 0,
               SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
         }
      }
   }

   log_debug("Leaving.");

   return hRet;
}

LONG WINAPI proxyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
   log_debug("Crashed inside m0d_s0beit.");
   log_debug("Base address is 0x%p, EIP is at 0x%p, Reason is %08x.",
      hDllModule,
      ExceptionInfo->ExceptionRecord->ExceptionAddress,
      ExceptionInfo->ExceptionRecord->ExceptionCode);

   return EXCEPTION_EXECUTE_HANDLER;
}

HRESULT proxyIDirect3DDevice9::Present(CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion)
{
   static int init;


   SetUnhandledExceptionFilter(proxyUnhandledExceptionFilter);

   if(!init)
   {
      LoadSpriteTexture();
      init = 1;
   }

   cheat_hook(pPresentParam.hDeviceWindow);

   /* dumb macro */
   #define HUD_TEXT(x, color, text) \
      pD3DFont->Print(                                                                       \
         1.0f + (x), (float)(pPresentParam.BackBufferHeight - 1) - pD3DFont->DrawHeight(),   \
         (color), (text), FT_NONE);                                                          \
      (x) += pD3DFont->DrawLength(text);
   #define HUD_TEXT_TGL(x, color, text) \
      HUD_TEXT(x, color_text, "[");     \
      HUD_TEXT(x, color, text);         \
      HUD_TEXT(x, color_text, "] ")

   if(bD3DRenderInit && origIDirect3DDevice9->BeginScene() == D3D_OK)
   {
      char buf[128];
      float x = 0.0f;
      uint32_t color_text = D3DCOLOR_ARGB(127, 255, 255, 255);
      uint32_t color_enabled  = D3DCOLOR_ARGB(191, 63, 255, 63);
      uint32_t color_disabled = D3DCOLOR_ARGB(191, 191, 191, 191);

      if(SUCCEEDED(CD3DBaseRender::BeginRender()))
      {
         if(set.d3dtext_hud)
         {
            if(cheat_panic() || cheat_state->state == CHEAT_STATE_NONE)
            {
               HUD_TEXT(x, color_text, "m0d s0beit for SA:MP");
            }
            else
            {
               HUD_TEXT_TGL(x, cheat_state->generic.hp_cheat ? color_enabled : color_disabled , "Inv");
               HUD_TEXT_TGL(x, cheat_state->generic.weapon ? color_enabled : color_disabled , "Weapon");
               HUD_TEXT_TGL(x, cheat_state->generic.money ? color_enabled : color_disabled , "Money");
               HUD_TEXT_TGL(x, cheat_state->generic.vehicles_freeze ? color_enabled : color_disabled , "Freeze");
            }

            if(cheat_state->state == CHEAT_STATE_VEHICLE)
            {
               HUD_TEXT_TGL(x, cheat_state->vehicle.air_brake ? color_enabled : color_disabled , "AirBrk");
               HUD_TEXT_TGL(x, cheat_state->vehicle.stick ? color_enabled : color_disabled , "Stick");
               HUD_TEXT_TGL(x, cheat_state->vehicle.protection ? color_enabled : color_disabled , "Prot");
            }
            else if(cheat_state->state == CHEAT_STATE_ACTOR)
            {
               HUD_TEXT_TGL(x, cheat_state->actor.air_brake ? color_enabled : color_disabled , "AirBrk");
               HUD_TEXT_TGL(x, cheat_state->actor.stick ? color_enabled : color_disabled , "Stick");
               HUD_TEXT_TGL(x, cheat_state->actor.autoaim ? color_enabled : color_disabled , "Aim");
            }

            if(cheat_state->state != CHEAT_STATE_NONE)
            {
               float *coord = (cheat_state->state == CHEAT_STATE_VEHICLE) ?
                               cheat_state->vehicle.coords
                             : cheat_state->actor.coords;

               snprintf(buf, sizeof(buf), "Pos: %.2f %.2f %.2f %d", coord[0], coord[1], coord[2], gta_interior_id_get());
               HUD_TEXT(x, color_text, buf);
            }

            if(cheat_state->text_time > 0 && time_get() - cheat_state->text_time < MSEC_TO_TIME(3000))
            {
               uint32_t color, alpha = 191;

               if(time_get() - cheat_state->text_time > MSEC_TO_TIME(2000))
                  alpha -= (time_get() - cheat_state->text_time - MSEC_TO_TIME(2000)) * 191 / MSEC_TO_TIME(1000);

               color = D3DCOLOR_ARGB(alpha, 191, 31, 31);

               HUD_TEXT(x, color, ": ");
               HUD_TEXT(x, color, cheat_state->text);
            }
         }  /* if(set.d3dtext_hud) */

         RenderSAMP();

         if(cheat_state->generic.map)
            RenderMap();

         if(cheat_state->generic.menu)
            RenderMenu();

         if(cheat_state->debug_enabled)
            RenderDebug();

         if(set.d3dtext_hud && cheat_state->state == CHEAT_STATE_VEHICLE)
            RenderVehicleHPBar();

         CD3DBaseRender::EndRender();
      }  /* CD3DBaseRender::BeginRender() */

      origIDirect3DDevice9->EndScene();
   }  /* d3dtext */

   SetUnhandledExceptionFilter(NULL);

   return origIDirect3DDevice9->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}

HRESULT proxyIDirect3DDevice9::GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer)
{
   return origIDirect3DDevice9->GetBackBuffer(iSwapChain, iBackBuffer, Type, ppBackBuffer);
}

HRESULT proxyIDirect3DDevice9::GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS *pRasterStatus)
{
   return origIDirect3DDevice9->GetRasterStatus(iSwapChain, pRasterStatus);
}

HRESULT proxyIDirect3DDevice9::SetDialogBoxMode(BOOL bEnableDialogs)
{
   return origIDirect3DDevice9->SetDialogBoxMode(bEnableDialogs);
}

void proxyIDirect3DDevice9::SetGammaRamp(UINT iSwapChain, DWORD Flags, CONST D3DGAMMARAMP *pRamp)
{
   origIDirect3DDevice9->SetGammaRamp(iSwapChain, Flags, pRamp);
}

void proxyIDirect3DDevice9::GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP *pRamp)
{
   origIDirect3DDevice9->GetGammaRamp(iSwapChain, pRamp);
}

HRESULT proxyIDirect3DDevice9::CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9 **ppTexture, HANDLE *pSharedHandle)
{
   return origIDirect3DDevice9->CreateTexture(Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
}

HRESULT proxyIDirect3DDevice9::CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9 **ppVolumeTexture, HANDLE *pSharedHandle)
{
   return origIDirect3DDevice9->CreateVolumeTexture(Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle);
}

HRESULT proxyIDirect3DDevice9::CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9 **ppCubeTexture, HANDLE *pSharedHandle)
{
   return origIDirect3DDevice9->CreateCubeTexture(EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle);
}

HRESULT proxyIDirect3DDevice9::CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9 **ppVertexBuffer, HANDLE *pSharedHandle)
{
   return origIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
}

HRESULT proxyIDirect3DDevice9::CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9 **ppIndexBuffer, HANDLE *pSharedHandle)
{
   return origIDirect3DDevice9->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, pSharedHandle);
}

HRESULT proxyIDirect3DDevice9::CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle)
{
   return origIDirect3DDevice9->CreateRenderTarget(Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle);
}

HRESULT proxyIDirect3DDevice9::CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle)
{
   return origIDirect3DDevice9->CreateDepthStencilSurface(Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle);
}

HRESULT proxyIDirect3DDevice9::UpdateSurface(IDirect3DSurface9 *pSourceSurface, CONST RECT *pSourceRect, IDirect3DSurface9 *pDestinationSurface, CONST POINT *pDestPoint)
{
   return origIDirect3DDevice9->UpdateSurface(pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
}

HRESULT proxyIDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9 *pSourceTexture, IDirect3DBaseTexture9 *pDestinationTexture)
{
   return origIDirect3DDevice9->UpdateTexture(pSourceTexture, pDestinationTexture);
}

HRESULT proxyIDirect3DDevice9::GetRenderTargetData(IDirect3DSurface9 *pRenderTarget, IDirect3DSurface9 *pDestSurface)
{
   return origIDirect3DDevice9->GetRenderTargetData(pRenderTarget, pDestSurface);
}

HRESULT proxyIDirect3DDevice9::GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9 *pDestSurface)
{
   return origIDirect3DDevice9->GetFrontBufferData(iSwapChain, pDestSurface);
}

HRESULT proxyIDirect3DDevice9::StretchRect(IDirect3DSurface9 *pSourceSurface, CONST RECT *pSourceRect, IDirect3DSurface9 *pDestSurface, CONST RECT *pDestRect, D3DTEXTUREFILTERTYPE Filter)
{
   return origIDirect3DDevice9->StretchRect(pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter);
}

HRESULT proxyIDirect3DDevice9::ColorFill(IDirect3DSurface9 *pSurface, CONST RECT *pRect, D3DCOLOR color)
{
   return origIDirect3DDevice9->ColorFill(pSurface, pRect, color);
}

HRESULT proxyIDirect3DDevice9::CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle)
{
   return origIDirect3DDevice9->CreateOffscreenPlainSurface(Width, Height, Format, Pool, ppSurface, pSharedHandle);
}

HRESULT proxyIDirect3DDevice9::SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 *pRenderTarget)
{
   return origIDirect3DDevice9->SetRenderTarget(RenderTargetIndex, pRenderTarget);
}

HRESULT proxyIDirect3DDevice9::GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 **ppRenderTarget)
{
   return origIDirect3DDevice9->GetRenderTarget(RenderTargetIndex, ppRenderTarget);
}

HRESULT proxyIDirect3DDevice9::SetDepthStencilSurface(IDirect3DSurface9 *pNewZStencil)
{
   return origIDirect3DDevice9->SetDepthStencilSurface(pNewZStencil);
}

HRESULT proxyIDirect3DDevice9::GetDepthStencilSurface(IDirect3DSurface9 **ppZStencilSurface)
{
   return origIDirect3DDevice9->GetDepthStencilSurface(ppZStencilSurface);
}

HRESULT proxyIDirect3DDevice9::BeginScene(void)
{
   HRESULT hRet = origIDirect3DDevice9->BeginScene();

   if(SUCCEEDED(hRet) && !bD3DRenderInit)
   {
      bD3DRenderInit = true;
      log_debug("Initializing D3D renderer.");
      pD3DFont->Initialize(pDirect3DDevice9);
      pD3DFontSAMP->Initialize(pDirect3DDevice9);
      pD3DFontFixed->Initialize(pDirect3DDevice9);
      pD3DFontSAMPFixed->Initialize(pDirect3DDevice9);
      log_debug("Ok.");
   }

   return hRet;
}

HRESULT proxyIDirect3DDevice9::EndScene(void)
{
   return origIDirect3DDevice9->EndScene();
}

HRESULT proxyIDirect3DDevice9::Clear(DWORD Count, CONST D3DRECT *pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil)
{
   return origIDirect3DDevice9->Clear(Count, pRects, Flags, Color, Z, Stencil);
}

HRESULT proxyIDirect3DDevice9::SetTransform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX *pMatrix)
{
   switch(State)
   {
   case D3DTS_VIEW:       origViewMatrix = *pMatrix; break;
   case D3DTS_PROJECTION: origProjMatrix = *pMatrix; break;
   }

   return origIDirect3DDevice9->SetTransform(State, pMatrix);
}

HRESULT proxyIDirect3DDevice9::GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX *pMatrix)
{
   return origIDirect3DDevice9->GetTransform(State, pMatrix);
}

HRESULT proxyIDirect3DDevice9::MultiplyTransform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX *pMatrix)
{
   return origIDirect3DDevice9->MultiplyTransform(State, pMatrix);
}

HRESULT proxyIDirect3DDevice9::SetViewport(CONST D3DVIEWPORT9 *pViewport)
{
   return origIDirect3DDevice9->SetViewport(pViewport);
}

HRESULT proxyIDirect3DDevice9::GetViewport(D3DVIEWPORT9 *pViewport)
{
   return origIDirect3DDevice9->GetViewport(pViewport);
}

HRESULT proxyIDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9 *pMaterial)
{
   return origIDirect3DDevice9->SetMaterial(pMaterial);
}

HRESULT proxyIDirect3DDevice9::GetMaterial(D3DMATERIAL9 *pMaterial)
{
   return origIDirect3DDevice9->GetMaterial(pMaterial);
}

HRESULT proxyIDirect3DDevice9::SetLight(DWORD Index, CONST D3DLIGHT9 *pLight)
{
   return origIDirect3DDevice9->SetLight(Index, pLight);
}

HRESULT proxyIDirect3DDevice9::GetLight(DWORD Index, D3DLIGHT9 *pLight)
{
   return origIDirect3DDevice9->GetLight(Index, pLight);
}

HRESULT proxyIDirect3DDevice9::LightEnable(DWORD Index, BOOL Enable)
{
   return origIDirect3DDevice9->LightEnable(Index, Enable);
}

HRESULT proxyIDirect3DDevice9::GetLightEnable(DWORD Index, BOOL *pEnable)
{
   return origIDirect3DDevice9->GetLightEnable(Index, pEnable);
}

HRESULT proxyIDirect3DDevice9::SetClipPlane(DWORD Index, CONST float *pPlane)
{
   return origIDirect3DDevice9->SetClipPlane(Index, pPlane);
}

HRESULT proxyIDirect3DDevice9::GetClipPlane(DWORD Index, float *pPlane)
{
   return origIDirect3DDevice9->GetClipPlane(Index, pPlane);
}

HRESULT proxyIDirect3DDevice9::SetRenderState(D3DRENDERSTATETYPE State, DWORD Value)
{
   return origIDirect3DDevice9->SetRenderState(State, Value);
}

HRESULT proxyIDirect3DDevice9::GetRenderState(D3DRENDERSTATETYPE State, DWORD *pValue)
{
   return origIDirect3DDevice9->GetRenderState(State, pValue);
}

HRESULT proxyIDirect3DDevice9::CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9 **ppSB)
{
   return origIDirect3DDevice9->CreateStateBlock(Type, ppSB);
}

HRESULT proxyIDirect3DDevice9::BeginStateBlock(void)
{
   return origIDirect3DDevice9->BeginStateBlock();
}

HRESULT proxyIDirect3DDevice9::EndStateBlock(IDirect3DStateBlock9 **ppSB)
{
   return origIDirect3DDevice9->EndStateBlock(ppSB);
}

HRESULT proxyIDirect3DDevice9::SetClipStatus(CONST D3DCLIPSTATUS9 *pClipStatus)
{
   return origIDirect3DDevice9->SetClipStatus(pClipStatus);
}

HRESULT proxyIDirect3DDevice9::GetClipStatus(D3DCLIPSTATUS9 *pClipStatus)
{
   return origIDirect3DDevice9->GetClipStatus(pClipStatus);
}

HRESULT proxyIDirect3DDevice9::GetTexture(DWORD Stage, IDirect3DBaseTexture9 **ppTexture)
{
   return origIDirect3DDevice9->GetTexture(Stage, ppTexture);
}

HRESULT proxyIDirect3DDevice9::SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture)
{
   return origIDirect3DDevice9->SetTexture(Stage, pTexture);
}

HRESULT proxyIDirect3DDevice9::GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
{
   return origIDirect3DDevice9->GetTextureStageState(Stage, Type, pValue);
}

HRESULT proxyIDirect3DDevice9::SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value)
{
   return origIDirect3DDevice9->SetTextureStageState(Stage, Type, Value);
}

HRESULT proxyIDirect3DDevice9::GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD *pValue)
{
   return origIDirect3DDevice9->GetSamplerState(Sampler, Type, pValue);
}

HRESULT proxyIDirect3DDevice9::SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value)
{
   return origIDirect3DDevice9->SetSamplerState(Sampler, Type, Value);
}

HRESULT proxyIDirect3DDevice9::ValidateDevice(DWORD *pNumPasses)
{
   return origIDirect3DDevice9->ValidateDevice(pNumPasses);
}

HRESULT proxyIDirect3DDevice9::SetPaletteEntries(UINT PaletteNumber, CONST PALETTEENTRY *pEntries)
{
   return origIDirect3DDevice9->SetPaletteEntries(PaletteNumber, pEntries);
}

HRESULT proxyIDirect3DDevice9::GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY *pEntries)
{
   return origIDirect3DDevice9->GetPaletteEntries(PaletteNumber, pEntries);
}

HRESULT proxyIDirect3DDevice9::SetCurrentTexturePalette(UINT PaletteNumber)
{
   return origIDirect3DDevice9->SetCurrentTexturePalette(PaletteNumber);
}

HRESULT proxyIDirect3DDevice9::GetCurrentTexturePalette(UINT *PaletteNumber)
{
   return origIDirect3DDevice9->GetCurrentTexturePalette(PaletteNumber);
}

HRESULT proxyIDirect3DDevice9::SetScissorRect(CONST RECT *pRect)
{
   return origIDirect3DDevice9->SetScissorRect(pRect);
}

HRESULT proxyIDirect3DDevice9::GetScissorRect(RECT *pRect)
{
   return origIDirect3DDevice9->GetScissorRect(pRect);
}

HRESULT proxyIDirect3DDevice9::SetSoftwareVertexProcessing(BOOL bSoftware)
{
   return origIDirect3DDevice9->SetSoftwareVertexProcessing(bSoftware);
}

BOOL proxyIDirect3DDevice9::GetSoftwareVertexProcessing(void)
{
   return origIDirect3DDevice9->GetSoftwareVertexProcessing();
}

HRESULT proxyIDirect3DDevice9::SetNPatchMode(float nSegments)
{
   return origIDirect3DDevice9->SetNPatchMode(nSegments);
}

float proxyIDirect3DDevice9::GetNPatchMode(void)
{
   return origIDirect3DDevice9->GetNPatchMode();
}

HRESULT proxyIDirect3DDevice9::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount)
{
   return origIDirect3DDevice9->DrawPrimitive(PrimitiveType, StartVertex, PrimitiveCount);
}

HRESULT proxyIDirect3DDevice9::DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount)
{
   if(set.blur_remove && primCount == 360 && NumVertices == 720)
         return D3D_OK;

   return origIDirect3DDevice9->DrawIndexedPrimitive(PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
}

HRESULT proxyIDirect3DDevice9::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, CONST void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
{
   return origIDirect3DDevice9->DrawPrimitiveUP(PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
}

HRESULT proxyIDirect3DDevice9::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, CONST void *pIndexData, D3DFORMAT IndexDataFormat, CONST void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
{
   return origIDirect3DDevice9->DrawIndexedPrimitiveUP(PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
}

HRESULT proxyIDirect3DDevice9::ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9 *pDestBuffer, IDirect3DVertexDeclaration9 *pVertexDecl, DWORD Flags)
{
   return origIDirect3DDevice9->ProcessVertices(SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
}

HRESULT proxyIDirect3DDevice9::CreateVertexDeclaration(CONST D3DVERTEXELEMENT9 *pVertexElements, IDirect3DVertexDeclaration9 **ppDecl)
{
   return origIDirect3DDevice9->CreateVertexDeclaration(pVertexElements, ppDecl);
}

HRESULT proxyIDirect3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9 *pDecl)
{
   return origIDirect3DDevice9->SetVertexDeclaration(pDecl);
}

HRESULT proxyIDirect3DDevice9::GetVertexDeclaration(IDirect3DVertexDeclaration9 **ppDecl)
{
   return origIDirect3DDevice9->GetVertexDeclaration(ppDecl);
}

HRESULT proxyIDirect3DDevice9::SetFVF(DWORD FVF)
{
   return origIDirect3DDevice9->SetFVF(FVF);
}

HRESULT proxyIDirect3DDevice9::GetFVF(DWORD *pFVF)
{
   return origIDirect3DDevice9->GetFVF(pFVF);
}

HRESULT proxyIDirect3DDevice9::CreateVertexShader(CONST DWORD *pFunction, IDirect3DVertexShader9 **ppShader)
{
   return origIDirect3DDevice9->CreateVertexShader(pFunction, ppShader);
}

HRESULT proxyIDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9 *pShader)
{
   return origIDirect3DDevice9->SetVertexShader(pShader);
}

HRESULT proxyIDirect3DDevice9::GetVertexShader(IDirect3DVertexShader9 **ppShader)
{
   return origIDirect3DDevice9->GetVertexShader(ppShader);
}

HRESULT proxyIDirect3DDevice9::SetVertexShaderConstantF(UINT StartRegister, CONST float *pConstantData, UINT Vector4fCount)
{
   return origIDirect3DDevice9->SetVertexShaderConstantF(StartRegister, pConstantData, Vector4fCount);
}

HRESULT proxyIDirect3DDevice9::GetVertexShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount)
{
   return origIDirect3DDevice9->GetVertexShaderConstantF(StartRegister, pConstantData, Vector4fCount);
}

HRESULT proxyIDirect3DDevice9::SetVertexShaderConstantI(UINT StartRegister, CONST int *pConstantData, UINT Vector4iCount)
{
   return origIDirect3DDevice9->SetVertexShaderConstantI(StartRegister, pConstantData, Vector4iCount);
}

HRESULT proxyIDirect3DDevice9::GetVertexShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount)
{
   return origIDirect3DDevice9->GetVertexShaderConstantI(StartRegister, pConstantData, Vector4iCount);
}

HRESULT proxyIDirect3DDevice9::SetVertexShaderConstantB(UINT StartRegister, CONST BOOL *pConstantData, UINT  BoolCount)
{
   return origIDirect3DDevice9->SetVertexShaderConstantB(StartRegister, pConstantData, BoolCount);
}

HRESULT proxyIDirect3DDevice9::GetVertexShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount)
{
   return origIDirect3DDevice9->GetVertexShaderConstantB(StartRegister, pConstantData, BoolCount);
}

HRESULT proxyIDirect3DDevice9::SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride)
{
   return origIDirect3DDevice9->SetStreamSource(StreamNumber, pStreamData, OffsetInBytes, Stride);
}

HRESULT proxyIDirect3DDevice9::GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 **ppStreamData, UINT *OffsetInBytes, UINT *pStride)
{
   return origIDirect3DDevice9->GetStreamSource(StreamNumber, ppStreamData, OffsetInBytes, pStride);
}

HRESULT proxyIDirect3DDevice9::SetStreamSourceFreq(UINT StreamNumber, UINT Divider)
{
   return origIDirect3DDevice9->SetStreamSourceFreq(StreamNumber, Divider);
}

HRESULT proxyIDirect3DDevice9::GetStreamSourceFreq(UINT StreamNumber, UINT *Divider)
{
   return origIDirect3DDevice9->GetStreamSourceFreq(StreamNumber, Divider);
}

HRESULT proxyIDirect3DDevice9::SetIndices(IDirect3DIndexBuffer9 *pIndexData)
{
   return origIDirect3DDevice9->SetIndices(pIndexData);
}

HRESULT proxyIDirect3DDevice9::GetIndices(IDirect3DIndexBuffer9 **ppIndexData)
{
   return origIDirect3DDevice9->GetIndices(ppIndexData);
}

HRESULT proxyIDirect3DDevice9::CreatePixelShader(CONST DWORD *pFunction, IDirect3DPixelShader9 **ppShader)
{
   return origIDirect3DDevice9->CreatePixelShader(pFunction, ppShader);
}

HRESULT proxyIDirect3DDevice9::SetPixelShader(IDirect3DPixelShader9 *pShader)
{
   return origIDirect3DDevice9->SetPixelShader(pShader);
}

HRESULT proxyIDirect3DDevice9::GetPixelShader(IDirect3DPixelShader9 **ppShader)
{
   return origIDirect3DDevice9->GetPixelShader(ppShader);
}

HRESULT proxyIDirect3DDevice9::SetPixelShaderConstantF(UINT StartRegister, CONST float *pConstantData, UINT Vector4fCount)
{
   return origIDirect3DDevice9->SetPixelShaderConstantF(StartRegister, pConstantData, Vector4fCount);
}

HRESULT proxyIDirect3DDevice9::GetPixelShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount)
{
   return origIDirect3DDevice9->GetPixelShaderConstantF(StartRegister, pConstantData, Vector4fCount);
}

HRESULT proxyIDirect3DDevice9::SetPixelShaderConstantI(UINT StartRegister, CONST int *pConstantData, UINT Vector4iCount)
{
   return origIDirect3DDevice9->SetPixelShaderConstantI(StartRegister, pConstantData, Vector4iCount);
}

HRESULT proxyIDirect3DDevice9::GetPixelShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount)
{
   return origIDirect3DDevice9->GetPixelShaderConstantI(StartRegister, pConstantData, Vector4iCount);
}

HRESULT proxyIDirect3DDevice9::SetPixelShaderConstantB(UINT StartRegister, CONST BOOL *pConstantData, UINT  BoolCount)
{
   return origIDirect3DDevice9->SetPixelShaderConstantB(StartRegister, pConstantData, BoolCount);
}

HRESULT proxyIDirect3DDevice9::GetPixelShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount)
{
   return origIDirect3DDevice9->GetPixelShaderConstantB(StartRegister, pConstantData, BoolCount);
}

HRESULT proxyIDirect3DDevice9::DrawRectPatch(UINT Handle, CONST float *pNumSegs, CONST D3DRECTPATCH_INFO *pRectPatchInfo)
{
   return origIDirect3DDevice9->DrawRectPatch(Handle, pNumSegs, pRectPatchInfo);
}

HRESULT proxyIDirect3DDevice9::DrawTriPatch(UINT Handle, CONST float *pNumSegs, CONST D3DTRIPATCH_INFO *pTriPatchInfo)
{
   return origIDirect3DDevice9->DrawTriPatch(Handle, pNumSegs, pTriPatchInfo);
}

HRESULT proxyIDirect3DDevice9::DeletePatch(UINT Handle)
{
   return origIDirect3DDevice9->DeletePatch(Handle);
}

HRESULT proxyIDirect3DDevice9::CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery)
{
   return origIDirect3DDevice9->CreateQuery(Type, ppQuery);
}

