forked from versenaut/quelsolaar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HACKING.html
1204 lines (1177 loc) · 41.4 KB
/
HACKING.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<style type="text/css">
<!--
div.title
{
text-align: center;
}
div.credits
{
text-align: center;
}
pre.code
{
background-color: #ddddee;
padding: 0.2em;
border-style: solid;
border-width: 1px;
border-color: #aaaabb;
}
ul.toc
{
margin-left: 1.0em;
padding-left: 0;
list-style-type: none;
}
table.table
{
background-color: #ddddee;
border-style: solid;
border-width: 1px;
border-color: #aaaabb;
}
-->
</style>
<title>"Quel Solaar" Source Guide</title>
</head>
<body>
<div class="title">
<h1>"Quel Solaar" Source Guide</h1>
</div>
<div class="credits">
<p> Written by Eskil Steenberg (<a href="mailto:eskil@obsession.se">eskil@obsession.se</a>),<br>
Converted to HTML by Emil Brink (<a href="mailto:emil@obsession.se">emil@obsession.se</a>),<br>
Additional proofreading by Camilla Berglund (<a href="mailto:camilla.berglund@gmail.com">camilla.berglund@gmail.com</a>).
</p>
<p>
December, 2005
</p>
</div>
<hr>
<h2>Table of Contents</h2>
<ul class="toc">
<li><a href="#intro">Introduction</a></li>
<li><a href="#modules">Modules and What They Do</a>
<ul class="toc">
<li><a href="#mod-verse">Verse</a></li>
<li><a href="#mod-st">St</a></li>
<li><a href="#mod-enough">Enough</a></li>
<li><a href="#mod-betray">Betray</a></li>
<li><a href="#mod-seduce">Seduce</a></li>
<li><a href="#mod-persuade">Persuade</a></li>
</ul>
</li>
<li><a href="#building">Building</a>
<ul class="toc">
<li><a href="#building-appspec">Application-Specific Code</a></li>
<li><a href="#building-codestyle">Code Style</a></li>
</ul>
</li>
<li><a href="#api">Module API Reference</a>
<ul class="toc">
<li><a href="#api-enough">Enough</a>
<ul class="toc">
<li><a href="#api-enough-con">Managing Connections</a></li>
<li><a href="#api-enough-nodes">Node Handling</a></li>
<li><a href="#api-enough-cdata">Custom Data</a></li>
<li><a href="#api-enough-ndata">Node Data</a></li>
<li><a href="#api-enough-nspec">Special Node Functions</a>
<ul class="toc">
<li><a href="#api-enough-nspec-g">Geometry Node</a></li>
<li><a href="#api-enough-nspec-b">Bitmap Node</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#api-betray">Betray</a></li>
<li><a href="#api-seduce">Seduce</a></li>
</ul>
</li>
<li><a href="#links">Links</a></li>
</ul>
<hr>
<h2><a name="intro">Introduction</a></h2>
<p>
This is a guide through the source code of Loq Airou, Quel Solaar,
Connector, and the UV editor
known just as "uv". Although these applications are separate they share
source code and are built on the same principles.
Generally the code has very few comments, but it should still be fairly
clear, with the help of this guide. This
guide also includes information on my coding style. Please try to
maintain the coding
style if you modify the code.
</p>
<h2><a name="modules">Modules and What They Do</a></h2>
<p>
The code is divided into a number of modules. They are Verse, Enough,
Betray, Seduce, Persuade and St.
</p>
<p>
All modules have a header file named after the module (like <tt>enough.h</tt>
and <tt>betray.h</tt>). All other files begin
with the first letter of the name of the module, followed by an
underscore, so a file named <tt>e_head.c</tt> is a file used by
Enough while <tt>s_main*</tt> is a file used by Seduce. The following
table summarizes the module-specific filename prefixes used
(in alphabetical order):
</p>
<table class="table">
<tbody>
<tr>
<th>Prefix</th>
<th>Module</th>
<th>Description</th>
</tr>
<tr>
<td><tt>b_</tt></td>
<td><a href="#mod-betray">Betray</a></td>
<td>Windowing abstractions</td>
</tr>
<tr>
<td><tt>e_</tt></td>
<td><a href="#mod-enough">Enough</a></td>
<td>Verse data storage</td>
</tr>
<tr>
<td><tt>p_</tt> </td>
<td><a href="#mod-persuade">Persuade</a></td>
<td>High-quality rendering</td>
</tr>
<tr>
<td><tt>s_</tt></td>
<td><a href="#mod-seduce">Seduce</a> </td>
<td>User interface</td>
</tr>
<tr>
<td><tt>st_</tt> </td>
<td><a href="#mod-st">"Standard"</a> </td>
<td>Utility code</td>
</tr>
</tbody>
</table>
<p>
Outside of a module, only the interface in its main header file should
be used. All application specific code is found in
files that begin with the application's initials, followed by an
underscore. For example, files from Loq Airou are named <code>la_*</code>.
In some cases, when multiple files in a module or application make up a
"sub-module", they may be named to reflect this. For instance, in Loq
Airou there are a number of files named <tt>la_tool_*</tt>, which
contain all the tools found in the pop-up menus<tt></tt>. I generally
write fairly short implementation files, and the practice of having one
header file for every .c file
would not be very practical, because many header files would contain
only one or two external symbols. Therefore,
many .c files share header files. Header files inside modules are
usually only used when many .c files in one sub-module needs to
access the same data.
</p>
<h3><a name="mod-verse">Verse</a></h3>
<p>
Verse is not really a module in this package, and it resides in its own
CVS module. Verse is needed by all applications, however, and was
written by
the same person who wrote the other modules (Eskil). In fact, the
modules and applications were created to showcase
Verse. Verse is the real-time network I/O layer that replaces all the
file loading and saving in the applications. Read more about
Verse at <a href="http://www.blender.org/modules/verse/">blender.org</a>.
</p>
<h3><a name="mod-st">St</a></h3>
<p>
St is a tiny module that includes basic definitions and some simple
globally used functions. St has no external dependencies, and so does
not require any
other library or module to compile.
</p>
<h3><a name="mod-enough">Enough</a></h3>
<p>
Enough is the storage library, and stores incoming data from Verse. It
downloads the basic structure of the content of the Verse host it is
connected to. Enough can handle multiple connections at the same time
(although neither any of the applications nor Persuade supports this).
Enough does not download data, like Geometry and Bitmap layers, until
the user actually asks for it. Enough does not support any form of
quick
searching or advanced data storage such as subdivision or BSP. In
Enough you can store user-defined and function pointers, which may be
very useful if you want to store your own representations of the nodes.
This is used extensively in both Connector and Persuade.
</p>
<h3><a name="mod-betray">Betray</a></h3>
<p>
Betray is the module that wraps all OS-specific calls, like access to
input devices and creation of windows. Betray can be compiled against
any one of
<a href="http://www.opengl.org/resources/libraries/glut.html">GLUT</a>,
<a href="http://glfw.sourceforge.net/">GLFW</a> or
<a href="http://www.libsdl.org/">SDL</a>. All are highly portable,
which in turn should make the applications portable. If you would like
to port any of the applications to another platform, or
give them native support on a platform where they already exist, then
this is where you should add it. The Betray module uses <code>define</code>s
in the <code>betray.h</code> file to switch between the different
libraries.
</p>
<p>
If you would like to add some sort of system-specific functionality,
the Betray API can be extended. However, it should be the same
regardless of how
Betray is compiled. Users of Betray should not have to read defines to
know whether or not something is available. The functionality may
not work on all platforms, but it should at least compile.
</p>
<p>
Betray contains the main loop and calls a function provided to it by
the application, which takes a pointer to the (very important)
<code>BInputState</code>
structure. This structure includes the position of the mouse pointer,
the state of the mouse buttons, key events and other data. It also
contains a "mode", which is perhaps the most important thing, but
rather non-obvious, because the function is not
called once per frame but <strong>three</strong> times! Once for
drawing, once for input and the third time for computational updates.
This means that Betray can choose to send any of these events at it
sees fit.
</p>
<p>
For instance Betray can run the compute command more often than the
draw command, and the draw command more often than the event command.
However, this means that your code has to check what mode it is
currently
running in. This may seem strange, after all, why not have there
separate entry
points? There is actually a very good reason for this, though. Imagine
that you
want to implement a button. Then you would create a function like this:
</p>
<pre class="code">
extern boolean my_nice_button(BInputState *input, float pos_x, float pos_y, char *name);
</pre>
<p>
Now, inside this function I can ether draw the button or
check if the user just clicked the button. The function will always
return
<code>FALSE</code> in draw mode, which means that the application can use the
function
like this:
</p>
<pre class="code">
if(my_nice_button(input, 0.2f, 0.4f, "cut"))
do_the_cutting();
</pre>
<p>
Now the <code>do_the_cutting()</code> function will only be called in
event mode and never in draw mode. As you can see, it makes it fairly
easy to write interfaces, since you don't need two different functions
to describe the interface, which then have to be kept synchronized.
</p>
<p>
The compute mode is usually processed quickly, and is only used for
things like keeping Verse alive and performing computation that has
nothing
to do
with drawing or input. This mode is the only mode that will be called
if the application is iconified.
</p>
<h3><a name="mod-seduce">Seduce</a></h3>
<p>
Seduce is the basic interface module used by all applications. Seduce
used to include buttons and other interface elements, but I have found
it easier and
more flexible to create ad hoc UI toolkits for each application, in
order to make
them fit better. Therefore, Seduce mainly includes helper code that is
used in
all
types of interfaces, such as checking if the mouse pointer is inside a
rectangle, storing settings, entering and drawing text. In
addition, Seduce
includes an editor for designing wireframe graphics used in all
applications. Although this editor is somewhat limited, it has made it
easy to create
good looking icons and manipulators. Seduce only requires St and Betray
to compile, and can be used for non-Verse related applications (in fact
I have
frequently used it for demos and rendering research projects).
</p>
<h3><a name="mod-persuade">Persuade</a></h3>
<p>
Persuade is a rendering library, and is currently under construction.
It uses <a href="http://www.opengl.org/">OpenGL</a> to draw Verse
data. It also includes subdivision geometry code, and shading code
using the OpenGL Shading Language. Persuade can be used to draw whole
Verse scenes, but can also be used to draw a specific geometry node, or
to get an OpenGL handle to a texture provided by Verse.
Persuade requires Enough and Verse to compile. It has a built-in
"kernel" with a task manager that does all the computations. All
computations are chopped up in small blocks that are computed one by one.
This means that if something needs to be computed that is quite demanding,
it will have to be split up, and won't lock up the computer. This ensures
continuous smooth framerates, regardless of how much has to be done in the
background.
</p>
<p>
Persuade is currently in development and is somewhat less than stable. Therefore, you
can compile applications that use it without it simply by removing all the Persuade
files and replace <tt>persuade.h</tt> with an empty <tt>persuade.h</tt> file (the
<tt>persuade.h</tt> file contains the define <code>PERSUADE_H</code>, which if not
defined, will cause the code using Persuade to be removed by <code>ifdef</code>:s).
</p>
<h2><a name="building">Building</a></h2>
<p>
To build one of the applications, compile and link all module files (including Verse)
with the files for the applications you want to build. Although the modules can be
compiled as separate libraries, I find easier to build them all at once. I keep them
in one large project, it helps when debugging and lets me have access to the entire
source base at any time.
</p>
<h3><a name="building-deps">Dependencies</a></h3>
<p>
All applications use the same set of external libraries:
</p>
<ul>
<li>Standard C library</li>
<li>Sockets (wsock32.lib on windows)</li>
<li>OpenGL</li>
<li>GLUT, GLFW or SDL (Betray back-end)</li>
</ul>
<h3><a name="building-appspec">Application specific code</a></h3>
<p>
Most of the application code is very straightforward. Each application
has a main .c file where you will find the main function. Each
application then hands a
function pointer to Betray, which will be the action function. In most
applications this
is initially the function for the connect/login/splash screen.
Later, when the application
is connected, it gives Betray the action function that
will drive the application. These main functions are found in the <tt>xx_input_handle.c</tt>
files. These
are possibly the most important files of the application. Here you will
find the main file that handles the user's actions and uses
all the functionality of
the application. Again, note that an action function is called three
times per
frame; once to draw, once to activate functionality and once for pure
computational updates.
</p>
<h3><a name="building-codestyle">Code style</a></h3>
<p>
My coding style is best described by seeing it. If you are adding to or
modifying the code, I would appreciate it if you kept the style
consistent. In
general I try to keep all
names descriptive, preferring <code>vertex_count</code> over <code>vc</code>. This
does result in rather wide code, but I think it is important to keep it
readable.
</p>
<p>
All functions, structures and typedefs should start with the first
letter of the module that they reside in. This makes it easy to tell
from what module a
function is taken. Functions, structure members, and variables are
written in lowercase with underscores as dividers. Functions that
are used as function
pointers get the suffix <code>_func</code>. Typedef:ed types are written in
lowercase without any spaces. Macros, defines and enum members are all
written in uppercase
with underscores as spaces. Enum members should also have a
sub-category that defines in which enum they are defined. Structures
and enum types are written in lowercase with lowercase letters, but
instead of underscores, the first
letter in each word is in uppercase.
</p>
<p>
Examples for the fictitious module "Leuq":
</p>
<pre class="code">
typedef unsigned int luint;
typedef struct{
float silly;
int very_silly;
void *noughty_bits;
}LMySillyStruct;
extern void l_my_hair_dryer(LHair *hair, float time);
extern void l_cut_short_func(LHair *hair, void *user); /* function used as pointer */
#define L_THERE_ARE_TOO_FEW_VERSE_APPS TRUE
typedef struct{
L_MSE_ONE_WAY,
L_MSE_OR_AN_OTHER
}LMySillyEnum;
</pre>
<p>
I use a tab size of 4 in my editor.
</p>
<h2><a name="api">Module API Reference</a></h2>
<h3><a name="api-enough">Enough</a></h3>
<p>
Enough is a simple storage library that stores all incoming data from
Verse. To send data changes back to Verse, the normal Verse API (in
verse.h) is
used. Enough stores
the data in a fairly simplistic way. It does not sort the data or
prepare it for any specific use. Therefore, if you use Enough you
are likely to need to
write a data conversion code on top of it.
</p>
<p>
OK, let's start looking at the API.
</p>
<h4><a name="api-enough-con">Managing Connections</a></h4>
<p>
To initialize you first need to run:
</p>
<pre class="code">
extern void enough_init(void);
</pre>
<p>
Enough can manage more than one connection, and lets you switch between all existing connections. You need to use Enough's connect command
rather than the regular Verse connection command. So use:
</p>
<pre class="code">
extern uint e_vc_connect(char *server_address, char *name, char *pass);
</pre>
<p>
Once you have sent the connection you can test to see if you got a connection.
</p>
<pre class="code">
extern boolean e_vc_check_connected(void);
extern boolean e_vc_check_connected_slot(uint connection);
extern boolean e_vc_check_accepted_slot(uint connection);
</pre>
<p>You disconnect using one of these functions:
</p>
<pre class="code">
extern void e_vc_disconnect(uint connection);
extern void e_vc_disconnect_all(void);
</pre>
<p>
To "update" the network, and to switch to a different connection, you
need to run:
</p>
<pre class="code">
extern void e_vc_set_current_active_connection(uint connection);
extern void e_vc_connection_update(uint connection, uint time);
</pre>
<p>
By default Enough will download all node types but you can control the
downloading of individual types by calling:
</p>
<pre class="code">
void e_vc_set_auto_subscribe(VNodeType type, boolean set);
</pre>
<h4><a name="api-enough-nodes">Node Handling</a></h4>
<p>
All nodes are handled using the <code>ENode</code> type. The basic way of getting
a node is with one of these functions:
</p>
<pre class="code">
extern ENode *e_ns_get_node(uint connection, uint node_id);
extern ENode *e_ns_get_node_next(uint id, uint connection, VNodeType type);
extern ENode *e_ns_get_node_avatar(uint connection);
extern ENode *e_ns_get_node_link(ENode *parent, uint node_id);
</pre>
<p>
You can get the number of nodes of any type by calling:
</p>
<pre class="code">
extern uint e_ns_get_node_count(uint connection, VNodeType type);
</pre>
<p>
Once you have a node you can read out data from it by calling:
</p>
<pre class="code">
extern uint e_ns_get_node_id(ENode *node);
extern VNodeType e_ns_get_node_type(ENode *node);
extern uint e_ns_get_node_owner(ENode *node);
extern char * e_ns_get_node_name(ENode *node);
extern uint e_ns_get_node_connection(ENode *node);
</pre>
<p>
Remember that any <code>ENode</code> or underlying data or pointers become invalid
every time you call network update. This is because the nodes may have
been
deleted or changed. Therefore, you have to store the node IDs and then
look up
the node again.
</p>
<p>
Some data like geometry and bitmap layers will not be subscribed to
until the user requests it. Thus, if you want to use Enough to write
a saver, you can't just connect, wait a while and then traverse the
data.
When you receive the data you need to traverse the layers and ask
Enough for
pointers to the data. The first time they are requested they will
return pointers pointing to blank data, but then they will start
filling up as Enough
requests the data from the server. If you are writing an application
that is connected to a host for a long time, this is very natural
behavior.
</p>
<h4><a name="api-enough-cdata">Custom data</a></h4>
<p>
When you use Enough you may still need to store your own custom data.
Enough provides various functions to do this.
</p>
<pre class="code">
extern void e_ns_set_custom_data(ENode *node, uint slot, void *data);
extern void * e_ns_get_custom_data(ENode *node, uint slot);
</pre>
<p>They can be used to store pointers for each node. There are 16
different
slots for each node. It is recommended that you use a <code>define</code>
for
the slot IDs you use to store your data. This makes it easier to
change slots if you want to merge your code with other codebases that
use
Enough for storage. However, this is not enough. If the node is
deleted, the slots will disappear and you will have a memory leak.
Therefore,
use this function:
</p>
<pre class="code">
typedef enum{
E_CDC_CREATE,
E_CDC_STRUCT,
E_CDC_DATA,
E_CDC_DESTROY
}ECustomDataCommand;
extern void e_ns_set_custom_func(uint slot, VNodeType type, void (*func)(ENode *node, ECustomDataCommand command));
</pre>
<p>
This lets you assign callbacks that will be called whenever a node is
created, destroyed or updated. This lets you write service functions
that keep your
custom data synced with Verses data.
</p>
<p>Additionally, each node has two version numbers that can be used to
tell if a node has been updated or not.
</p>
<pre class="code">
extern uint e_ns_get_node_version_struct(ENode *node);
extern uint e_ns_get_node_version_data(ENode *node);
</pre>
<p>
The data version is updated if there is any change to the node at all,
while the structure version will only be updated if there is a
structural
change.
For instance, a new vertex will result in a structural update, while
moving an existing vertex will only be considered a data update. You
can also force updates of these version numbers yourself by calling:
</p>
<pre class="code">
extern void e_ns_update_node_version_struct(ENode *node);
extern void e_ns_update_node_version_data(ENode *node);
</pre>
<p>
On top of all this functionality, Enough provides yet another callback:
</p>
<pre class="code">
extern void e_ns_set_node_create_func(void (* func)(uint connection, uint id, VNodeType type, void *user), void *user);
</pre>
<p>
This callback is called whenever your connection receives a node creation
command for a node that you have asked to be created. This is useful if you
write an application that creates a node and then automatically want to
add more data to it.
</p>
<p>
Similarly to the node graph, you can store custom
data in the material graph and register update callbacks with these
calls:
</p>
<pre class="code">
extern uint e_nsm_get_fragment_version(ENode *node, VNMFragmentID id);
extern void e_nsm_set_custom_data(ENode *node, VNMFragmentID frag, uint slot, void *data);
extern void * e_nsm_get_custom_data(ENode *node, VNMFragmentID frag, uint slot);
extern void e_nsm_set_custom_func(uint slot, void (*func)(ENode *node, VNMFragmentID frag, ECustomDataCommand command));
</pre>
<h4><a name="api-enough-ndata">Node data</a></h4>
<p>
This is very brief documentation and most of the functionality is
self-explanatory if you know how Verse works. However, there are
some things to explain.
Layers and other data have their own handles:
</p>
<pre class="code">
typedef void EObjLink;
typedef void EGeoLayer;
typedef void EBitLayer;
typedef void ECodeBuffer;
</pre>
<p>
They are obtained just like ENode handles, using the same types of
functions.
</p>
<p>
All of them have functions named <code>_next</code>, which will give you the next
available handle that has the same or higher ID as the one given. This
allows you to easily iterate over all nodes or layers. Here is an
example of a loop that
gives you all object nodes.
</p>
<pre class="code">
ENode *node;
for(node = e_ns_get_node_next(0, 0, V_NT_OBJECT);
node != NULL;
node = e_ns_get_node_next(e_ns_get_node_id(node) + 1, 0, V_NT_OBJECT)
{
/* ... process the node here ... */
}
</pre>
<p>
Some data types don't have their own C-level types and only IDs are
used. They have similar <code>_next</code> functions. Here is an example of going
through
all tag groups of a node:
</p>
<pre class="code">
for(id = e_ns_get_next_tag_group(node, 0);
id != (uint16) -1;
e_ns_get_next_tag_group(node, id + 1))
{
/* ... process the tag group here ... */
}
</pre>
<h4><a name="api-enough-nspec">Special Node Functions</a></h4>
<p>
These are functions that are node-specific, i.e. they work only on
certain types
of nodes.
</p>
<h5><a name="api-enough-nspec-g">Geometry Node</a></h5>
<p>
When adding new vertices and polygons to a geometry node,
one needs empty IDs. To find such IDs, use these functions:
</p>
<pre class="code">
extern uint e_nsg_find_empty_vertex_slot(ENode *node, uint start);
extern uint e_nsg_find_empty_polygon_slot(ENode *node, uint start);
</pre>
<p>
Use the <code>start</code> parameter if you need to more than one ID. A typical
loop to obtain ten IDs can look like this:
</p>
<pre class="code">
uint ids[10], i;
ids[0] = e_nsg_find_empty_vertex_slot(node, 0);
for(i = 1; i < 10; i++)
ids[i] = e_nsg_find_empty_vertex_slot(node, ids[i - 1]);
</pre>
<h5><a name="api-enough-nspec-b">Bitmap Node</a></h5>
<p>
The bitmap node has the same type of functions as the other nodes, but
it also has some extra functionality for reading out colors from
layers.
All you need to do is to get a handle, and then use that to read out a
color at any UV coordinate. The functionality will handle layer
searching,
data conversion, pixel filtering and pixel lookup. Here is an
example:
</p>
<pre class="code">
EBMHandle *my_handle;
EBMPrecision my_pixel[3];
my_handle = e_nsb_get_image_handle(node_id, "col_r", "col_g", "col_b");
for(i = 0; i < 200; i++)
{
e_nsb_evaluate_image_handle_tile(my_handle, my_pixel, u, v, w);
...
}
e_nsb_destroy_image_handle(my_handle);
</pre>
<p>
The image handle doesn't ever become invalidated and will work even if
the
node gets deleted or if layers are created, deleted, or have their
names or types changed.
</p>
<h3><a name="api-betray">Betray</a></h3>
<p>
Betray has a very simple API, which is very straightforward and should
be easy use.
</p>
<p>
This code switches Betray between using GLUT, GLFW, or SDL (only one
should be <code>define</code>d before building):
</p>
<pre class="code">
/*#define BETRAY_SDL_SYSTEM_WRAPPER*/
/*#define BETRAY_GLFW_SYSTEM_WRAPPER*/
#define BETRAY_GLUT_SYSTEM_WRAPPER
</pre>
<p>
Here are the three modes that the action function can be called in:
</p>
<pre class="code">
typedef enum{
BAM_DRAW,
BAM_EVENT,
BAM_MAIN
}BActionMode;
</pre>
<p>
This structure is the main structure given to the action function. It
contains all of the input data.
</p>
<pre class="code">
typedef struct{
boolean mouse_button[DEVICE_BUTTONS_COUNT];
boolean last_mouse_button[DEVICE_BUTTONS_COUNT];
float pointer_x;
float pointer_y;
float click_pointer_x;
float click_pointer_y;
float delta_pointer_x;
float delta_pointer_y;
BButtonEvent event[16];
uint event_count;
double time;
BActionMode mode;
}BInputState;
</pre>
<p>
The <code>mouse_button</code> member tells you whether or not a button
is pressed, with the following index mapping:
</p>
<table class="table">
<tbody>
<tr>
<th>Index</th>
<th align="left">Describes</th>
</tr>
<tr>
<td align="center">0</td>
<td>Left mouse button</td>
</tr>
<tr>
<td align="center">1</td>
<td>Middle mouse button</td>
</tr>
<tr>
<td align="center">2</td>
<td>Right mouse button</td>
</tr>
</tbody>
</table>
<p>
The <code>last_mouse_button</code> field stores the value of the last
frame's <code>mouse_button</code> value. This makes it possible
to do tests like this to check for a button press:
</p>
<pre class="code">
if(index->mouse_button[0] == TRUE && input->last_mouse_button[0] == FALSE)
{
/* ... process press here ... */
}
</pre>
<p>
The current position of the mouse is stored in <code>pointer_x</code>
and <code>pointer_y</code>,
while <code>click_pointer_x</code> and
<code>click_pointer_y</code> are the position of the mouse the last
time the left mouse button wasn't pressed. For movement,
<code>delta_pointer_x</code> and <code>delta_pointer_y</code> are the
delta movement of the pointer from the last frame.
The <code>event</code> and <code>event_count</code> fields contain
all key presses since the last frame.
</p>
<pre class="code">
extern void betray_init(int argc, char **argv, uint window_size_x, uint window_size_y, boolean window_fullscreen, char *name);
</pre>
<p>Initializes Betray and creates a window.
</p>
<pre class="code">
extern void betray_action(BActionMode mode);
</pre>
<p>
Runs the current action function in a specific made (for testing
mostly)
</p>
<pre class="code">
extern void betray_set_action_func(void (*input_compute_func)(BInputState *data, void *user_pointer), void *user_pointer);
</pre>
<p>
Sets the action function.
</p>
<pre class="code">
extern void betray_set_mouse_warp(boolean warp);
</pre>
<p>
Turn on or of the wrapping of the mouse, for applications that don't
use the
pointer (FPS type of controls) use the delta pointer field to read the
mouse input.
</p>
<pre class="code">
extern void betray_execute(char *command);
</pre>
<p>
Used to execute a program outside the code.
</p>
<pre class="code">
extern float betray_get_time();
</pre>
<p>
Gives you the current time.
</p>
<pre class="code">
extern void * betray_get_gl_proc_address();
</pre>
<p>Gives you a pointer to the function used to retrieve OpenGL
extension functions.
</p>
<pre class="code">
extern boolean betray_get_key(uint key);
</pre>
<p>
Gives you a simple way to check if a key is pressed.
</p>
<pre class="code">
extern void betray_get_key_up_down(boolean *press, boolean *last_press, uint key);
</pre>
<p>
Gives you the ability to read out a continuous state of a key, mouse
button style.
</p>
<pre class="code">
extern BInputState * betray_get_input_state();
</pre>
<p>
Gives you the input state if you have lost it, (used in Seduce to avoid
input parameters).
</p>
<pre class="code">
extern void betray_reshape_view(uint x_size, uint y_size);
</pre>
<p>
</p>
<pre class="code">
extern boolean betray_set_screen_mode(uint x_size, uint y_size, boolean fullscreen);
</pre>
<p>Sets the window size, or changes to a specific screen mode.
</p>
<pre class="code">
extern double betray_get_screen_mode(uint *x_size, uint *y_size, boolean *fullscreen);
</pre>
<p>Gives you the current screen size. It
returns the aspect, and allows any of the arguments to be <code>NULL</code>.
</p>
<pre class="code">
extern void betray_start_type_in(char *text, uint size, void (*done_func)(void *user, boolean cancel), uint *cursor, void *user_pointer);
</pre>
<p>Starts the type-in mode. The Betray library has special input
functionality to handle text
editing. Here, <code>text</code> is a pointer to the buffer that is
being
edited; <code>size</code> is the size of that buffer; <code>cursor</code>
is a pointer to an int where the position of the editing cursor in the
buffer is stored; <code>done_func</code> is a pointer to a function
that will be called once the user presses enter or the following
function is called:
</p>
<pre class="code">
extern void betray_end_type_in_mode(boolean cancel);
</pre>
<p>Ends the type-in mode, and calls the callback function provided when
it was started.
</p>
<pre class="code">
extern boolean betray_is_type_in();
</pre>
<p>Checks whether you are in the type-in mode.
</p>
<pre class="code">
extern void betray_launch_main_loop(void);
</pre>
<p>Starts the main loop.</p>
<pre class="code">
extern void betray_get_current_time(uint32 *seconds, uint32 *fractions);
extern double betray_get_delta_time();
</pre>
<p>
Two functions to read the time independent of Verse, although you
should use Verse timer API if you are timing anything like animation in
the interface
(too bad I haven't used in the applications so all the timing on the
animation is all screwed up...). They also work before you have a
connection.
</p>
<p><code>betray_get_current_time()</code> works just like the timer
function in Verse. For inter-frame timing, <code>betray_get_delta_time()</code>
returns
the fraction of a section since the last drawn frame.
</p>
<h3><a name="api-seduce">Seduce</a></h3>
<p>
Seduce is the module that provides basic functionality for user
interface construction and management.
</p>
<p>
To initialize Seduce call:
</p>
<pre class="code">
extern void sui_init(void);
</pre>
<p>
To draw a mouse pointer call:
</p>
<pre class="code">
extern void sui_draw_pointer(float x, float y);
</pre>
<p>
To help create quadratic buttons or click areas, these functions check
if the
mouse pointer is or was inside an area:
</p>
<pre class="code">
extern boolean sui_box_click_test(float x_pos, float y_pos, float x_size, float y_size);
extern boolean sui_box_down_click_test(float x_pos, float y_pos, float x_size, float y_size);
</pre>
<p>
The perhaps largest functionality of Seduce is the built in vector line
editor. They are arguably not very good and
have been modified many times. A rewrite would not be a bad thing, but
since
this is something only I have needed to use, the functionality is
manageable. To run the editor, pass one of the
following functions as action functions to Betray.
</p>
<pre class="code">
extern void * sui_symbol_editor_func(BInputState *input, void *user_pointer);
extern void * sui_font_editor_func(BInputState *input, void *user_pointer);
</pre>
<p>
Once long ago there was an other module called NGL that wrapped
OpenGL. It has since been removed, but GL code can be quite verbose,
so in order to not make the code five times bigger, I wrote a set of
very simple
functions to handle basic drawing using the GL. If you want the
details I suggest you look at the code itself.
</p>
<p>Anyhow to draw geometry, call:
</p>
<pre class="code">
extern void sui_draw_gl(uint draw_type, float *array, uint length, uint dimensions, float red, float green, float blue);
extern void sui_draw_elements_gl(uint draw_type, float *array, uint reference, uint length, uint dimensions, float red, float green, float blue);
</pre>
<p>
To draw simple lines, call:
</p>
<pre class="code">
extern void sui_draw_2d_line_gl(float start_x, float start_y, float end_x, float end_y, float red, float green, float blue);
extern void sui_draw_3d_line_gl(float start_x, float start_y, float start_z, float end_x, float end_y, float end_z, float red, float green, float blue);
</pre>
<p>
To set blending mode, call:
</p>