]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/point_layer.c
Revert "(#164) %z -> %l for mingw on Windows"
[nothing.git] / src / game / level / level_editor / point_layer.c
1 #include <stdio.h>
2
3 #include <SDL.h>
4
5 #include "dynarray.h"
6 #include "game/camera.h"
7 #include "system/line_stream.h"
8 #include "system/log.h"
9 #include "system/lt.h"
10 #include "system/nth_alloc.h"
11 #include "system/stacktrace.h"
12 #include "system/str.h"
13 #include "ui/edit_field.h"
14 #include "./point_layer.h"
15 #include "math/extrema.h"
16 #include "math/mat3x3.h"
17 #include "./color_picker.h"
18 #include "undo_history.h"
19
20 #define POINT_LAYER_ELEMENT_RADIUS 10.0f
21 #define POINT_LAYER_ID_TEXT_SIZE vec(2.0f, 2.0f)
22 #define POINT_LAYER_ID_TEXT_COLOR COLOR_BLACK
23
24 static int point_clipboard = 0;
25 static Color point_clipboard_color;
26
27 // TODO(#1140): PointLayer does not support snapping
28
29 typedef enum {
30     POINT_LAYER_IDLE = 0,
31     POINT_LAYER_EDIT_ID,
32     POINT_LAYER_MOVE,
33     POINT_LAYER_RECOLOR
34 } PointLayerState;
35
36 struct PointLayer
37 {
38     Lt *lt;
39     PointLayerState state;
40     Dynarray/*<Vec2f>*/ *positions;
41     Dynarray/*<Color>*/ *colors;
42     Dynarray/*<char[ID_MAX_SIZE]>*/ *ids;
43     int selection;
44     ColorPicker color_picker;
45
46     Vec2f inter_position;
47     Color inter_color;
48     Edit_field *edit_field;
49
50     int id_name_counter;
51     const char *id_name_prefix;
52 };
53
54 typedef enum {
55     POINT_UNDO_ADD,
56     POINT_UNDO_DELETE,
57     POINT_UNDO_UPDATE,
58     POINT_UNDO_SWAP
59 } PointUndoType;
60
61 typedef struct {
62     PointUndoType type;
63     PointLayer *layer;
64     Vec2f position;
65     Color color;
66     char id[ID_MAX_SIZE];
67     size_t index;
68     size_t index2;
69 } PointUndoContext;
70
71 static
72 PointUndoContext create_point_undo_swap_context(PointLayer *point_layer,
73                                      size_t index, size_t index2)
74 {
75     trace_assert(point_layer);
76     trace_assert(index < dynarray_count(point_layer->positions));
77     trace_assert(index2 < dynarray_count(point_layer->positions));
78
79     PointUndoContext undo_context;
80     undo_context.type = POINT_UNDO_SWAP;
81     undo_context.layer = point_layer;
82     undo_context.index = index;
83     undo_context.index2 = index2;
84     return undo_context;
85 }
86
87 static
88 PointUndoContext create_point_undo_context(PointLayer *point_layer,
89                                 PointUndoType type)
90 {
91     trace_assert(type != POINT_UNDO_SWAP);
92
93     (void) create_point_undo_swap_context;
94
95     PointUndoContext undo_context;
96
97     size_t index =
98         type == POINT_UNDO_ADD
99         ? dynarray_count(point_layer->positions) - 1
100         : (size_t) point_layer->selection;
101
102     undo_context.type = type;
103     undo_context.layer = point_layer;
104     dynarray_copy_to(point_layer->positions, &undo_context.position, index);
105     dynarray_copy_to(point_layer->colors, &undo_context.color, index);
106     dynarray_copy_to(point_layer->ids, &undo_context.id, index);
107     undo_context.index = index;
108
109     return undo_context;
110 }
111
112 static
113 void point_layer_undo(void *context, size_t context_size)
114 {
115     trace_assert(context);
116     trace_assert(sizeof(PointUndoContext) == context_size);
117
118     PointUndoContext *undo_context = context;
119     PointLayer *point_layer = undo_context->layer;
120
121     switch (undo_context->type) {
122     case POINT_UNDO_ADD: {
123         dynarray_pop(point_layer->positions, NULL);
124         dynarray_pop(point_layer->colors, NULL);
125         dynarray_pop(point_layer->ids, NULL);
126         point_layer->selection = -1;
127     } break;
128
129     case POINT_UNDO_DELETE: {
130         dynarray_insert_before(point_layer->positions, undo_context->index, &undo_context->position);
131         dynarray_insert_before(point_layer->colors, undo_context->index, &undo_context->color);
132         dynarray_insert_before(point_layer->ids, undo_context->index, &undo_context->id);
133         point_layer->selection = -1;
134     } break;
135
136     case POINT_UNDO_UPDATE: {
137         dynarray_replace_at(point_layer->positions, undo_context->index, &undo_context->position);
138         dynarray_replace_at(point_layer->colors, undo_context->index, &undo_context->color);
139         dynarray_replace_at(point_layer->ids, undo_context->index, &undo_context->id);
140     } break;
141
142     case POINT_UNDO_SWAP: {
143         dynarray_swap(point_layer->positions, undo_context->index, undo_context->index2);
144         dynarray_swap(point_layer->colors, undo_context->index, undo_context->index2);
145         dynarray_swap(point_layer->ids, undo_context->index, undo_context->index2);
146     } break;
147     }
148 }
149
150 #define POINT_UNDO_PUSH(HISTORY, CONTEXT)                                     \
151     do {                                                                \
152         PointUndoContext context = (CONTEXT);                                \
153         undo_history_push(                                              \
154             HISTORY,                                                    \
155             point_layer_undo,                                           \
156             &context,                                                   \
157             sizeof(context));                                           \
158     } while(0)
159
160 LayerPtr point_layer_as_layer(PointLayer *point_layer)
161 {
162     LayerPtr layer = {
163         .type = LAYER_POINT,
164         .ptr = point_layer
165     };
166     return layer;
167 }
168
169 PointLayer *create_point_layer(const char *id_name_prefix)
170 {
171     Lt *lt = create_lt();
172
173     PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free);
174     if (point_layer == NULL) {
175         RETURN_LT(lt, NULL);
176     }
177     point_layer->lt = lt;
178
179     point_layer->state = POINT_LAYER_IDLE;
180
181     point_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Vec2f)), destroy_dynarray);
182     if (point_layer->positions == NULL) {
183         RETURN_LT(lt, NULL);
184     }
185
186     point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
187     if (point_layer->colors == NULL) {
188         RETURN_LT(lt, NULL);
189     }
190
191     point_layer->ids = PUSH_LT(lt, create_dynarray(sizeof(char) * ID_MAX_SIZE), destroy_dynarray);
192     if (point_layer->ids == NULL) {
193         RETURN_LT(lt, NULL);
194     }
195
196     point_layer->edit_field = PUSH_LT(
197         lt,
198         create_edit_field(
199             POINT_LAYER_ID_TEXT_SIZE,
200             POINT_LAYER_ID_TEXT_COLOR),
201         destroy_edit_field);
202     if (point_layer->edit_field == NULL) {
203         RETURN_LT(lt, NULL);
204     }
205
206     point_layer->id_name_prefix = id_name_prefix;
207
208     return point_layer;
209 }
210
211 PointLayer *create_point_layer_from_line_stream(LineStream *line_stream,
212                                                 const char *id_name_prefix)
213 {
214     trace_assert(line_stream);
215
216     PointLayer *point_layer = create_point_layer(id_name_prefix);
217
218     size_t count = 0;
219     if (sscanf(
220             line_stream_next(line_stream),
221             "%zu",
222             &count) == EOF) {
223         log_fail("Could not read amount of points");
224         RETURN_LT(point_layer->lt, NULL);
225     }
226
227     char color_name[7];
228     char id[ID_MAX_SIZE];
229     float x, y;
230     for (size_t i = 0; i < count; ++i) {
231         if (sscanf(
232                 line_stream_next(line_stream),
233                 "%"STRINGIFY(ID_MAX_SIZE)"s%f%f%6s",
234                 id, &x, &y, color_name) < 0) {
235             log_fail("Could not read %dth goal\n", i);
236             RETURN_LT(point_layer->lt, NULL);
237         }
238         const Color color = hexstr(color_name);
239         const Vec2f point = vec(x, y);
240
241         dynarray_push(point_layer->colors, &color);
242         dynarray_push(point_layer->positions, &point);
243         dynarray_push(point_layer->ids, id);
244     }
245
246     point_layer->selection = -1;
247
248     point_layer->color_picker = create_color_picker_from_rgba(COLOR_RED);
249
250     return point_layer;
251 }
252
253 void destroy_point_layer(PointLayer *point_layer)
254 {
255     trace_assert(point_layer);
256     RETURN_LT0(point_layer->lt);
257 }
258
259 static inline
260 Triangle element_shape(Vec2f position, float scale)
261 {
262     return triangle_mat3x3_product(
263         equilateral_triangle(),
264         mat3x3_product(
265             trans_mat_vec(position),
266             scale_mat(scale)));
267 }
268
269 int point_layer_render(const PointLayer *point_layer,
270                        const Camera *camera,
271                        int active)
272 {
273     trace_assert(point_layer);
274     trace_assert(camera);
275
276     const int n = (int) dynarray_count(point_layer->positions);
277     Vec2f *positions = dynarray_data(point_layer->positions);
278     Color *colors = dynarray_data(point_layer->colors);
279     char *ids = dynarray_data(point_layer->ids);
280
281     for (int i = 0; i < n; ++i) {
282         const Color color = color_scale(
283             point_layer->state == POINT_LAYER_RECOLOR && i == point_layer->selection
284             ? point_layer->inter_color
285             : colors[i],
286             rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f));
287
288         const Vec2f position =
289             point_layer->state == POINT_LAYER_MOVE && i == point_layer->selection
290             ? point_layer->inter_position
291             : positions[i];
292
293         // Selection Layer
294         if (active && i == point_layer->selection) {
295             if (camera_fill_triangle(
296                     camera,
297                     element_shape(
298                         position,
299                         POINT_LAYER_ELEMENT_RADIUS + 5.0f),
300                     color_invert(color)) < 0) {
301                 return -1;
302             }
303
304             if (point_layer->state != POINT_LAYER_EDIT_ID &&
305                 camera_render_text(
306                     camera,
307                     ids + ID_MAX_SIZE * i,
308                     POINT_LAYER_ID_TEXT_SIZE,
309                     POINT_LAYER_ID_TEXT_COLOR,
310                     position) < 0) {
311                 return -1;
312             }
313         }
314
315         if (camera_fill_triangle(
316                 camera,
317                 element_shape(
318                     position,
319                     POINT_LAYER_ELEMENT_RADIUS),
320                 color) < 0) {
321             return -1;
322         }
323     }
324
325     if (point_layer->state == POINT_LAYER_EDIT_ID) {
326         if (edit_field_render_world(
327                 point_layer->edit_field,
328                 camera,
329                 positions[point_layer->selection]) < 0) {
330             return -1;
331         }
332     }
333
334     if (active && color_picker_render(&point_layer->color_picker, camera) < 0) {
335         return -1;
336     }
337
338
339     return 0;
340 }
341
342 static
343 int point_layer_element_at(const PointLayer *point_layer,
344                            Vec2f position)
345 {
346     trace_assert(point_layer);
347
348     int n = (int) dynarray_count(point_layer->positions);
349     Vec2f *positions = dynarray_data(point_layer->positions);
350
351     for (int i = n - 1; i >= 0; --i) {
352         if (vec_length(vec_sub(positions[i], position)) < POINT_LAYER_ELEMENT_RADIUS) {
353             return i;
354         }
355     }
356
357     return -1;
358 }
359
360 static
361 int point_layer_add_element(PointLayer *point_layer,
362                             Vec2f position,
363                             Color color,
364                             UndoHistory *undo_history)
365 {
366     trace_assert(point_layer);
367     trace_assert(undo_history);
368
369     char id[ID_MAX_SIZE];
370     snprintf(id, ID_MAX_SIZE, "%s_%d",
371              point_layer->id_name_prefix,
372              point_layer->id_name_counter++);
373
374     dynarray_push(point_layer->positions, &position);
375     dynarray_push(point_layer->colors, &color);
376     dynarray_push(point_layer->ids, id);
377
378     POINT_UNDO_PUSH(
379         undo_history,
380         create_point_undo_context(point_layer, POINT_UNDO_ADD));
381
382     return 0;
383 }
384
385 static
386 void point_layer_swap_elements(PointLayer *point_layer,
387                                size_t a, size_t b,
388                                UndoHistory *undo_history)
389 {
390     trace_assert(point_layer);
391     trace_assert(undo_history);
392     trace_assert(a < dynarray_count(point_layer->positions));
393     trace_assert(b < dynarray_count(point_layer->positions));
394
395     dynarray_swap(point_layer->positions, a, b);
396     dynarray_swap(point_layer->colors, a, b);
397     dynarray_swap(point_layer->ids, a, b);
398
399     POINT_UNDO_PUSH(
400         undo_history,
401         create_point_undo_swap_context(point_layer, a, b));
402 }
403
404 static
405 void point_layer_delete_nth_element(PointLayer *point_layer,
406                                     size_t i,
407                                     UndoHistory *undo_history)
408 {
409     trace_assert(point_layer);
410
411     POINT_UNDO_PUSH(
412         undo_history,
413         create_point_undo_context(
414             point_layer,
415             POINT_UNDO_DELETE));
416
417     dynarray_delete_at(point_layer->positions, i);
418     dynarray_delete_at(point_layer->colors, i);
419     dynarray_delete_at(point_layer->ids, i);
420 }
421
422 static
423 int point_layer_idle_event(PointLayer *point_layer,
424                            const SDL_Event *event,
425                            const Camera *camera,
426                            UndoHistory *undo_history)
427 {
428     trace_assert(point_layer);
429     trace_assert(event);
430     trace_assert(camera);
431
432     int selected = 0;
433     if (color_picker_event(
434             &point_layer->color_picker,
435             event,
436             camera,
437             &selected) < 0) {
438         return -1;
439     }
440
441     if (selected) {
442         if (point_layer->selection >= 0) {
443             point_layer->inter_color = color_picker_rgba(&point_layer->color_picker);
444             point_layer->state = POINT_LAYER_RECOLOR;
445         }
446         return 0;
447     }
448
449     switch (event->type) {
450     case SDL_MOUSEBUTTONDOWN: {
451         switch (event->button.button) {
452         case SDL_BUTTON_LEFT: {
453             const Vec2f position = camera_map_screen(camera, event->button.x, event->button.y);
454
455             point_layer->selection = point_layer_element_at(
456                 point_layer, position);
457
458             if (point_layer->selection < 0) {
459                 point_layer_add_element(
460                     point_layer,
461                     position,
462                     color_picker_rgba(&point_layer->color_picker),
463                     undo_history);
464             } else {
465                 Color *colors = dynarray_data(point_layer->colors);
466                 Vec2f *positions = dynarray_data(point_layer->positions);
467
468                 point_layer->state = POINT_LAYER_MOVE;
469                 point_layer->color_picker =
470                     create_color_picker_from_rgba(colors[point_layer->selection]);
471                 point_layer->inter_position = positions[point_layer->selection];
472             }
473         } break;
474         }
475     } break;
476
477     case SDL_KEYDOWN: {
478         switch (event->key.keysym.sym) {
479         case SDLK_UP: {
480             if ((event->key.keysym.mod & KMOD_SHIFT)
481                 && (point_layer->selection >= 0)
482                 && ((size_t)(point_layer->selection + 1) < dynarray_count(point_layer->positions))) {
483                 point_layer_swap_elements(
484                     point_layer,
485                     (size_t) point_layer->selection,
486                     (size_t) point_layer->selection + 1,
487                     undo_history);
488                 point_layer->selection++;
489             }
490         } break;
491
492         case SDLK_DOWN: {
493             if ((event->key.keysym.mod & KMOD_SHIFT)
494                 && (point_layer->selection > 0)
495                 && ((size_t) point_layer->selection < dynarray_count(point_layer->positions))) {
496                 point_layer_swap_elements(
497                     point_layer,
498                     (size_t) point_layer->selection,
499                     (size_t) point_layer->selection - 1,
500                     undo_history);
501                 point_layer->selection--;
502             }
503         } break;
504
505         case SDLK_DELETE: {
506             if (0 <= point_layer->selection && point_layer->selection < (int) dynarray_count(point_layer->positions)) {
507                 point_layer_delete_nth_element(
508                     point_layer,
509                     (size_t)point_layer->selection,
510                     undo_history);
511                 point_layer->selection = -1;
512             }
513         } break;
514
515         case SDLK_F2: {
516             if (point_layer->selection >= 0) {
517                 char *ids = dynarray_data(point_layer->ids);
518                 point_layer->state = POINT_LAYER_EDIT_ID;
519                 edit_field_replace(
520                     point_layer->edit_field,
521                     ids + ID_MAX_SIZE * point_layer->selection);
522                 SDL_StartTextInput();
523             }
524         } break;
525
526         case SDLK_c: {
527             if ((event->key.keysym.mod & KMOD_LCTRL) && point_layer->selection >= 0) {
528                 point_clipboard = 1;
529                 dynarray_copy_to(point_layer->colors, &point_clipboard_color, (size_t)point_layer->selection);
530             }
531         } break;
532
533         case SDLK_v: {
534             if ((event->key.keysym.mod & KMOD_LCTRL) && point_clipboard) {
535                 int x, y;
536                 SDL_GetMouseState(&x, &y);
537                 Vec2f position = camera_map_screen(camera, x, y);
538
539                 point_layer_add_element(
540                     point_layer,
541                     position,
542                     point_clipboard_color,
543                     undo_history);
544             }
545         } break;
546         }
547     } break;
548     }
549
550     return 0;
551 }
552
553 static
554 int point_layer_edit_id_event(PointLayer *point_layer,
555                               const SDL_Event *event,
556                               const Camera *camera,
557                               UndoHistory *undo_history)
558 {
559     trace_assert(point_layer);
560     trace_assert(event);
561     trace_assert(camera);
562
563     switch (event->type) {
564     case SDL_KEYDOWN: {
565         switch(event->key.keysym.sym) {
566         case SDLK_RETURN: {
567             POINT_UNDO_PUSH(
568                 undo_history,
569                 create_point_undo_context(
570                     point_layer,
571                     POINT_UNDO_UPDATE));
572
573             char *id = dynarray_pointer_at(point_layer->ids, (size_t) point_layer->selection);
574             const char *text = edit_field_as_text(point_layer->edit_field);
575             size_t n = min_size_t(strlen(text), ID_MAX_SIZE - 1);
576             memcpy(id, text, n);
577             memset(id + n, 0, ID_MAX_SIZE - n);
578
579             point_layer->state = POINT_LAYER_IDLE;
580             SDL_StopTextInput();
581             return 0;
582         } break;
583
584         case SDLK_ESCAPE: {
585             point_layer->state = POINT_LAYER_IDLE;
586             SDL_StopTextInput();
587             return 0;
588         } break;
589         }
590     } break;
591     }
592
593     return edit_field_event(point_layer->edit_field, event);
594 }
595
596 static
597 int point_layer_move_event(PointLayer *point_layer,
598                            const SDL_Event *event,
599                            const Camera *camera,
600                            UndoHistory *undo_history)
601 {
602     trace_assert(point_layer);
603     trace_assert(event);
604     trace_assert(camera);
605     trace_assert(point_layer->selection >= 0);
606
607     Vec2f *positions = dynarray_data(point_layer->positions);
608
609     switch (event->type) {
610     case SDL_MOUSEBUTTONUP: {
611         switch (event->button.button) {
612         case SDL_BUTTON_LEFT: {
613             point_layer->state = POINT_LAYER_IDLE;
614
615             const float distance = vec_length(
616                 vec_sub(point_layer->inter_position,
617                         positions[point_layer->selection]));
618
619             if (distance > 1e-6) {
620                 POINT_UNDO_PUSH(
621                     undo_history,
622                     create_point_undo_context(
623                         point_layer,
624                         POINT_UNDO_UPDATE));
625
626                 dynarray_replace_at(
627                     point_layer->positions,
628                     (size_t) point_layer->selection,
629                     &point_layer->inter_position);
630             }
631         } break;
632         }
633     } break;
634
635     case SDL_MOUSEMOTION: {
636         const Uint8 *state = SDL_GetKeyboardState(NULL);
637         const Vec2f mouse_pos = camera_map_screen(camera, event->motion.x, event->motion.y);
638         const Vec2f point_pos = positions[point_layer->selection];
639
640         if (!(state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL])) {
641             point_layer->inter_position = mouse_pos;
642         } else {
643             const float dx = fabsf(point_pos.x - mouse_pos.x);
644             const float dy = fabsf(point_pos.y - mouse_pos.y);
645
646             if (dx > dy) {
647                 point_layer->inter_position = vec(mouse_pos.x, point_pos.y);
648             } else {
649                 point_layer->inter_position = vec(point_pos.x, mouse_pos.y);
650             }
651         }
652     } break;
653     }
654
655     return 0;
656 }
657
658 static
659 int point_layer_recolor_event(PointLayer *point_layer,
660                               const SDL_Event *event,
661                               const Camera *camera,
662                               UndoHistory *undo_history)
663 {
664     trace_assert(point_layer);
665     trace_assert(event);
666     trace_assert(camera);
667     trace_assert(undo_history);
668     trace_assert(point_layer->selection >= 0);
669
670     int selected = 0;
671     if (color_picker_event(
672             &point_layer->color_picker,
673             event,
674             camera,
675             &selected) < 0) {
676         return -1;
677     }
678
679     if (selected) {
680         point_layer->inter_color = color_picker_rgba(&point_layer->color_picker);
681
682         if (!color_picker_drag(&point_layer->color_picker)) {
683             POINT_UNDO_PUSH(
684                 undo_history,
685                 create_point_undo_context(
686                     point_layer,
687                     POINT_UNDO_UPDATE));
688
689             dynarray_replace_at(
690                 point_layer->colors,
691                 (size_t) point_layer->selection,
692                 &point_layer->inter_color);
693
694             point_layer->state = POINT_LAYER_IDLE;
695         }
696     }
697
698
699     return 0;
700 }
701
702 int point_layer_event(PointLayer *point_layer,
703                       const SDL_Event *event,
704                       const Camera *camera,
705                       UndoHistory *undo_history)
706 {
707     trace_assert(point_layer);
708     trace_assert(event);
709     trace_assert(camera);
710     trace_assert(undo_history);
711
712     switch (point_layer->state) {
713     case POINT_LAYER_IDLE:
714         return point_layer_idle_event(point_layer, event, camera, undo_history);
715
716     case POINT_LAYER_EDIT_ID:
717         return point_layer_edit_id_event(point_layer, event, camera, undo_history);
718
719     case POINT_LAYER_MOVE:
720         return point_layer_move_event(point_layer, event, camera, undo_history);
721
722     case POINT_LAYER_RECOLOR:
723         return point_layer_recolor_event(point_layer, event, camera, undo_history);
724     }
725
726     return 0;
727 }
728
729 size_t point_layer_count(const PointLayer *point_layer)
730 {
731     trace_assert(point_layer);
732     return dynarray_count(point_layer->positions);
733 }
734
735 const Vec2f *point_layer_positions(const PointLayer *point_layer)
736 {
737     trace_assert(point_layer);
738     return dynarray_data(point_layer->positions);
739 }
740
741 const Color *point_layer_colors(const PointLayer *point_layer)
742 {
743     trace_assert(point_layer);
744     return dynarray_data(point_layer->colors);
745 }
746
747 const char *point_layer_ids(const PointLayer *point_layer)
748 {
749     trace_assert(point_layer);
750     return dynarray_data(point_layer->ids);
751 }
752
753 int point_layer_dump_stream(const PointLayer *point_layer,
754                             FILE *filedump)
755 {
756     trace_assert(point_layer);
757     trace_assert(filedump);
758
759     size_t n = dynarray_count(point_layer->ids);
760     char *ids = dynarray_data(point_layer->ids);
761     Vec2f *positions = dynarray_data(point_layer->positions);
762     Color *colors = dynarray_data(point_layer->colors);
763
764     fprintf(filedump, "%zd\n", n);
765     for (size_t i = 0; i < n; ++i) {
766         fprintf(filedump, "%s %f %f ",
767                 ids + ID_MAX_SIZE * i,
768                 positions[i].x, positions[i].y);
769         color_hex_to_stream(colors[i], filedump);
770         fprintf(filedump, "\n");
771     }
772
773     return 0;
774 }