344
|
1 /* |
|
2 * js-sprite.c -- core sprite binding |
|
3 * |
|
4 * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr> |
|
5 * |
|
6 * Permission to use, copy, modify, and/or distribute this software for any |
|
7 * purpose with or without fee is hereby granted, provided that the above |
|
8 * copyright notice and this permission notice appear in all copies. |
|
9 * |
|
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
17 */ |
|
18 |
|
19 #include <assert.h> |
|
20 |
|
21 #include <core/alloc.h> |
|
22 #include <core/sprite.h> |
|
23 |
|
24 #include "js-sprite.h" |
|
25 #include "js-texture.h" |
|
26 |
|
27 #define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.Sprite") |
|
28 #define TEXREF DUK_HIDDEN_SYMBOL("Mlk.Sprite.texture") |
|
29 |
|
30 static inline struct sprite * |
|
31 self(duk_context *ctx) |
|
32 { |
|
33 struct sprite *sprite; |
|
34 |
|
35 duk_push_this(ctx); |
|
36 duk_get_prop_string(ctx, -1, SIGNATURE); |
|
37 sprite = duk_to_pointer(ctx, -1); |
|
38 duk_pop_2(ctx); |
|
39 |
|
40 if (!sprite) |
|
41 duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Sprite object"); |
|
42 |
|
43 return sprite; |
|
44 } |
|
45 |
|
46 static duk_ret_t |
|
47 Sprite_constructor(duk_context *ctx) |
|
48 { |
|
49 struct sprite *sprite; |
|
50 struct texture *tex = js_texture_require(ctx, 0); |
|
51 const unsigned int cellw = duk_require_uint(ctx, 1); |
|
52 const unsigned int cellh = duk_require_uint(ctx, 2); |
|
53 |
|
54 sprite = alloc_new0(sizeof (*sprite)); |
|
55 sprite_init(sprite, tex, cellw, cellh); |
|
56 |
|
57 duk_push_this(ctx); |
|
58 duk_push_pointer(ctx, sprite); |
|
59 duk_put_prop_string(ctx, -2, SIGNATURE); |
|
60 |
|
61 /* Store a copy of texture to avoid destruction. */ |
|
62 duk_dup(ctx, 0); |
|
63 duk_put_prop_string(ctx, -2, TEXREF); |
|
64 |
|
65 duk_pop(ctx); |
|
66 |
|
67 return 0; |
|
68 } |
|
69 |
|
70 static duk_ret_t |
|
71 Sprite_destructor(duk_context *ctx) |
|
72 { |
|
73 duk_get_prop_string(ctx, 0, SIGNATURE); |
|
74 free(duk_to_pointer(ctx, -1)); |
|
75 duk_pop(ctx); |
|
76 duk_del_prop_string(ctx, 0, SIGNATURE); |
|
77 |
|
78 /* Remove texture reference. */ |
|
79 duk_del_prop_string(ctx, 0, TEXREF); |
|
80 |
|
81 return 0; |
|
82 } |
|
83 |
|
84 static duk_ret_t |
|
85 Sprite_draw(duk_context *ctx) |
|
86 { |
|
87 const struct sprite *sprite = self(ctx); |
|
88 const unsigned int r = duk_require_uint(ctx, 0); |
|
89 const unsigned int c = duk_require_uint(ctx, 1); |
|
90 const int x = duk_require_int(ctx, 2); |
|
91 const int y = duk_require_int(ctx, 3); |
|
92 |
|
93 if (r >= sprite->nrows) |
|
94 duk_error(ctx, DUK_ERR_RANGE_ERROR, "row overflow: %u >= %u", r, sprite->nrows); |
|
95 if (c >= sprite->ncols) |
|
96 duk_error(ctx, DUK_ERR_RANGE_ERROR, "column overflow: %u >= %u", c, sprite->ncols); |
|
97 |
|
98 sprite_draw(sprite, r, c, x, y); |
|
99 |
|
100 return 0; |
|
101 } |
|
102 |
|
103 static duk_ret_t |
|
104 Sprite_scale(duk_context *ctx) |
|
105 { |
|
106 const struct sprite *sprite = self(ctx); |
|
107 const unsigned int r = duk_require_uint(ctx, 0); |
|
108 const unsigned int c = duk_require_uint(ctx, 1); |
|
109 const int x = duk_require_int(ctx, 2); |
|
110 const int y = duk_require_int(ctx, 3); |
|
111 const unsigned int w = duk_require_uint(ctx, 4); |
|
112 const unsigned int h = duk_require_uint(ctx, 5); |
|
113 |
|
114 if (r >= sprite->nrows) |
|
115 duk_error(ctx, DUK_ERR_RANGE_ERROR, "row overflow: %u >= %u", r, sprite->nrows); |
|
116 if (c >= sprite->ncols) |
|
117 duk_error(ctx, DUK_ERR_RANGE_ERROR, "column overflow: %u >= %u", c, sprite->ncols); |
|
118 |
|
119 sprite_scale(sprite, r, c, x, y, w, h); |
|
120 |
|
121 return 0; |
|
122 } |
|
123 |
|
124 static const duk_function_list_entry methods[] = { |
|
125 { "draw", Sprite_draw, 4 }, |
|
126 { "scale", Sprite_scale, 6 }, |
|
127 { NULL, NULL, 0 } |
|
128 }; |
|
129 |
|
130 void |
|
131 js_sprite_bind(duk_context *ctx) |
|
132 { |
|
133 assert(ctx); |
|
134 |
|
135 duk_push_c_function(ctx, Sprite_constructor, 3); |
|
136 duk_push_object(ctx); |
|
137 duk_put_function_list(ctx, -1, methods); |
|
138 duk_push_c_function(ctx, Sprite_destructor, 1); |
|
139 duk_set_finalizer(ctx, -2); |
|
140 duk_put_prop_string(ctx, -2, "prototype"); |
|
141 duk_put_global_string(ctx, "Sprite"); |
|
142 } |