rgss 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.clang-format +6 -0
- data/.gitignore +167 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/Rakefile +9 -0
- data/ext/rgss/cglm-v0.7.9.tar.gz +0 -0
- data/ext/rgss/color.c +599 -0
- data/ext/rgss/entity.c +373 -0
- data/ext/rgss/extconf.rb +53 -0
- data/ext/rgss/font.c +135 -0
- data/ext/rgss/game.c +469 -0
- data/ext/rgss/game.h +99 -0
- data/ext/rgss/gl.c +3217 -0
- data/ext/rgss/glad.c +1140 -0
- data/ext/rgss/glad.h +2129 -0
- data/ext/rgss/glfw.c +1453 -0
- data/ext/rgss/graphics.c +324 -0
- data/ext/rgss/image.c +274 -0
- data/ext/rgss/input.c +745 -0
- data/ext/rgss/khrplatform.h +290 -0
- data/ext/rgss/mat4.c +279 -0
- data/ext/rgss/pax_global_header +1 -0
- data/ext/rgss/point.c +253 -0
- data/ext/rgss/rect.c +449 -0
- data/ext/rgss/rgss.c +56 -0
- data/ext/rgss/rgss.h +241 -0
- data/ext/rgss/stb_image.h +7762 -0
- data/ext/rgss/stb_image_write.h +1690 -0
- data/ext/rgss/stb_rect_pack.h +628 -0
- data/ext/rgss/stb_truetype.h +5011 -0
- data/ext/rgss/utf8.h +1652 -0
- data/ext/rgss/uthash.h +1133 -0
- data/ext/rgss/vec.c +114 -0
- data/ext/rgss/vec.h +192 -0
- data/ext/rgss/vec2.c +489 -0
- data/ext/rgss/vec3.c +751 -0
- data/ext/rgss/vec4.c +681 -0
- data/lib/rgss.rb +140 -0
- data/lib/rgss/batch.rb +57 -0
- data/lib/rgss/blend.rb +47 -0
- data/lib/rgss/game_object.rb +28 -0
- data/lib/rgss/plane.rb +95 -0
- data/lib/rgss/renderable.rb +158 -0
- data/lib/rgss/rgss.so +0 -0
- data/lib/rgss/shader.rb +94 -0
- data/lib/rgss/shaders/sprite-frag.glsl +40 -0
- data/lib/rgss/shaders/sprite-vert.glsl +17 -0
- data/lib/rgss/sprite.rb +139 -0
- data/lib/rgss/stubs/color.rb +318 -0
- data/lib/rgss/stubs/gl.rb +1999 -0
- data/lib/rgss/stubs/glfw.rb +626 -0
- data/lib/rgss/stubs/rect.rb +324 -0
- data/lib/rgss/stubs/rpg.rb +267 -0
- data/lib/rgss/stubs/tone.rb +65 -0
- data/lib/rgss/texture.rb +132 -0
- data/lib/rgss/tilemap.rb +116 -0
- data/lib/rgss/version.rb +3 -0
- data/lib/rgss/viewport.rb +67 -0
- data/rgss.gemspec +44 -0
- data/test.png +0 -0
- metadata +178 -0
data/ext/rgss/graphics.c
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
#include "game.h"
|
2
|
+
#include "glad.h"
|
3
|
+
|
4
|
+
VALUE rb_mGraphics;
|
5
|
+
ID render_id;
|
6
|
+
|
7
|
+
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
|
8
|
+
|
9
|
+
#define GL_DEBUG_SOURCE_API 0x8246
|
10
|
+
#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
|
11
|
+
#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
|
12
|
+
#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
|
13
|
+
#define GL_DEBUG_SOURCE_APPLICATION 0x824A
|
14
|
+
#define GL_DEBUG_SOURCE_OTHER 0x824B
|
15
|
+
|
16
|
+
#define GL_DEBUG_TYPE_ERROR 0x824C
|
17
|
+
#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
|
18
|
+
#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
|
19
|
+
#define GL_DEBUG_TYPE_PORTABILITY 0x824F
|
20
|
+
#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
|
21
|
+
#define GL_DEBUG_TYPE_MARKER 0x8268
|
22
|
+
#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
|
23
|
+
#define GL_DEBUG_TYPE_POP_GROUP 0x826A
|
24
|
+
#define GL_DEBUG_TYPE_OTHER 0x8251
|
25
|
+
|
26
|
+
#define GL_DEBUG_SEVERITY_LOW 0x9148
|
27
|
+
#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
|
28
|
+
#define GL_DEBUG_SEVERITY_HIGH 0x9146
|
29
|
+
#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
|
30
|
+
|
31
|
+
typedef void (*GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *msg,
|
32
|
+
const void *data);
|
33
|
+
typedef void (APIENTRYP PFGLDEBUGMESSAGECALLBACK)(GLDEBUGPROC callback, const void *userParam);
|
34
|
+
|
35
|
+
|
36
|
+
void RGSS_Graphics_GLCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *msg,
|
37
|
+
const void *data)
|
38
|
+
{
|
39
|
+
if(id == 131169 || id == 131185 || id == 131218 || id == 131204)
|
40
|
+
return;
|
41
|
+
|
42
|
+
printf("%s\n", msg);
|
43
|
+
}
|
44
|
+
|
45
|
+
#define RGSS_VIEWPORT(rect) \
|
46
|
+
glViewport(rect.x, rect.y, rect.width, rect.height);\
|
47
|
+
glScissor(rect.x, rect.y, rect.width, rect.height)
|
48
|
+
|
49
|
+
static void RGSS_Graphics_Reshape(int width, int height)
|
50
|
+
{
|
51
|
+
// Calculate ratios between window and internal resolution
|
52
|
+
RGSS_GAME.graphics.ratio[0] = (float)width / RGSS_GAME.graphics.resolution[0];
|
53
|
+
RGSS_GAME.graphics.ratio[1] = (float)height / RGSS_GAME.graphics.resolution[1];
|
54
|
+
float ratio = RGSS_MIN(RGSS_GAME.graphics.ratio[0], RGSS_GAME.graphics.ratio[1]);
|
55
|
+
|
56
|
+
// Calculate letterbox/pillar rendering coordinates as required
|
57
|
+
int x, y, w, h;
|
58
|
+
w = (int)roundf(RGSS_GAME.graphics.resolution[0] * ratio);
|
59
|
+
h = (int)roundf(RGSS_GAME.graphics.resolution[1] * ratio);
|
60
|
+
x = (int)roundf(((float)width - RGSS_GAME.graphics.resolution[0] * ratio) * 0.5f);
|
61
|
+
y = (int)roundf(((float)height - RGSS_GAME.graphics.resolution[1] * ratio) * 0.5f);
|
62
|
+
|
63
|
+
RGSS_GAME.graphics.viewport = (RGSS_Rect){x, y, w, h};
|
64
|
+
glViewport(x, y, w, h);
|
65
|
+
|
66
|
+
// Ensure the clipping area is also cleared
|
67
|
+
glDisable(GL_SCISSOR_TEST);
|
68
|
+
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
69
|
+
glClear(GL_COLOR_BUFFER_BIT);
|
70
|
+
glEnable(GL_SCISSOR_TEST);
|
71
|
+
glScissor(x, y, w, h);
|
72
|
+
glClearColor(RGSS_GAME.graphics.color[0], RGSS_GAME.graphics.color[1], RGSS_GAME.graphics.color[2],
|
73
|
+
RGSS_GAME.graphics.color[3]);
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE RGSS_Graphics_GetFPS(VALUE graphics)
|
77
|
+
{
|
78
|
+
return DBL2NUM(RGSS_GAME.window ? RGSS_GAME.time.fps : 0.0);
|
79
|
+
}
|
80
|
+
|
81
|
+
static VALUE RGSS_Graphics_GetBackColor(VALUE graphics)
|
82
|
+
{
|
83
|
+
RGSS_ASSERT_GAME;
|
84
|
+
float *color = RGSS_VEC4_NEW;
|
85
|
+
memcpy(color, RGSS_GAME.graphics.color, RGSS_VEC4_SIZE);
|
86
|
+
return Data_Wrap_Struct(rb_cColor, NULL, free, color);
|
87
|
+
}
|
88
|
+
|
89
|
+
static VALUE RGSS_Graphics_SetBackColor(VALUE graphics, VALUE color)
|
90
|
+
{
|
91
|
+
RGSS_ASSERT_GAME;
|
92
|
+
if (RTEST(color))
|
93
|
+
{
|
94
|
+
float *vec = DATA_PTR(color);
|
95
|
+
memcpy(RGSS_GAME.graphics.color, vec, RGSS_VEC4_SIZE);
|
96
|
+
}
|
97
|
+
else
|
98
|
+
{
|
99
|
+
memset(RGSS_GAME.graphics.color, 0, RGSS_VEC4_SIZE);
|
100
|
+
}
|
101
|
+
glClearColor(RGSS_GAME.graphics.color[0], RGSS_GAME.graphics.color[1], RGSS_GAME.graphics.color[2],
|
102
|
+
RGSS_GAME.graphics.color[3]);
|
103
|
+
return color;
|
104
|
+
}
|
105
|
+
|
106
|
+
static VALUE RGSS_Graphics_Clear(VALUE graphics)
|
107
|
+
{
|
108
|
+
RGSS_ASSERT_GAME;
|
109
|
+
glClear(GL_COLOR_BUFFER_BIT);
|
110
|
+
return Qnil;
|
111
|
+
}
|
112
|
+
|
113
|
+
static VALUE RGSS_Graphics_Capture(VALUE graphics)
|
114
|
+
{
|
115
|
+
RGSS_ASSERT_GAME;
|
116
|
+
|
117
|
+
// glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
|
118
|
+
// TODO: Set projection/viewport to graphics size, render, read framebuffer, return image
|
119
|
+
|
120
|
+
GLFWimage *image = xmalloc(sizeof(GLFWimage));
|
121
|
+
image->width = (int)RGSS_GAME.graphics.resolution[0];
|
122
|
+
image->height = (int)RGSS_GAME.graphics.resolution[1];
|
123
|
+
image->pixels = xmalloc(sizeof(int) * image->width * image->height);
|
124
|
+
|
125
|
+
glViewport(0, 0, image->width, image->height);
|
126
|
+
rb_funcall(graphics, render_id, 1, DBL2NUM(0.0));
|
127
|
+
|
128
|
+
glReadPixels(0, 0, image->width, image->height, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
|
129
|
+
RGSS_VIEWPORT(RGSS_GAME.graphics.viewport);
|
130
|
+
|
131
|
+
return Data_Wrap_Struct(rb_cImage, NULL, RGSS_Image_Free, image);
|
132
|
+
}
|
133
|
+
|
134
|
+
static VALUE RGSS_Graphics_GetResolution(VALUE graphics)
|
135
|
+
{
|
136
|
+
if (RGSS_GAME.window == NULL)
|
137
|
+
return RGSS_Size_New(0, 0);
|
138
|
+
|
139
|
+
return RGSS_Size_New((int)RGSS_GAME.graphics.resolution[0], (int)RGSS_GAME.graphics.resolution[1]);
|
140
|
+
}
|
141
|
+
|
142
|
+
static VALUE RGSS_Graphics_SetResolution(VALUE graphics, VALUE size)
|
143
|
+
{
|
144
|
+
RGSS_ASSERT_GAME;
|
145
|
+
RGSS_Size *ivec = DATA_PTR(size);
|
146
|
+
|
147
|
+
if (ivec->width < 0)
|
148
|
+
rb_raise(rb_eArgError, "width must be greater than 0 (given %d)", ivec->width);
|
149
|
+
if (ivec->height < 0)
|
150
|
+
rb_raise(rb_eArgError, "height must be greater than 0 (given %d)", ivec->height);
|
151
|
+
|
152
|
+
RGSS_GAME.graphics.resolution[0] = (float)ivec->width;
|
153
|
+
RGSS_GAME.graphics.resolution[1] = (float)ivec->height;
|
154
|
+
glm_ortho(0.0f, (float)ivec->width, (float)ivec->height, 0.0f, -1.0f, 1.0f, RGSS_GAME.graphics.projection);
|
155
|
+
|
156
|
+
GLvoid *p = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
|
157
|
+
memcpy(p, RGSS_GAME.graphics.projection, RGSS_MAT4_SIZE);
|
158
|
+
glUnmapBuffer(GL_UNIFORM_BUFFER);
|
159
|
+
|
160
|
+
int w, h;
|
161
|
+
glfwGetFramebufferSize(RGSS_GAME.window, &w, &h);
|
162
|
+
RGSS_Graphics_Reshape(w, h);
|
163
|
+
}
|
164
|
+
|
165
|
+
static void RGSS_Graphics_ResizeCallback(GLFWwindow *window, int width, int height)
|
166
|
+
{
|
167
|
+
RGSS_Graphics_Reshape(width, height);
|
168
|
+
// TODO: Call block if set
|
169
|
+
}
|
170
|
+
|
171
|
+
static VALUE RGSS_Graphics_Restore(VALUE graphics)
|
172
|
+
{
|
173
|
+
if (RGSS_GAME.window == NULL)
|
174
|
+
return Qnil;
|
175
|
+
|
176
|
+
RGSS_VIEWPORT(RGSS_GAME.graphics.viewport);
|
177
|
+
glClearColor(RGSS_GAME.graphics.color[0], RGSS_GAME.graphics.color[1], RGSS_GAME.graphics.color[2],
|
178
|
+
RGSS_GAME.graphics.color[3]);
|
179
|
+
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
|
180
|
+
return Qnil;
|
181
|
+
}
|
182
|
+
|
183
|
+
void RGSS_Graphics_Init(GLFWwindow *window, int width, int height, int vsync)
|
184
|
+
{
|
185
|
+
glfwSwapInterval(vsync);
|
186
|
+
RGSS_GAME.graphics.projection = RGSS_MAT4_NEW;
|
187
|
+
RGSS_GAME.graphics.resolution[0] = (float)width;
|
188
|
+
RGSS_GAME.graphics.resolution[1] = (float)height;
|
189
|
+
|
190
|
+
glm_vec2_one(RGSS_GAME.graphics.ratio);
|
191
|
+
RGSS_GAME.graphics.viewport = (RGSS_Rect){0, 0, width, height};
|
192
|
+
glm_ortho(0.0f, RGSS_GAME.graphics.resolution[0], RGSS_GAME.graphics.resolution[1], 0.0f, -1.0f, 1.0f,
|
193
|
+
RGSS_GAME.graphics.projection);
|
194
|
+
|
195
|
+
glGenBuffers(1, &RGSS_GAME.graphics.ubo);
|
196
|
+
glBindBuffer(GL_UNIFORM_BUFFER, RGSS_GAME.graphics.ubo);
|
197
|
+
glBufferData(GL_UNIFORM_BUFFER, RGSS_MAT4_SIZE, RGSS_GAME.graphics.projection, GL_DYNAMIC_DRAW);
|
198
|
+
glBindBufferBase(GL_UNIFORM_BUFFER, 0, RGSS_GAME.graphics.ubo);
|
199
|
+
glBindBuffer(GL_UNIFORM_BUFFER, GL_NONE);
|
200
|
+
|
201
|
+
glfwSetFramebufferSizeCallback(window, RGSS_Graphics_ResizeCallback);
|
202
|
+
|
203
|
+
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
204
|
+
glEnable(GL_SCISSOR_TEST);
|
205
|
+
glEnable(GL_BLEND);
|
206
|
+
|
207
|
+
if (RGSS_GAME.debug)
|
208
|
+
{
|
209
|
+
void *address;
|
210
|
+
address = glfwGetProcAddress("glDebugMessageCallback");
|
211
|
+
if (address)
|
212
|
+
{
|
213
|
+
PFGLDEBUGMESSAGECALLBACK proc = (PFGLDEBUGMESSAGECALLBACK) address;
|
214
|
+
proc(RGSS_Graphics_GLCallback, NULL);
|
215
|
+
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
void RGSS_Graphics_Deinit(GLFWwindow *window)
|
221
|
+
{
|
222
|
+
glfwSetFramebufferSizeCallback(window, NULL);
|
223
|
+
|
224
|
+
if (RGSS_GAME.graphics.projection)
|
225
|
+
free(RGSS_GAME.graphics.projection);
|
226
|
+
glDeleteBuffers(1, &RGSS_GAME.graphics.ubo);
|
227
|
+
}
|
228
|
+
|
229
|
+
void RGSS_Graphics_Render(double alpha)
|
230
|
+
{
|
231
|
+
glClear(GL_COLOR_BUFFER_BIT);
|
232
|
+
rb_funcall(rb_mGraphics, render_id, 1, DBL2NUM(alpha));
|
233
|
+
|
234
|
+
RGSS_GAME.time.fps_count++;
|
235
|
+
RGSS_GAME.time.total_frames++;
|
236
|
+
glfwSwapBuffers(RGSS_GAME.window);
|
237
|
+
}
|
238
|
+
|
239
|
+
static VALUE RGSS_Graphics_GetFrameCount(VALUE graphics)
|
240
|
+
{
|
241
|
+
return ULL2NUM(RGSS_GAME.window ? RGSS_GAME.time.total_frames : 0);
|
242
|
+
}
|
243
|
+
|
244
|
+
static VALUE RGSS_Graphics_GetProjection(VALUE graphics)
|
245
|
+
{
|
246
|
+
RGSS_ASSERT_GAME;
|
247
|
+
return Data_Wrap_Struct(rb_cMat4, NULL, RUBY_NEVER_FREE, RGSS_GAME.graphics.projection);
|
248
|
+
}
|
249
|
+
|
250
|
+
// static VALUE RGSS_Graphics_SetProjection(VALUE graphics, VALUE projection)
|
251
|
+
// {
|
252
|
+
// RGSS_ASSERT_GAME;
|
253
|
+
// if (RTEST(projection))
|
254
|
+
// {
|
255
|
+
// vec4 *mat4 = DATA_PTR(projection);
|
256
|
+
// glm_mat4_copy(mat4, RGSS_GAME.graphics.projection);
|
257
|
+
// }
|
258
|
+
// else
|
259
|
+
// {
|
260
|
+
// glm_mat4_identity(RGSS_GAME.graphics.projection);
|
261
|
+
// }
|
262
|
+
// return projection;
|
263
|
+
// }
|
264
|
+
|
265
|
+
static VALUE RGSS_Graphics_Project(int argc, VALUE *argv, VALUE graphics)
|
266
|
+
{
|
267
|
+
rb_need_block();
|
268
|
+
|
269
|
+
VALUE x, y, w, h;
|
270
|
+
rb_scan_args(argc, argv, "13", &x, &y, &w, &h);
|
271
|
+
glBindBuffer(GL_UNIFORM_BUFFER, RGSS_GAME.graphics.ubo);
|
272
|
+
|
273
|
+
if (argc == 1)
|
274
|
+
{
|
275
|
+
glBufferSubData(GL_UNIFORM_BUFFER, 0, RGSS_MAT4_SIZE, DATA_PTR(x));
|
276
|
+
}
|
277
|
+
else if (argc == 4)
|
278
|
+
{
|
279
|
+
mat4 mat;
|
280
|
+
glm_ortho(NUM2FLT(x), NUM2FLT(x + w), NUM2FLT(y), NUM2FLT(y + h), -1.0f, 1.0f, mat);
|
281
|
+
glBufferSubData(GL_UNIFORM_BUFFER, 0, RGSS_MAT4_SIZE, mat);
|
282
|
+
}
|
283
|
+
else
|
284
|
+
{
|
285
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1 or 4)", argc);
|
286
|
+
}
|
287
|
+
glBindBuffer(GL_UNIFORM_BUFFER, GL_NONE);
|
288
|
+
|
289
|
+
rb_yield(Qundef);
|
290
|
+
|
291
|
+
glBindBuffer(GL_UNIFORM_BUFFER, RGSS_GAME.graphics.ubo);
|
292
|
+
glBufferSubData(GL_UNIFORM_BUFFER, 0, RGSS_MAT4_SIZE, RGSS_GAME.graphics.projection);
|
293
|
+
glBindBuffer(GL_UNIFORM_BUFFER, GL_NONE);
|
294
|
+
return Qnil;
|
295
|
+
}
|
296
|
+
|
297
|
+
static VALUE RGSS_Graphics_GetUniformBlock(VALUE graphics)
|
298
|
+
{
|
299
|
+
RGSS_ASSERT_GAME;
|
300
|
+
return UINT2NUM(RGSS_GAME.graphics.ubo);
|
301
|
+
}
|
302
|
+
|
303
|
+
void RGSS_Init_Graphics(VALUE parent)
|
304
|
+
{
|
305
|
+
rb_mGraphics = rb_define_module_under(parent, "Graphics");
|
306
|
+
rb_define_singleton_method0(rb_mGraphics, "frame_rate", RGSS_Graphics_GetFPS, 0);
|
307
|
+
rb_define_singleton_method0(rb_mGraphics, "frame_count", RGSS_Graphics_GetFrameCount, 0);
|
308
|
+
rb_define_singleton_method0(rb_mGraphics, "back_color", RGSS_Graphics_GetBackColor, 0);
|
309
|
+
rb_define_singleton_method1(rb_mGraphics, "back_color=", RGSS_Graphics_SetBackColor, 1);
|
310
|
+
rb_define_singleton_method0(rb_mGraphics, "clear", RGSS_Graphics_Clear, 0);
|
311
|
+
rb_define_singleton_method0(rb_mGraphics, "restore", RGSS_Graphics_Restore, 0);
|
312
|
+
rb_define_singleton_method0(rb_mGraphics, "resolution", RGSS_Graphics_GetResolution, 0);
|
313
|
+
rb_define_singleton_method1(rb_mGraphics, "resolution=", RGSS_Graphics_SetResolution, 1);
|
314
|
+
|
315
|
+
rb_define_singleton_method0(rb_mGraphics, "projection", RGSS_Graphics_GetProjection, 0);
|
316
|
+
rb_define_singleton_method0(rb_mGraphics, "ubo", RGSS_Graphics_GetUniformBlock, 0);
|
317
|
+
rb_define_singleton_methodm1(rb_mGraphics, "project", RGSS_Graphics_Project, -1);
|
318
|
+
// rb_define_singleton_method1(rb_mGraphics, "projection=", RGSS_Graphics_SetProjection, 1);
|
319
|
+
|
320
|
+
VALUE singleton = rb_singleton_class(rb_mGraphics);
|
321
|
+
rb_define_alias(singleton, "fps", "frame_rate");
|
322
|
+
|
323
|
+
render_id = rb_intern("render");
|
324
|
+
}
|
data/ext/rgss/image.c
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
#include "rgss.h"
|
2
|
+
#include "GLFW/glfw3.h"
|
3
|
+
|
4
|
+
VALUE rb_cImage;
|
5
|
+
|
6
|
+
#define STBI_NO_PSD 1
|
7
|
+
#define STBI_NO_HDR 1
|
8
|
+
#define STBI_NO_PIC 1
|
9
|
+
#define STBI_NO_PNM 1
|
10
|
+
|
11
|
+
// stb_image.h macros
|
12
|
+
#define STBI_ASSERT RUBY_ASSERT
|
13
|
+
#define STBI_FREE xfree
|
14
|
+
#define STBI_MALLOC xmalloc
|
15
|
+
#define STBI_REALLOC xrealloc
|
16
|
+
#define STB_IMAGE_IMPLEMENTATION
|
17
|
+
#include "stb_image.h"
|
18
|
+
|
19
|
+
// stb_image_write.h macros
|
20
|
+
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
21
|
+
#define STBIW_ASSERT RUBY_ASSERT
|
22
|
+
#define STBIW_MALLOC xmalloc
|
23
|
+
#define STBIW_REALLOC xrealloc
|
24
|
+
#define STBIW_FREE xfree
|
25
|
+
#include "stb_image_write.h"
|
26
|
+
|
27
|
+
#define JPEG_QUALITY 95
|
28
|
+
#define BYTES_PER_PIXEL 4
|
29
|
+
#define COMPONENT_COUNT 4
|
30
|
+
|
31
|
+
void RGSS_Image_Free(void *img)
|
32
|
+
{
|
33
|
+
if (img)
|
34
|
+
{
|
35
|
+
GLFWimage *image = img;
|
36
|
+
if (image->pixels)
|
37
|
+
stbi_image_free(image->pixels);
|
38
|
+
xfree(image);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
static VALUE RGSS_Image_Alloc(VALUE klass)
|
43
|
+
{
|
44
|
+
GLFWimage *image = ALLOC(GLFWimage);
|
45
|
+
memset(image, 0, sizeof(GLFWimage));
|
46
|
+
return Data_Wrap_Struct(klass, NULL, RGSS_Image_Free, image);
|
47
|
+
}
|
48
|
+
|
49
|
+
static VALUE RGSS_Image_GetWidth(VALUE self)
|
50
|
+
{
|
51
|
+
GLFWimage *image = DATA_PTR(self);
|
52
|
+
return INT2NUM(image->width);
|
53
|
+
}
|
54
|
+
|
55
|
+
static VALUE RGSS_Image_GetHeight(VALUE self)
|
56
|
+
{
|
57
|
+
GLFWimage *image = DATA_PTR(self);
|
58
|
+
return INT2NUM(image->height);
|
59
|
+
}
|
60
|
+
|
61
|
+
static VALUE RGSS_Image_GetPixels(VALUE self)
|
62
|
+
{
|
63
|
+
GLFWimage *image = DATA_PTR(self);
|
64
|
+
if (image->pixels)
|
65
|
+
{
|
66
|
+
size_t size = image->width * image->height * BYTES_PER_PIXEL;
|
67
|
+
return rb_str_new((char*) image->pixels, size);
|
68
|
+
}
|
69
|
+
return Qnil;
|
70
|
+
}
|
71
|
+
|
72
|
+
void RGSS_Image_Load(const char *path, int *width, int *height, unsigned char **pixels)
|
73
|
+
{
|
74
|
+
*pixels = stbi_load(path, width, height, NULL, COMPONENT_COUNT);
|
75
|
+
if (pixels == NULL)
|
76
|
+
rb_raise(rb_eRuntimeError, "failed to load image");
|
77
|
+
}
|
78
|
+
|
79
|
+
static VALUE RGSS_Image_Dispose(VALUE self)
|
80
|
+
{
|
81
|
+
GLFWimage *image = DATA_PTR(self);
|
82
|
+
if (image->pixels)
|
83
|
+
{
|
84
|
+
xfree(image->pixels);
|
85
|
+
image->pixels = NULL;
|
86
|
+
}
|
87
|
+
return Qnil;
|
88
|
+
}
|
89
|
+
|
90
|
+
static VALUE RGSS_Image_IsDisposed(VALUE self)
|
91
|
+
{
|
92
|
+
GLFWimage *image = DATA_PTR(self);
|
93
|
+
return RB_BOOL(image->pixels == NULL);
|
94
|
+
}
|
95
|
+
|
96
|
+
static VALUE RGSS_Image_Initialize(int argc, VALUE *argv, VALUE self)
|
97
|
+
{
|
98
|
+
VALUE x, y, blob;
|
99
|
+
rb_scan_args(argc, argv, "12", &x, &y, &blob);
|
100
|
+
|
101
|
+
GLFWimage *image = DATA_PTR(self);
|
102
|
+
|
103
|
+
switch (argc)
|
104
|
+
{
|
105
|
+
case 1:
|
106
|
+
{
|
107
|
+
RGSS_Image_Load(StringValueCStr(x), &image->width, &image->height, &image->pixels);
|
108
|
+
break;
|
109
|
+
}
|
110
|
+
case 2:
|
111
|
+
case 3:
|
112
|
+
{
|
113
|
+
image->width = NUM2INT(x);
|
114
|
+
if (image->width < 1)
|
115
|
+
rb_raise(rb_eArgError, "width must be greater than 0");
|
116
|
+
|
117
|
+
image->height = NUM2INT(y);
|
118
|
+
if (image->height < 1)
|
119
|
+
rb_raise(rb_eArgError, "height must be greater than 0");
|
120
|
+
|
121
|
+
size_t size = image->width * image->height * BYTES_PER_PIXEL;
|
122
|
+
image->pixels = xmalloc(size);
|
123
|
+
if (image->pixels == NULL)
|
124
|
+
rb_raise(rb_eNoMemError, "out of memory");
|
125
|
+
|
126
|
+
if (RTEST(blob))
|
127
|
+
{
|
128
|
+
long len = RSTRING_LEN(blob);
|
129
|
+
if (len != size)
|
130
|
+
rb_raise(rb_eArgError, "invalid blob length (given %d bytes, expected %u bytes)", len, size);
|
131
|
+
memcpy(image->pixels, StringValuePtr(blob), size);
|
132
|
+
}
|
133
|
+
else
|
134
|
+
{
|
135
|
+
memset(image->pixels, 0, size);
|
136
|
+
}
|
137
|
+
|
138
|
+
break;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
|
143
|
+
return self;
|
144
|
+
}
|
145
|
+
|
146
|
+
static VALUE RGSS_Image_GetAddress(VALUE self)
|
147
|
+
{
|
148
|
+
GLFWimage *image = DATA_PTR(self);
|
149
|
+
return PTR2NUM(image->pixels);
|
150
|
+
}
|
151
|
+
|
152
|
+
static inline size_t RGSS_Image_GetOffset(GLFWimage *image, int x, int y)
|
153
|
+
{
|
154
|
+
if (image->pixels == NULL)
|
155
|
+
rb_raise(rb_eArgError, "disposed image");
|
156
|
+
|
157
|
+
if (x < 0 || x >= image->width)
|
158
|
+
rb_raise(rb_eIndexError, "x value out of range (given %d, expected 0..%d)", x, image->width - 1);
|
159
|
+
if (y < 0 || y >= image->height)
|
160
|
+
rb_raise(rb_eIndexError, "y value out of range (given %d, expected 0..%d)", y, image->height - 1);
|
161
|
+
|
162
|
+
return (x * BYTES_PER_PIXEL) + (y * image->width * BYTES_PER_PIXEL);
|
163
|
+
}
|
164
|
+
|
165
|
+
static VALUE RGSS_Image_GetPixel(VALUE self, VALUE x, VALUE y)
|
166
|
+
{
|
167
|
+
GLFWimage *image = DATA_PTR(self);
|
168
|
+
size_t i = RGSS_Image_GetOffset(image, NUM2INT(x), NUM2INT(y));
|
169
|
+
|
170
|
+
float *color = xmalloc(sizeof(float) * 4);
|
171
|
+
color[0] = image->pixels[i + 0] / 255.0f;
|
172
|
+
color[1] = image->pixels[i + 1] / 255.0f;
|
173
|
+
color[2] = image->pixels[i + 2] / 255.0f;
|
174
|
+
color[3] = image->pixels[i + 3] / 255.0f;
|
175
|
+
return Data_Wrap_Struct(rb_cColor, NULL, RUBY_DEFAULT_FREE, color);
|
176
|
+
}
|
177
|
+
|
178
|
+
static VALUE RGSS_Image_SetPixel(VALUE self, VALUE x, VALUE y, VALUE color)
|
179
|
+
{
|
180
|
+
GLFWimage *image = DATA_PTR(self);
|
181
|
+
size_t i = RGSS_Image_GetOffset(image, NUM2INT(x), NUM2INT(y));
|
182
|
+
|
183
|
+
if (RTEST(color))
|
184
|
+
{
|
185
|
+
float *vec = DATA_PTR(color);
|
186
|
+
image->pixels[i + 0] = (unsigned char) roundf(vec[0] * 255.0f);
|
187
|
+
image->pixels[i + 1] = (unsigned char) roundf(vec[1] * 255.0f);
|
188
|
+
image->pixels[i + 2] = (unsigned char) roundf(vec[2] * 255.0f);
|
189
|
+
image->pixels[i + 3] = (unsigned char) roundf(vec[3] * 255.0f);
|
190
|
+
}
|
191
|
+
else
|
192
|
+
memset(&image->pixels[i], 0, BYTES_PER_PIXEL);
|
193
|
+
|
194
|
+
return self;
|
195
|
+
}
|
196
|
+
|
197
|
+
static VALUE RGSS_Image_Save(int argc, VALUE *argv, VALUE self)
|
198
|
+
{
|
199
|
+
VALUE path, format, opts;
|
200
|
+
rb_scan_args(argc, argv, "11:", &path, &format, &opts);
|
201
|
+
|
202
|
+
GLFWimage *image = DATA_PTR(self);
|
203
|
+
if (image->pixels == NULL)
|
204
|
+
rb_raise(rb_eRuntimeError, "disposed image");
|
205
|
+
|
206
|
+
VALUE type = RTEST(format) ? format : STR2SYM("png");
|
207
|
+
|
208
|
+
int result;
|
209
|
+
int flip = RTEST(opts) && RTEST(rb_hash_aref(opts, STR2SYM("flip")));
|
210
|
+
stbi_flip_vertically_on_write(flip);
|
211
|
+
const char *file = StringValueCStr(path);
|
212
|
+
|
213
|
+
if (type == STR2SYM("png"))
|
214
|
+
{
|
215
|
+
stbi_write_png_compression_level = 8;
|
216
|
+
if (RTEST(opts))
|
217
|
+
{
|
218
|
+
VALUE cmp = rb_hash_aref(opts, STR2SYM("compression"));
|
219
|
+
if (RTEST(cmp))
|
220
|
+
stbi_write_png_compression_level = RGSS_MAX(0, RGSS_MIN(9, NUM2INT(cmp)));
|
221
|
+
}
|
222
|
+
|
223
|
+
int stride = image->width * BYTES_PER_PIXEL;
|
224
|
+
result = stbi_write_png(file, image->width, image->height, COMPONENT_COUNT, image->pixels, stride);
|
225
|
+
}
|
226
|
+
else if (type == STR2SYM("jpg") || type == STR2SYM("jpeg"))
|
227
|
+
{
|
228
|
+
int quality = JPEG_QUALITY;
|
229
|
+
if (RTEST(opts))
|
230
|
+
{
|
231
|
+
VALUE q = rb_hash_aref(opts, STR2SYM("quality"));
|
232
|
+
if (RTEST(q))
|
233
|
+
quality = RGSS_MAX(0, RGSS_MIN(100, NUM2INT(q)));
|
234
|
+
}
|
235
|
+
|
236
|
+
result = stbi_write_jpg(file, image->width, image->height, COMPONENT_COUNT, image->pixels, quality);
|
237
|
+
}
|
238
|
+
else if (type == STR2SYM("bmp"))
|
239
|
+
{
|
240
|
+
result = stbi_write_bmp(file, image->width, image->height, COMPONENT_COUNT, image->pixels);
|
241
|
+
}
|
242
|
+
else
|
243
|
+
{
|
244
|
+
rb_raise(rb_eArgError, "invalid image format specified");
|
245
|
+
}
|
246
|
+
|
247
|
+
if (!result)
|
248
|
+
rb_raise(rb_eRuntimeError, "failed to save image");
|
249
|
+
|
250
|
+
return self;
|
251
|
+
}
|
252
|
+
|
253
|
+
void RGSS_Init_Image(VALUE parent)
|
254
|
+
{
|
255
|
+
rb_cImage = rb_define_class_under(parent, "Image", rb_cObject);
|
256
|
+
rb_define_alloc_func(rb_cImage, RGSS_Image_Alloc);
|
257
|
+
|
258
|
+
rb_define_methodm1(rb_cImage, "initialize", RGSS_Image_Initialize, -1);
|
259
|
+
rb_define_method0(rb_cImage, "dispose", RGSS_Image_Dispose, 0);
|
260
|
+
rb_define_method0(rb_cImage, "disposed?", RGSS_Image_IsDisposed, 0);
|
261
|
+
|
262
|
+
rb_define_method0(rb_cImage, "width", RGSS_Image_GetWidth, 0);
|
263
|
+
rb_define_method0(rb_cImage, "height", RGSS_Image_GetHeight, 0);
|
264
|
+
rb_define_method0(rb_cImage, "pixels", RGSS_Image_GetPixels, 0);
|
265
|
+
rb_define_method0(rb_cImage, "address", RGSS_Image_GetAddress, 0);
|
266
|
+
rb_define_method2(rb_cImage, "get_pixel", RGSS_Image_GetPixel, 2);
|
267
|
+
rb_define_method3(rb_cImage, "set_pixel", RGSS_Image_SetPixel, 3);
|
268
|
+
|
269
|
+
rb_define_methodm1(rb_cImage, "save", RGSS_Image_Save, -1);
|
270
|
+
|
271
|
+
rb_define_alias(rb_cImage, "columns", "width");
|
272
|
+
rb_define_alias(rb_cImage, "rows", "height");
|
273
|
+
rb_define_alias(rb_cImage, "blob", "pixels");
|
274
|
+
}
|