#include <stdlib.h>
#include <mmsystem.h>
#include <tchar.h>
#include <d3dx9.h>
#include <memory.h>
#include <math.h>
#include <d3d9types.h>
#include <WINNLS32.H>

/* Ruby1.8の古いほう対応 */
#ifndef RSTRING_PTR
#  define RSTRING_PTR(s) (RSTRING(s)->ptr)
#endif
#ifndef RSTRING_LEN
#  define RSTRING_LEN(s) (RSTRING(s)->len)
#endif

#ifndef RARRAY_PTR
#  define RARRAY_PTR(s) (RARRAY(s)->ptr)
#endif
#ifndef RARRAY_LEN
#  define RARRAY_LEN(s) (RARRAY(s)->len)
#endif

#define RELEASE( x )  if( x ) { if(FAILED(x->lpVtbl->Release( x )))rb_raise(eDXRubyError,"release error"); x = NULL; }
#define DXRUBY_CHECK_TYPE( a, b ) \
        {if( TYPE( b ) != T_DATA || RDATA( b )->dfree != (RUBY_DATA_FUNC)a##_release )\
        rb_raise(rb_eTypeError, "wrong argument type %s (expected DXRuby::"#a")", rb_obj_classname( b ));}
#define DXRUBY_CHECK_IMAGE( a ) \
        {if( TYPE( a ) != T_DATA || (RDATA( a )->dfree != (RUBY_DATA_FUNC)Image_release && RDATA( a )->dfree != (RUBY_DATA_FUNC)RenderTarget_release) )\
        rb_raise(rb_eTypeError, "wrong argument type %s (expected DXRuby::Image or DXRuby::RenderTarget)", rb_obj_classname( a ));}
#define DXRUBY_GET_STRUCT( c, v ) ((struct DXRuby##c *)DATA_PTR( v ))
#define DXRUBY_CHECK_DISPOSE( a, b ) {if( a->b == NULL ) { rb_raise( eDXRubyError, "disposed object" );}}
#define NUM2FLOAT( x ) ((float)( FIXNUM_P(x) ? FIX2INT(x) : NUM2DBL(x) ))

#define FORMAT_JPEG D3DXIFF_JPG
#define FORMAT_JPG  D3DXIFF_JPG
#define FORMAT_PNG  D3DXIFF_PNG
#define FORMAT_BMP  D3DXIFF_BMP
#define FORMAT_DDS  D3DXIFF_DDS

struct DXRubyWindowInfo {
    int x;              /* ｘ座標 */
    int y;              /* ｙ座標 */
    int width;          /* 幅     */
    int height;         /* 高さ   */
    int windowed;       /* ウィンドウモード時にQtrue */
    int created;        /* ウィンドウを作成したらQtrue */
    float scale;        /* ウィンドウのサイズ倍率 */
    int RefreshRate;    /* リフレッシュレート */
    int enablemouse;    /* マウスを表示するかどうか */
    int mousewheelpos;  /* マウスホイールの位置 */
    int fps;            /* fps */
    int fpscheck;       /* 現在のfps */
    int frameskip;      /* コマ落ち制御フラグ */
    HANDLE hIcon;       /* ウィンドウアイコンハンドル */
    int userloop;       /* 自前ループされてたら1、Window.loopされたら2*/
    int requestclose;   /* ウィンドウが閉じられたら1 */
    VALUE render_target; /* スクリーンレンダーターゲット */
    int active;         /* ゲーム調整用 */
};

/* ピクチャ配列 */
static struct DXRubyPictureList {
    float z;                        /* ピクチャのZ座標 */
    struct DXRubyPicture *picture;    /* ピクチャ構造体へのポインタ */
};


/* RenderTargetオブジェクトの中身 */
struct DXRubyRenderTarget {
    struct DXRubyTexture *texture;
    float x;     /* x始点位置      */
    float y;     /* y始点位置      */
    float width; /* イメージの幅   */
    float height;/* イメージの高さ ここまでImageと共通*/
    IDirect3DSurface9 *surface;

    int PictureCount;                  /* ピクチャの登録数 */
    int PictureAllocateCount;          /* ピクチャ登録のメモリ確保数 */
    int PictureSize;                   /* ピクチャデータの使用済みサイズ */
    int PictureAllocateSize;           /* ピクチャデータのメモリ確保サイズ */
    char *PictureStruct;

    struct DXRubyPictureList *PictureList;

    int minfilter;      /* 縮小フィルタ */
    int magfilter;      /* 拡大フィルタ */

    int a;              /* 背景クリア色 α成分 */
    int r;              /* 背景クリア色 赤成分 */
    int g;              /* 背景クリア色 緑成分 */
    int b;              /* 背景クリア色 青成分 */

    VALUE array; /* drawFontExによる自動生成Imageの置き場所 */

    int PictureDecideCount;            /* ピクチャの登録確定数 */
    int PictureDecideSize;             /* ピクチャデータの登録確定サイズ */

};

struct DXRubyPicture_draw {
    void (*func)(void*);
    VALUE value;
    unsigned char blendflag; /* 半透明(000)、加算合成1(100)、加算合成2(101)、減算合成1(110)、減算合成2(111)のフラグ */
    unsigned char alpha;     /* アルファ（透明）値 */
    char reserve1;           /* 予約3 */
    char reserve2;           /* 予約4 */
    int x;
    int y;
    float z;
};

struct DXRubyPicture_drawEx {
    void (*func)(void*);
    VALUE value;
    unsigned char blendflag; /* 半透明(000)、加算合成1(100)、加算合成2(101)、減算合成1(110)、減算合成2(111)のフラグ */
    unsigned char alpha;     /* アルファ（透明）値 */
    char reserve1;           /* 予約3 */
    char reserve2;           /* 予約4 */
    int x;
    int y;
    float z;
    float scalex;
    float scaley;
    float centerx;
    float centery;
    float angle;
};

struct DXRubyPicture_drawFont {
    void (*func)(void*);
    VALUE value;
    unsigned char blendflag; /* 半透明(000)、加算合成1(100)、加算合成2(101)、減算合成1(110)、減算合成2(111)のフラグ */
    unsigned char alpha;     /* アルファ（透明）値 */
    char reserve1;           /* 予約3 */
    char reserve2;           /* 予約4 */
    int x;
    int y;
    int z;
    float scalex;
    float scaley;
    float centerx;
    float centery;
    float angle;
    int color;                  /* フォントの色 */
    char str[0];                /* 文字列オブジェクト */
};

struct DXRubyPicture_drawMorph {
    void (*func)(void*);
    VALUE value;
    unsigned char blendflag; /* 半透明(000)、加算合成1(100)、加算合成2(101)、減算合成1(110)、減算合成2(111)のフラグ */
    unsigned char alpha;     /* アルファ（透明）値 */
    char reserve1;           /* 予約3 */
    char reserve2;           /* 予約4 */
    float x1;
    float y1;
    float x2;
    float y2;
    float x3;
    float y3;
    float x4;
    float y4;
    float z;
    int dividex;
    int dividey;
    char colorflag, r, g, b;
};

struct DXRubyPicture_drawTile {
    void (*func)(void*);
    VALUE value;
    unsigned char blendflag; /* 半透明(000)、加算合成1(100)、加算合成2(101)、減算合成1(110)、減算合成2(111)のフラグ */
    unsigned char alpha;     /* アルファ（透明）値 */
    char reserve1;           /* 予約3 */
    char reserve2;           /* 予約4 */
    int basex;
    int basey;
    int sizex;
    int sizey;
    int startx;
    int starty;
    float z;
};

/* ShaderCore */
struct DXRubyShaderCore {
    LPD3DXEFFECT pD3DXEffect;
    VALUE vtype; /* 引数名と型のセット */
};

/* Shader */
struct DXRubyShader {
    VALUE vcore;
    VALUE vparam; /* 引数名と中身のセット*/
    VALUE vname;
};


#ifdef DXRUBY_EXTERN
extern HINSTANCE g_hInstance; /* アプリケーションインスタンス   */
extern HANDLE    g_hWnd;      /* ウィンドウハンドル             */
extern int g_iRefAll;        /* インターフェースの参照カウント */

extern LPDIRECT3D9           g_pD3D;       /* Direct3Dインターフェイス       */
extern LPDIRECT3DDEVICE9     g_pD3DDevice; /* Direct3DDeviceインターフェイス */
extern D3DPRESENT_PARAMETERS g_D3DPP;      /* D3DDeviceの設定                */

extern struct DXRubyWindowInfo g_WindowInfo;
extern char sys_encode[256];

extern VALUE mDXRuby;        /* DXRubyモジュール     */
extern VALUE eDXRubyError;   /* 例外                 */

/* シンボル */
extern VALUE symbol_blend;
extern VALUE symbol_angle;
extern VALUE symbol_alpha;
extern VALUE symbol_scalex;
extern VALUE symbol_scaley;
extern VALUE symbol_centerx;
extern VALUE symbol_centery;
extern VALUE symbol_z;
extern VALUE symbol_color;
extern VALUE symbol_add;
extern VALUE symbol_add2;
extern VALUE symbol_sub;
extern VALUE symbol_sub2;
extern VALUE symbol_none;
extern VALUE symbol_dividex;
extern VALUE symbol_dividey;
extern VALUE symbol_edge;
extern VALUE symbol_edge_color;
extern VALUE symbol_edge_width;
extern VALUE symbol_edge_level;
extern VALUE symbol_shadow;
extern VALUE symbol_shadow_color;
extern VALUE symbol_shadow_x;
extern VALUE symbol_shadow_y;
extern VALUE symbol_shadow_edge;
extern VALUE symbol_shader;
extern VALUE symbol_int;
extern VALUE symbol_float;
extern VALUE symbol_texture;
extern VALUE symbol_technique;
extern VALUE symbol_discard;

#endif

void *RenderTarget_AllocPictureList( struct DXRubyRenderTarget *rt, int size );
void RenderTarget_draw_func( struct DXRubyPicture_draw *picture );
void RenderTarget_drawShader_func( struct DXRubyPicture_draw *picture );
void RenderTarget_drawEx_func( struct DXRubyPicture_drawEx *picture );
void RenderTarget_release( struct DXRubyRenderTarget* rt );
void ShaderCore_release( struct DXRubyShaderCore *core );
void Shader_release( struct DXRubyShader *shader );

VALUE hash_lookup(VALUE hash, VALUE key);

