1 module grape.image;
2 
3 import derelict.sdl2.sdl;
4 import derelict.sdl2.image;
5 
6 import std.stdio;
7 import std..string;
8 import std.file;
9 import std.exception : enforce;
10 
11 import grape.buffer;
12 import grape.surface;
13 import grape.renderer;
14 import grape.shader;
15 import grape.window;
16 
17 /**
18  * 画像を管理するクラス
19  */
20 class Image {
21   public:
22     this() {
23       if (!_initialized) {
24         _initialized = true;
25         DerelictSDL2Image.load();
26         int flags = IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF;
27         if (IMG_Init(flags) == -1)
28           throw new Exception("IMG_Init() failed");
29       }
30 
31       _texture = new Texture;
32       _surf = new Surface;
33     }
34 
35     /** Imageの初期化
36      *
37      * 引数に画像のファイル名を渡すと読み込みます。
38      * file: 画像のファイル名
39      */
40     this(in string file) {
41       this();
42       load(file);
43     }
44 
45     static ~this() {
46       debug(tor) writeln("Image dtor");
47       if (_initialized)
48         IMG_Quit();
49     }
50 
51     /**
52      * 画像の読み込み
53      *
54      * file:   画像のファイル名
55      */
56     void load(in string file) {
57       enforce(exists(file), file ~ " does not exist");
58       _surf.create({ return IMG_Load(toStringz(file)); });
59       enforce(_surf !is null, "IMG_Load() failed");
60     }
61 
62     /**
63      * 画像テクスチャの作成
64      *
65      * 基本的にユーザーは使いません。
66      */
67     void create_texture() {
68       _texture.create(_surf);
69     }
70 
71     @property {
72       /**
73        * 画像テクスチャを返す
74        *
75        * 基本的にユーザーは使いません。
76        */
77       Texture texture() {
78         return _texture;
79       }
80     }
81 
82   private:
83     Texture _texture;
84     Surface _surf;
85     static bool _initialized = false;
86 }
87 
88 // Cameraの影響をうけない
89 /**
90  * 画像を描画するクラス
91  *
92  * TODO:
93  * Camera使うか
94  */
95 class ImageRenderer : Old_Renderer {
96   public:
97     /**
98      * 初期化
99      *
100      * 引数に描画する画像を渡します。
101      * 渡さなかった場合、描画する前に必ずset_image関数を呼ぶ必要があります。
102      * image: 描画する画像
103      */
104     this(Image image) {
105       this();
106       set_image(image);
107     }
108 
109     this() {
110       string[] locNames = [ "pos", "texCoord" ];
111       int[] strides = [ 3, 2 ];
112 
113       // TODO Weird name
114       mixin FontShaderSource;
115       init(FontShader, locNames, strides, DrawMode.Triangles);
116 
117       _program.use();
118       init_vbo();
119       init_ibo();
120       set_uniform("tex", 0, "1i");
121     }
122 
123     /**
124      * 描画する画像のセット
125      *
126      * image: 描画する画像
127      */
128     void set_image(Image image) {
129       _image = image;
130     }
131 
132     override void render() {}
133 
134     /**
135      * 描画
136      *
137      * x:      描画する左上のx座標
138      * y:      描画する左上のy座標
139      * scale:  倍率(未実装なので基本1.0を指定)
140      *
141      * TODO:
142      * Rendererのrenderを使用してない
143      * scale is not implemented yet
144      */
145     void render(in float x, in float y, in float scale) {
146       _program.use();
147 
148       _image.create_texture();
149 
150       float[12] pos = set_pos(x, y);
151       set_vbo(pos, _texCoord);
152       _image.texture.texture_scope({ _ibo.draw(_drawMode); });
153     }
154 
155   private:
156     void init_vbo() {
157       _texCoord = [ 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 ];        
158     }
159 
160     void init_ibo() {
161       int[] index = [ 0, 1, 2, 0, 2, 3 ];
162       _ibo = new IBO;
163       _ibo.create(index);
164     }
165     
166     float[12] set_pos(in float x, in float y) {
167       auto startX = x / (WINDOW_WIDTH/2.0);
168       auto startY = y / (WINDOW_HEIGHT/2.0);
169       auto w = _image.texture.w / (WINDOW_WIDTH/2.0);
170       auto h = _image.texture.h / (WINDOW_HEIGHT/2.0);
171 
172       return [ startX, startY, 0.0,
173                startX+w, startY, 0.0,
174                startX+w, startY-h, 0.0,
175                startX, startY-h, 0.0 ];
176     }
177 
178     Image _image;
179     float[] _texCoord;
180 }
181