Saving and Loading Files
[
278 
]
Developers may design their plugin features and behaviors according to different op瑩on 
strings. Note that the op瑩on object is set and passed in the 
r
e
a
d
N
o
d
e
F
i
l
e
(
)
func瑩on, so 
the plugin interface may always receive a 
N
U
L
L
pointer, which means that there is no input 
op瑩ons. This is actually the default se瑴ng of 
r
e
a
d
N
o
d
e
F
i
l
e
(
)
:
Handling the data stream
The 
o
s
g
D
B
:
:
R
e
a
d
e
r
W
r
i
t
e
r
base class involves a set of stream data handling methods, 
which can also be overridden by user-defined plugins. The only difference is that the input 
filename argument is replaced by a 
s
t
d
:
:
i
s
t
r
e
a
m
&
or 
s
t
d
:
:
o
s
t
r
e
a
m
&
variable. Making 
use of the file stream is always preferred rather than directly opera瑩ng on physical files. To 
perform stream opera瑩ons when reading a file, we may design the reader-writer interface 
like this:
{
}
{
r
e
t
u
r
n
r
o
o
t
;
}
We can then use 
to load and parse the file as usual, but it 
actually creates and handles stream data in the reader-writer implementa瑩on. The problem 
here is how to directly perform opera瑩ons on some exis瑩ng streams, for instance, a string 
stream in a data buffer or transferred over the socket? As we have seen already, OSG 
doesn't define a direct user interface, like the famous 
and 
, for analyzing streams.
Break password pdf - Split, seperate PDF into multiple files in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Explain How to Split PDF Document in Visual C#.NET Application
break up pdf into individual pages; pdf link to specific page
Break password pdf - VB.NET PDF File Split Library: Split, seperate PDF into multiple files in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
VB.NET PDF Document Splitter Control to Disassemble PDF Document
break a pdf file; can't cut and paste from pdf
Chapter 10
[
279 
]
A solu瑩on is to retrieve a specific reader-writer and use it to parse the current stream in the 
buffer, using the 
method of 
o
s
g
D
B
:
:
R
e
g
i
s
t
r
y
The obtained reader-writer must have implemented the stream opera瑩ng interface, and 
the developer himself must ensure that the stream data format corresponds to the parser's 
specifica瑩on defini瑩on. This means that a 3Ds reader-writer must only be used to read a 3Ds 
format stream; otherwise a not-so-well-wri瑴en plugin may even cause a system crash when 
trying to explain unpredictable data.
Example code for reading stream data with the 
o
s
g
d
b
_
o
s
g
plugin is as follows:
i
f
(
r
w
)
{
}
The 
n
o
d
e
variable can be used as the loaded scene graph later. The 
s
u
c
c
e
s
s
(
)
and 
t
a
k
e
N
o
d
e
(
)
methods read status informa瑩on and the stored 
o
s
g
:
:
N
o
d
e
pointer from 
the read result.
Time for action – designing and parsing a new file format
We will design a new file format and create the I/O plugin for it in this example. Its format 
specifica瑩on should be simple enough so that we won't take much 瑩me in explaining the 
usage and parsing it to a scene graph.
The new format will only focus on quickly crea瑩ng triangle strips—that is, a series of 
connected triangles with 
N
+
2
shared ver瑩ces, where 
N
is the number of triangles to be 
drawn. The file is in text format, and has one extension, 
.
t
r
i
, which means triangle file 
format. The total number of ver瑩ces will always be wri瑴en at the first line of every 
.
t
r
i
file. The following lines provide the ver瑩ces data fields. Each vertex is stored as three float 
values in a row. An example of the content of the new format is as follows:
8
0
0
10 0 0
0
0
11 0 1
0
0
12 0 2
0
0
13 0 3
C# PDF Convert: How to Convert Jpeg, Png, Bmp, & Gif Raster Images
Success"); break; case ConvertResult.FILE_TYPE_UNSUPPORT: Console.WriteLine("Fail: can not convert to PDF, file type unsupport"); break; case ConvertResult
break pdf file into multiple files; pdf insert page break
C# Image Convert: How to Convert Word to Jpeg, Png, Bmp, and Gif
RasterEdge.XDoc.PDF.dll. FileType.IMG_JPEG); switch (result) { case ConvertResult. NO_ERROR: Console.WriteLine("Success"); break; case ConvertResult
break a pdf file into parts; split pdf into individual pages
Saving and Loading Files
[
280 
]
Save these values to an 
e
x
a
m
p
l
e
.
t
r
i
file, which will be used later. Now it's 瑩me to start 
implemen瑩ng our reader-writer interface.
1. 
Include the necessary headers:
2. 
We would like to implement the reading methods of the new format. So two 
r
e
a
d
N
o
d
e
(
)
methods should be overridden here, one for reading data from 
files and the other for reading from streams:
{
p
u
b
l
i
c
:
c
o
n
s
t
;
}
;
3. 
In the constructor, we have to announce that the extension 
.
t
r
i
is supported 
by this plugin. Support for extensions can be added here with the same  
s
u
p
p
o
r
t
E
x
t
e
n
s
i
o
n
(
)
method:
4. 
Now we are going to implement the 
r
e
a
d
N
o
d
e
(
)
method for reading files from the 
disk. It will check if the input extension and filename are available, and try to redirect 
the content of the file into the 
s
t
d
:
:
f
s
t
r
e
a
m
object for further opera瑩ons:
c
o
n
s
{t
VB.NET PDF Page Insert Library: insert pages into PDF file in vb.
Forms. Support adding PDF page number. Offer PDF page break inserting function. Free SDK library for Visual Studio .NET. Independent
break pdf into multiple files; can print pdf no pages selected
C# PDF Page Insert Library: insert pages into PDF file in C#.net
Ability to add PDF page number in preview. Offer PDF page break inserting function. Free components and online source codes for .NET framework 2.0+.
pdf file specification; split pdf
Chapter 10
[
281 
]
}
5. 
This is the core implementa瑩on of the new file format. All that we need to do is to 
read the total number and every vertex from the data stream, and push them into 
the 
o
s
g
:
:
V
e
c
3
A
r
r
a
y
variable. A new 
o
s
g
:
:
G
e
o
m
e
t
r
y
object is then created to 
include the vertex array and related primi瑩ve object. Finally, we generate the normals 
of the geometry and return a new 
o
s
g
:
:
G
e
o
d
e
containing it as the reading result:
{
{
i
n
d
e
x
+
+
;
  }  
}
C# TWAIN - Query & Set Device Abilities in C#
device.TwainTransferMode = method; break; } if (method == TwainTransferMethod.TWSX_FILE) device.TransferMethod = method; } // If it's not supported tell stop.
split pdf into multiple files; acrobat split pdf bookmark
C# TWAIN - Install, Deploy and Distribute XImage.Twain Control
RasterEdge.XDoc.PDF.dll. device.TwainTransferMode = method; break; } if (method == TwainTransferMethod.TWSX_FILE) device.TransferMethod = method; } // If it's
cannot select text in pdf; cannot print pdf file no pages selected
Saving and Loading Files
[
282 
]
6. 
Register the reader-writer class with the following macro. This must be done for 
every OSG plugin at the end of the source file. The first parameter indicates  
the plugin library name (without the 
o
s
g
d
b
_
prefix), and the second one 
provides the class name:
7. 
Note that the output target name should be 
o
s
g
d
b
_
t
r
i
this 瑩me, and must be a 
shared library file instead of an executable. So the CMake script for genera瑩ng  
our project should use the macro 
a
d
d
_
l
i
b
r
a
r
y
(
)
to replace 
a
d
d
_
e
x
e
c
u
t
a
b
l
e
(
)
such as:
8. 
Now, start a console and run 
o
s
g
v
i
e
w
e
r
with the 
e
x
a
m
p
l
e
.
t
r
i
as the 
input filename:
9. 
The result clearly shows whether the ver瑩ces are read out correctly and form the 
geometry as triangular strips:
C# TWAIN - Specify Size and Location to Scan
foreach (TwainStaticFrameSizeType frame in frames) { if (frame == TwainStaticFrameSizeType.LetterUS) { this.device.FrameSize = frame; break; } } }.
break a pdf into smaller files; add page break to pdf
C# TWAIN - Acquire or Save Image to File
RasterEdge.XDoc.PDF.dll. if (device.Compression != TwainCompressionMode.Group4) device.Compression = TwainCompressionMode.Group3; break; } } acq.FileTranfer
pdf rotate single page; cannot print pdf no pages selected
Chapter 10
[
283 
]
W
h
a
t
j
u
s
t
h
a
p
p
e
n
e
d
?
A few u瑩lity func瑩ons are used here to judge the validity of the input filename in the 
r
e
a
d
N
o
d
e
(
)
method. The 
obtains the file 
extension, which is checked by 
a
c
c
e
p
t
s
E
x
t
e
n
s
i
o
n
(
)
of the 
o
s
g
D
B
:
:
R
e
a
d
e
r
W
r
i
t
e
r
base class. The 
func瑩on then looks for the file in possible paths 
(current and system paths). It will return the full path of the first valid file found, or an empty 
string if nothing is found.
Another important point to men瑩on is the macro 
R
E
G
I
S
T
E
R
_
O
S
G
P
L
U
G
I
N
. This 
actually defines a global variable that registers the user-defined reader-writer to the 
o
s
g
D
B
:
:
R
e
g
i
s
t
r
y
instance in the constructor. When the dynamic library is first loaded, 
the global variable is automa瑩cally allocated, and the reader-writer can be found in order  
to handle the input file or stream then.
Have a go hero – finishing the writing interface of the plugin
We have already demonstrated the reading opera瑩on of the 
.
t
r
i
format, by implemen瑩ng 
the two virtual 
r
e
a
d
N
o
d
e
(
)
methods. Now it's your turn to re-implement the 
w
r
i
t
e
N
o
d
e
(
)
methods and finish the reader-writer interface. Of course, a plugin can work 
with only the reading func瑩onality or the wri瑩ng func瑩onality, but why not make things 
perfect if we have the chance?
A customized node visitor may be used to find all 
o
s
g
:
:
G
e
o
d
e
nodes and 
geometries of a 
s
c
e
n
e
g
r
a
p
h
. You can improve the format specifica瑩on to 
support saving and loading mul瑩ple triangle strips from 
.
t
r
i
files, if necessary.
Serializing OSG native scenes
The OSG na瑩ve formats, implemented by the 
o
s
g
d
b
_
i
v
e
and 
o
s
g
d
b
_
o
s
g
plugins, are used 
for encapsula瑩ng OSG na瑩ve classes and conver瑩ng them to representa瑩ons that can be 
wri瑴en to a data stream. This makes it possible to save the scene graph to a disk file and 
read it back without missing any informa瑩on.
For example, the Cessna model is stored in a file named 
c
e
s
s
n
a
.
o
s
g
. It is actually made up 
of an 
o
s
g
:
:
G
r
o
u
p
root node, an 
o
s
g
:
:
G
e
o
d
e
child node, and an 
o
s
g
:
:
G
e
o
m
e
t
r
y
object 
with specific materials and some other rendering a瑴ributes. In a text file, it may be defined 
by the following lines:
o
s
g
:
:
G
r
o
u
p
{
Saving and Loading Files
[
284 
]
C
h
i
l
d
r
e
n
1
{
}
}
}
}}
Every scene object (node, drawable, and so on) is defined by a class name and begin and end 
brackets. The object's proper瑩es, including proper瑩es of its parent classes, are wri瑴en into a 
sequence of bits for storing in files and buffers. For example, the 
N
a
m
e
and 
D
a
t
a
V
a
r
i
a
n
c
e
fields are defined in the 
o
s
g
:
:
O
b
j
e
c
t
base class, 
U
p
d
a
t
e
C
a
l
l
b
a
c
k
is defined in 
o
s
g
:
:
N
o
d
e
, and 
C
h
i
l
d
r
e
n
is the only na瑩ve property of 
o
s
g
:
:
G
r
o
u
p
. They are all saved 
for the Cessna's root node to record all of the informa瑩on required for a complete model.
These proper瑩es can be soon reread to create a seman瑩cally-iden瑩cal clone of the original 
Cessna scene graph, according to the same sequence of bits. The process of serializing 
(wri瑩ng to a series of data) and deserializing (resurrec瑩ng the series of data) the scene graph 
is called I/O serializa瑩on. Each property that can be saved into and reread from a sequence 
is called a serializable object, or a serializer for short.
Creating serializers
The OSG na瑩ve formats, including 
.
o
s
g
.
o
s
g
b
.
o
s
g
t
, and 
.
o
s
g
x
, are extensible for saving 
to and loading from files and data streams. With the excep瑩on of the deprecated 
.
i
v
e
format, they all need special helper classes called wrappers, which wrap up primi瑩ve values 
that offer the u瑩lity methods and proper瑩es of the API's classes. When new methods and 
classes are introduced into the OSG core libraries, there should be corresponding wrappers 
for them in order to make sure that any new features can be immediately supported in the 
na瑩ve format files. The theory of serializing is extremely useful in this situa瑩on, enabling 
simple and common input/output interfaces to be u瑩lized.
The 
.
o
s
g
format has been widely used in the OSG community for many years. Almost all of 
the models referred to in this book are wri瑴en in this format. It supports only ASCII formats 
and uses a slightly complex interface for implemen瑩ng wrappers.
Chapter 10
[
285 
]
But there is another "second genera瑩on" format in development, which is well serialized, 
easy-to-extend, and even cross-format. ASCII format (
.
o
s
g
t
), binary format (
.
o
s
g
b
), and 
XML style format (
.
o
s
g
x
) files are all supported with one set of core class wrappers, in 
each of which a series of serializers are used to bind reading and wri瑩ng members. In the 
following example, we will discuss how to write wrappers for user-defined classes in your 
own applica瑩ons or dynamic libraries. The to-be-wrapped class must be derived from 
o
s
g
:
:
O
b
j
e
c
t
, and must have a namespace for the wrapper manager in osgDB to use.
All OSG predefined wrappers are stored in the 
s
r
c
/
o
s
g
W
r
a
p
p
e
r
s
directory of the source 
code. They are always a good reference for user-customized designing and programming.
Time for action – creating serializers for user-defined classes
To create serializers for a class and make it accessible from OSG na瑩ve formats, there are 
some precondi瑩ons: firstly, the class must be derived from 
o
s
g
:
:
O
b
j
e
c
t
, either directly 
or indirectly; secondly, the class must be declared in a namespace, and uses 
M
E
T
A
_
O
b
j
e
c
t
to define the correct namespace and class names; finally and most importantly, the class 
must have at least a ge瑴er and a se瑴er method for each member property, which makes it 
serializable, that is, it can be stored to OSG na瑩ve scene files and deserialized to a cloned 
scene object at any 瑩me.
1. 
Include the necessary headers:
#
i
n
c
l
u
d
e
<
i
o
s
t
r
e
a
m
>
2. 
We define the 
t
e
s
t
N
S
:
:
E
x
a
m
p
l
e
N
o
d
e
class to be serialized. It is easy to 
understand and will do nothing except record an unsigned integer number,  
_
e
x
a
m
p
l
e
I
D
. You will easily find that the se瑴er and ge瑴er methods are defined in 
strict naming conven瑩ons (the same string a晴er the 
s
e
t
or 
g
e
t
prefix, the same 
input and return value type, and a constant keyword to the ge瑴er method):
n
a
m
e
s
p
a
c
e
t
e
s
t
N
S
{
{
p
u
b
l
i
c
:
Saving and Loading Files
[
286 
]
C
O
P
Y
)
p
r
o
t
e
c
t
e
d
:
}
;
}
3. 
The 
macro is used to define a wrapper class. It has 
four arguments: the unique wrapper name, the prototype, the class name, and the  
inheritance rela瑩ons in the form of a string. The only serializer object to be added is  
the 
_
e
x
a
m
p
l
e
I
D
property. Its shared name (shared by the se瑴er and ge瑴er) 
is 
E
x
a
m
p
l
e
I
D
, and the default value is 0:
{
}
4. 
Now we enter the main entry. We hope this 瑩ny applica瑩on can demonstrate both 
the wri瑩ng and reading opera瑩ons. When the 
-
w
argument is specified, a newly-
allocated node is saved to a 
.
o
s
g
t
file (OSG na瑩ve ASCII format); otherwise the 
saved file will be loaded and the 
_
e
x
a
m
p
l
e
I
D
will be printed on the screen:
5. 
Write the 
E
x
a
m
p
l
e
N
o
d
e
node to the 
e
x
a
m
p
l
e
n
o
d
e
.
o
s
g
t
file, if there 
is a valid value that can be set with the 
s
e
t
E
x
a
m
p
l
e
I
D
(
)
method:
{
t
e
s
t
N
S
:
:
E
x
a
m
p
l
e
N
o
d
e
;
}
Chapter 10
[
287 
]
6. 
Read back the node from the same file and print the wri瑴en value with 
g
e
t
E
x
a
m
p
l
e
I
D
(
)
:
e
l
s
e{
{
}}
7. 
We will first set a 
_
e
x
a
m
p
l
e
I
D
value and write the scene graph to the 
.
o
s
g
t
file, assuming the executable name is 
M
y
P
r
o
j
e
c
t
.
e
x
e
:
8. 
A file named 
e
x
a
m
p
l
e
n
o
d
e
.
o
s
g
t
will be created in current path. Now 
let's read it back to the memory and print the stored 
_
e
x
a
m
p
l
e
I
D
:
#
M
y
P
r
o
j
e
c
t
.
e
x
e
9. 
It simply shows the value we just inpu瑴ed. It is certainly obtained when loading 
the file on the disk and reconstruc瑩ng the clone of the previous scene graph:
W
h
a
t
j
u
s
t
h
a
p
p
e
n
e
d
?
Open the 
e
x
a
m
p
l
e
n
o
d
e
.
o
s
g
t
file with any text editors. It may contain the following lines:
U
n
i
q
u
e
I
D
1
E
x
a
m
p
l
e
I
D
2
0
}
The namespace and class names are leading a block of proper瑩es, including the 
E
x
a
m
p
l
e
I
D
field which saves our input value. OSG will gain the namespace and class names and look for 
appropriate wrapper object that is already registered in the system memory. The wrapper, if 
found, will create the 
E
x
a
m
p
l
e
N
o
d
e
instance from the prototype, and then traverse every 
superclass in the inheritance rela瑩ons string to read out all of the proper瑩es (proper瑩es with 
default values will not be saved to or read from ASCII files).
Documents you may be interested
Documents you may be interested