File format specification for: ---------------------------------------------------------------- Ovo Vector Object (.ovo) Format version: 1 Author: the Oddwarg Date: 2021-04-24 An Ovo Vector Object (.ovo) file contains a single vector object, typically a 3D model. The object consists of metadata, vertices, group relationships and primitives to be assembled from the vertices. Example file: #File name: test.ovo METADATA 3 ovo_version:1 name:Test mtllib:test.mtl VERTEX_GROUPS 2 0; Foo 1; Bar VERTICES [v:2 n:3 t0:2] 4 0; -1 -1 0 0 1 0 0 [0:1] 1; 1 -1 0 0 1 1 0 [0:1 1:0.5] 2; -1 1 0 0 1 0 1 [0:0.5 1:1] 3; 1 1 0 0 1 1 1 [1:1] PRIMITIVE_GROUPS 2 0; PlainMaterial 1; SomeGroup PRIMITIVE_LISTS 1 TRIANGLES [0 1] 6 0 1 2 2 1 3 The feature set defined by the .ovo file format can be leveraged to implement features such as: -Rendering models with several materials -Multitexturing and vertex colours -Skinning (armature deformation) -Rendering triangles, triangle strips, lines, etc. -Index buffer rendering --------------------------- Overview --------------------------- .ovo files are plaintext. The format is designed with human inspection and limited manual editing in mind. However, it is not recommended to write .ovo files from scratch by hand. On the other hand, the .ovo file format is specifically designed to be simple to parse line by line using string and array manipulation. .ovo files define data structures that are naturally suited to indexed rendering (Index Buffers in Direct3D or Index Buffer Objects in OpenGL). Thus, the need for data restructuring after parsing should be limited or nonexistent. The data structures defined by the .ovo file format are somewhat flexible. Applications are encouraged to only support the configurations that they require, ignore irrelevant data, and document this well. --------------------------- Comments --------------------------- .ovo files can contain two types of comments that can appear on any line: I. Trailing comments. These appear at the end of the line, starting at the _last_ '#' character. Example: #File name: test.ovo II. Leading comments. These appear at the start of a line and end with the _first_ ';' character. Example: 0; Note that trailing comments take precedence: If the first ';' on a line appears after the last '#', then it does not count as a leading comment. By convention, the vertex group list, vertex list and primitive group list should have the element index prefixed as a leading comment on each line. ---------------------------- Spaces ---------------------------- .ovo importers should recognize any non-empty sequence of space characters (' ') and/or tabs as a space. Spaces at the start and end of a line should be ignored, and spaces between elements should be trimmed. ---------------------------- Names ----------------------------- .ovo files can define various names. It is recommended to avoid using spaces or any of the following reserved characters in names: '#', ';', ':', '[', ']'. Names cannot start or end with spaces, and cannot contain line breaks. A name may contain the character ';' only if it appears after a leading comment on the same line, and may contain '#' only if it appears before a trailing comment on the same line. Doing this is allowed in a pinch, but discouraged. Some names may not contain interior spaces characters or any of the characters ':', '[' and ']'. The restricted cases are documented below. ---------------------------- Numbers --------------------------- .ovo files should use decimal numbers with '.' as the radix point. Negative numbers start with a single '-'. Positive numbers should not have a prefix. All numbers should have an integer part consisting of one or more decimal digits (0-9). The radix point and fractional part are optional, but if they are present then the fractional part should consist of one or more decimal digits. Numbers that are specifically stated to be integers must not have a radix point or a fractional part. ---------------------------- Blocks ---------------------------- .ovo files are organized in blocks. The first line of a block starts with the block type and ends with information about the block. The block types are described below. A block type may not appear more than once. A. METADATA Contains a map of data about the Ovo Vector Object itself. METADATA must be followed by a space, then an integer equal to the number of lines to follow in the block. Each line must contain exactly one key:value pair or just a key. Both keys and values are names. Keys cannot contain ':'. Example: METADATA 3 ovo_version:1 name:Test mtllib:test.mtl The meaning of the object metadata is application-defined, but the following conventions exist: -ovo_version: The format version used by the file -name: The name of the object -mtllib: A relative path to a file with materials The METADATA block is optional. If it is present, it must be the first block in the file. B. VERTEX_GROUPS Contains the list of vertex groups. A vertex group represents a logical group of vertices. The relationship between vertices and vertex groups is many-to-many, and each relation has a numeric weight. VERTEX_GROUPS must be followed by a space, then an integer equal to the number of lines to follow in the block. Each line must contain exactly one vertex group. A vertex group is a name. Vertex groups are indexed, starting from 0, in the order they appear in this list. Example: VERTEX_GROUPS 2 0; Foo 1; Bar Weighted relations between vertices and vertex groups are defined in the VERTICES block, explained below. Vertex groups are typically used to implement skinning, wherein a vertex group represents an animation bone. The amount of influence a bone has on a vertex is given by the weight of the relation between the vertex and the bone (zero if there is no relation). However, the meaning of vertex groups is ultimately application-defined. The VERTEX_GROUPS block is optional. If it is present, it must be before VERTICES. C. VERTICES Contains the vertex attribute layout and the list of vertices. A vertex typically has a position and may include other attributes, such as normals, colors or texture coordinates. VERTICES must be followed by a space, then the vertex attribute layout, then a space, then an integer equal to the number of lines to follow in the block. Each line must contain exactly one vertex. Example: VERTICES [v:2 n:3 t0:2] 4 0; -1 -1 0 0 1 0 0 [0:1] 1; 1 -1 0 0 1 1 0 [0:1 1:0.5] 2; -1 1 0 0 1 0 1 [0:0.5 1:1] 3; 1 1 0 0 1 1 1 [1:1] C.I Vertex attribute layout Vertex data is made up of vertex attributes such as the vertex position. The vertex attribute layout defines which attributes are included in the vertex list and their layout. The vertex attribute layout is a space-separated list of attributeName:componentCount pairs, enclosed in square brackets. The pairs may not contain spaces. -attributeName is a name. It cannot contain spaces nor any of the characters '[', ']' or ':'. An attribute name must not occur more than once in the vertex attribute layout. -componentCount is an integer, typically between 1 and 4, specifying how many numbers are reserved for this attribute in the vertex data for each vertex. Applications may define their own vertex attributes, but the following conventions are used for common attributes: Vertex attribute Name Component count Vertex position v 2-4, typically 3 Normal n 3 Texture coordinate t or t0 1-4, typically 2 Vertex colour c 3 (rgb) or 4 (rgba) If multiple texture coordinate attributes are included, then these should be named t0, t1 ... tn. C.II Vertex list The vertex list consists of one vertex on each line. A vertex consists of vertex data optionally followed by vertex group relations. Vertices are indexed, starting from 0, in the order they appear in this list. The vertex data is a space-separated list of numbers. For each vertex attribute, there is a subsequence of N numbers, where N is that vertex attribute's componentCount. These subsequences appear in the order that the vertex attributes were listed. The total length of this list is equal to the sum of componentCounts for all vertex attributes. For example, if the vertex attribute was "v:3", then the first 3 numbers on a line can be assumed to be the x, y, and z coordinates for the vertex on that line. The vertex group relations, if present, is a space-separated list of groupIndex:groupWeight pairs, enclosed in square brackets. The pairs may not contain spaces. Each pair defines a relation between the vertex on the current line to a given vertex group. -vertexGroupIndex is an integer specifying the index of the vertex group that the relation pertains to. It is an error to specify an index for a vertex group that does not exist. -vertexGroupWeight is a number specifying the weight of the relation, typically between 0 and 1. The VERTICES block is mandatory and must appear before PRIMITIVE_LISTS. D. PRIMITIVE_GROUPS Contains the list of primitive groups. A primitive group represents a logical group of primitives. PRIMITIVE_GROUPS must be followed by a space, then an integer equal to the number of lines to follow in the block. Each line must contain exactly one primitive group. A primitive group is a name. Primitive groups are indexed, starting from 0, in the order they appear in this list. Example: PRIMITIVE_GROUPS 2 0; PlainMaterial 1; SomeGroup Primitive lists can refer to primitive groups by index, as explained in the next section. The meaning of primitive groups is application-defined, but they typically represent materials. This block is optional. If it is present, it must appear before PRIMITIVE_LISTS. E. PRIMITIVE_LISTS Contains primitive lists. A primitive is a fundamental type of graphical shape, such as a triangle. A primitive list defines the assembly of one or several primitives by specifying a primitive mode and a list of vertex indices. PRIMITIVE_LISTS must be followed by a space, then an integer equal to the number of primitive lists to follow. The first primitive list must start on the next line. A primitive list is a sub-block starting with a primitive mode, followed by a space, then optionally primitive group memberships and another space, then the index count. The index count is an integer equal to the number of indices to follow in the index list. The index list starts on the next line. Primitive lists must be separated by a single line break. Example: PRIMITIVE_LISTS 1 TRIANGLES [0 1] 6 0 1 2 2 1 3 E.I Primitive modes A primitive mode represents a method of assembling a sequence of vertices into a one or several primitives (graphical shapes). A primitive mode is a name that must not contain spaces, '[' or ']'. By convention, it should be written in capital letters. The most common primitive mode is TRIANGLES. It should be supported by most applications. For a description of TRIANGLES and some other conventional primitive modes, see appendix 1. Any number of primitive lists may use the same primitive mode. E.II Primitive group memberships The primitive group memberships is a space-separated list of primitive group indices (integers), enclosed in square brackets. Each index is the index of a primitive group that the current primitive list is a member of. It is an error to include a primitive group index for a primitive group that does not exist. By convention, the first primitive group that a primitive list is a member of should represent a material to use when drawing the primitives produced by the primitive list. E.III Index list The index list is a list of vertex indices (integers) that is separated by spaces and/or a single line break. The total number of items is given by the primitive list's index count. Primitives are produced by letting each vertex index act as a substitute for the vertex with the same index in the vertex list, and using the method represented by the primitive mode to assemble primitives from those vertices. Example: The example file in this document specifies one primitive list, whose primitive mode is TRIANGLES and index list is 0 1 2 2 1 3. The vertex list contains 4 vertices, each with a 2D position: vertex index x y 0 -1 -1 1 1 -1 2 -1 1 3 1 1 Thus, the triangles produced would be as follows: vertex corner positions indices first second third x y x y x y First Triangle 0 1 2 -1 -1 1 -1 -1 1 Second Triangle 2 1 3 -1 1 1 -1 1 1 Illustration: -1,-1 1,-1 0_______________1 | /| | First / | | Triangle / | | / | | / | | / Second | | / Triangle | |/______________| 2 3 -1,1 1,1 For how to implement this efficiently in a renderer, look up Index Buffers (Direct3D) or Index Buffer Objects (OpenGL). The PRIMITIVE_LISTS block is mandatory and must be the last block in the file. --------------------------- Appendix --------------------------- 0. Standard winding order conventions: coordinate system type standard winding order left-handed clockwise right-handed counterclockwise 1. Conventional primitive modes: -POINTS Each vertex is rendered as a separate point. -LINES Lines are drawn using a sequence of vertex pairs: Between the 1st and 2nd vertex, then 3rd and 4th, etc. -LINE_STRIP From the 2nd vertex on, lines are drawn between the two most recent vertices: The 1st and 2nd vertex, then 2nd and 3rd, etc. -LINE_LOOP Like LINE_STRIP, but an additional line is drawn between the last and first vertex. -TRIANGLES Triangles are drawn using a sequence of vertex triads: 1st, 2nd and 3rd vertex, then 4th, 5th and 6th, etc. By convention, the vertices of a triangle are given in the standard winding order. -TRIANGLE_STRIP From the 3rd vertex on, triangles are drawn using the 3 most recent vertices, with every other triangle being reversed: The 1st, 2nd and 3rd vertex, then 3rd, 2nd and 4th, then 3rd, 4th and 5th, then 5th, 4th and 6th, etc. Triangles with even indices (starting with triangle 0) use the standard winding order. Odd triangles use the opposite winding order. -TRIANGLE_FAN From the 3rd vertex on, triangles are drawn using the first and two most recent vertices: The 1st, 2nd and 3rd vertex, then the 1st, 3rd and 4th, and so forth. -QUADS Quadrilaterals are drawn using a sequence of vertex tetrads: 1st, 2nd, 3rd and 4th vertex, then 5th, 6th and 7th and 8th, etc. The vertices of a quad are given in the standard winding order. Typical systems will draw a quadrilateral as two conjoined triangles. -POLYGON A polygon is drawn using the entire list of vertices as its corners. The vertices of a polygon are given in the standard winding order. Typical systems only support convex polygons. 2. License Permission is hereby granted, free of charge, to any person obtaining a copy of this document, to deal in the document without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the document, and to permit persons to whom the document is furnished to do so, subject to the following conditions: This permission notice shall be included in all copies or substantial portions of the document.