toggle buttons and tools
[retroray] / src / scr_mod.c
1 /*
2 RetroRay - integrated standalone vintage modeller/renderer
3 Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include "gaw/gaw.h"
19 #include "app.h"
20 #include "rtk.h"
21 #include "scene.h"
22 #include "cmesh.h"
23 #include "meshgen.h"
24
25 enum {
26         TBN_NEW, TBN_OPEN, TBN_SAVE, TBN_SEP1,
27         TBN_SEL, TBN_MOVE, TBN_ROT, TBN_SCALE, TBN_SEP2,
28         TBN_ADD, TBN_RM, TBN_SEP3,
29         TBN_MTL, TBN_REND, TBN_VIEWREND, TBN_SEP4, TBN_CFG,
30
31         NUM_TOOL_BUTTONS
32 };
33 static const char *tbn_icon_name[] = {
34         "new", "open", "save", 0,
35         "sel", "move", "rot", "scale", 0,
36         "add", "remove", 0,
37         "mtl", "rend", "viewrend", 0, "cfg"
38 };
39 static int tbn_icon_pos[][2] = {
40         {0,0}, {16,0}, {32,0}, {-1,-1},
41         {48,0}, {64,0}, {80,0}, {96,0}, {-1,-1},
42         {112,0}, {112,16}, {-1,-1},
43         {48,16}, {64,16}, {80,16}, {-1,-1}, {96,16}
44 };
45 static rtk_icon *tbn_icons[NUM_TOOL_BUTTONS];
46 static rtk_widget *tbn_buttons[NUM_TOOL_BUTTONS];
47
48 #define TOOLBAR_HEIGHT  26
49
50 enum {TOOL_SEL, TOOL_MOVE, TOOL_ROT, TOOL_SCALE, NUM_TOOLS};
51
52
53 static int mdl_init(void);
54 static void mdl_destroy(void);
55 static int mdl_start(void);
56 static void mdl_stop(void);
57 static void mdl_display(void);
58 static void mdl_reshape(int x, int y);
59 static void mdl_keyb(int key, int press);
60 static void mdl_mouse(int bn, int press, int x, int y);
61 static void mdl_motion(int x, int y);
62
63 static void draw_grid(void);
64 static void tbn_callback(rtk_widget *w, void *cls);
65
66 struct app_screen scr_model = {
67         "modeller",
68         mdl_init, mdl_destroy,
69         mdl_start, mdl_stop,
70         mdl_display, mdl_reshape,
71         mdl_keyb, mdl_mouse, mdl_motion
72 };
73
74 static rtk_widget *toolbar;
75 static rtk_iconsheet *icons;
76
77 static struct cmesh *mesh_sph;
78
79 static float cam_theta, cam_phi = 20, cam_dist = 8;
80
81 static int tool;
82 static int selobj = -1;
83
84
85 static int mdl_init(void)
86 {
87         int i;
88         rtk_widget *w;
89
90         if(!(icons = rtk_load_iconsheet("data/icons.png"))) {
91                 errormsg("failed to load iconsheet\n");
92                 return -1;
93         }
94         for(i=0; i<NUM_TOOL_BUTTONS; i++) {
95                 if(tbn_icon_name[i]) {
96                         tbn_icons[i] = rtk_define_icon(icons, tbn_icon_name[i],
97                                         tbn_icon_pos[i][0], tbn_icon_pos[i][1], 16, 16);
98                 } else {
99                         tbn_icons[i] = 0;
100                 }
101         }
102
103         if(!(toolbar = rtk_create_window(0, "toolbar", 0, 0, win_width, TOOLBAR_HEIGHT))) {
104                 return -1;
105         }
106         rtk_win_layout(toolbar, RTK_HBOX);
107
108         for(i=0; i<NUM_TOOL_BUTTONS; i++) {
109                 if(!tbn_icons[i]) {
110                         rtk_create_separator(toolbar);
111                 } else {
112                         if(!(w = rtk_create_iconbutton(toolbar, tbn_icons[i], 0))) {
113                                 return -1;
114                         }
115                         tbn_buttons[i] = w;
116                         rtk_set_callback(w, tbn_callback, (void*)i);
117                         if(i >= TBN_SEL && i <= TBN_SCALE) {
118                                 rtk_bn_mode(w, RTK_TOGGLEBN);
119                         }
120                         if(i == TBN_SEL) {
121                                 rtk_set_value(w, 1);
122                         }
123                 }
124         }
125
126         if(!(mesh_sph = cmesh_alloc())) {
127                 errormsg("failed to allocate sphere vis mesh\n");
128                 return -1;
129         }
130         gen_sphere(mesh_sph, 1.0f, 16, 8, 1.0f, 1.0f);
131         return 0;
132 }
133
134 static void mdl_destroy(void)
135 {
136         cmesh_free(mesh_sph);
137         rtk_free_iconsheet(icons);
138 }
139
140 static int mdl_start(void)
141 {
142         gaw_clear_color(0.125, 0.125, 0.125, 1);
143
144         gaw_enable(GAW_DEPTH_TEST);
145         gaw_enable(GAW_CULL_FACE);
146         gaw_enable(GAW_LIGHTING);
147         gaw_enable(GAW_LIGHT0);
148         return 0;
149 }
150
151 static void mdl_stop(void)
152 {
153 }
154
155 static void mdl_display(void)
156 {
157         int i, num;
158
159         gaw_clear(GAW_COLORBUF | GAW_DEPTHBUF);
160
161         rtk_draw_widget(toolbar);
162
163         gaw_viewport(0, TOOLBAR_HEIGHT, win_width, win_height - TOOLBAR_HEIGHT);
164
165         gaw_matrix_mode(GAW_MODELVIEW);
166         gaw_load_identity();
167         gaw_translate(0, 0, -cam_dist);
168         gaw_rotate(cam_phi, 1, 0, 0);
169         gaw_rotate(cam_theta, 0, 1, 0);
170
171         draw_grid();
172
173         num = scn_num_objects(scn);
174         for(i=0; i<num; i++) {
175                 struct object *obj = scn->objects[i];
176                 struct sphere *sph;
177
178                 calc_object_matrix(obj);
179                 gaw_push_matrix();
180                 gaw_mult_matrix(obj->xform);
181
182                 switch(obj->type) {
183                 case OBJ_SPHERE:
184                         sph = (struct sphere*)obj;
185                         gaw_scale(sph->rad, sph->rad, sph->rad);
186                         gaw_zoffset(0.1);
187                         cmesh_draw(mesh_sph);
188                         gaw_zoffset(0);
189
190                         gaw_save();
191                         gaw_disable(GAW_LIGHTING);
192                         gaw_poly_wire();
193                         gaw_color3f(0, 1, 0);
194                         cmesh_draw(mesh_sph);
195                         gaw_poly_gouraud();
196                         gaw_restore();
197                         break;
198
199                 default:
200                         break;
201                 }
202
203                 gaw_pop_matrix();
204         }
205
206         gaw_viewport(0, 0, win_width, win_height);
207 }
208
209 static void draw_grid(void)
210 {
211         gaw_save();
212         gaw_disable(GAW_LIGHTING);
213
214         gaw_begin(GAW_LINES);
215         gaw_color3f(0.5, 0, 0);
216         gaw_vertex3f(0, 0, 0);
217         gaw_vertex3f(-100, 0, 0);
218         gaw_vertex3f(0, 0, 0);
219         gaw_vertex3f(100, 0, 0);
220         gaw_color3f(0, 0.5, 0);
221         gaw_vertex3f(0, 0, 0);
222         gaw_vertex3f(0, 0, -100);
223         gaw_vertex3f(0, 0, 0);
224         gaw_vertex3f(0, 0, 100);
225         gaw_end();
226
227         gaw_restore();
228 }
229
230 static void mdl_reshape(int x, int y)
231 {
232         float aspect = (float)x / (float)(y - TOOLBAR_HEIGHT);
233
234         gaw_matrix_mode(GAW_PROJECTION);
235         gaw_load_identity();
236         gaw_perspective(50, aspect, 0.5, 100.0);
237
238         rtk_resize(toolbar, win_width, TOOLBAR_HEIGHT);
239 }
240
241 static void mdl_keyb(int key, int press)
242 {
243         if(rtk_input_key(toolbar, key, press)) {
244                 app_redisplay();
245                 return;
246         }
247 }
248
249 static int vpdrag;
250
251 static void mdl_mouse(int bn, int press, int x, int y)
252 {
253         if(!vpdrag && rtk_input_mbutton(toolbar, bn, press, x, y)) {
254                 app_redisplay();
255                 return;
256         }
257
258         if(press) {
259                 vpdrag |= (1 << bn);
260         } else {
261                 vpdrag &= ~(1 << bn);
262         }
263 }
264
265 static void mdl_motion(int x, int y)
266 {
267         int dx, dy;
268
269         if(!vpdrag && rtk_input_mmotion(toolbar, x, y)) {
270                 app_redisplay();
271                 return;
272         }
273
274         dx = x - mouse_x;
275         dy = y - mouse_y;
276
277         if((dx | dy) == 0) return;
278
279         if(mouse_state[0]) {
280                 cam_theta += dx * 0.5f;
281                 cam_phi += dy * 0.5f;
282                 if(cam_phi < -90) cam_phi = -90;
283                 if(cam_phi > 90) cam_phi = 90;
284                 app_redisplay();
285         }
286
287         if(mouse_state[2]) {
288                 cam_dist += dy * 0.1f;
289                 if(cam_dist < 0) cam_dist = 0;
290                 app_redisplay();
291         }
292 }
293
294 static void add_sphere(void)
295 {
296         struct object *obj;
297
298         if(!(obj = create_object(OBJ_SPHERE))) {
299                 return;
300         }
301         scn_add_object(scn, obj);
302 }
303
304 static void tbn_callback(rtk_widget *w, void *cls)
305 {
306         int i, id = (intptr_t)cls;
307         int idx;
308
309         switch(id) {
310         case TBN_SEL:
311         case TBN_MOVE:
312         case TBN_ROT:
313         case TBN_SCALE:
314                 tool = id - TBN_SEL;
315                 for(i=0; i<NUM_TOOLS; i++) {
316                         if(i != tool) {
317                                 rtk_set_value(tbn_buttons[i + TBN_SEL], 0);
318                         }
319                 }
320                 break;
321
322         case TBN_ADD:
323                 idx = scn_num_objects(scn);
324                 add_sphere();
325                 selobj = idx;
326                 break;
327
328         default:
329                 break;
330         }
331 }