terasology-archived / grammarsystem Goto Github PK
View Code? Open in Web Editor NEWGrammar System for procedural structure generation. Basis for the Procedural Architecture Grammar
Grammar System for procedural structure generation. Basis for the Procedural Architecture Grammar
I'm cleaning up the engine wiki and moving some doc to modules, especially if they're inactive like the grammar system. @skaldarnar save us from the lack of grammar! :-)
Old Grammar System page:
The Grammar System (or Grammar Building System) uses the [[Procedural Architecture Grammar]] to generate building structures. It
is included in versions starting from stable #22.
Building Generators are used to create a [[Block Collection]] which can then be placed in the world. For the generation process,
the structure's dimension and a proper [[grammar|Procedural Architecture Grammar]] is needed. Please refeer to the corresponding sites
for more information.
The Grammar System provides console commands to test the building generation. At the moment the system is quite restricted. You can only
call a pre defined generator with specifying width, depth and height of the building. To do so, just type
\build <width> <heigth> <depth>
in the [[Console|Console Help]]. The generated building will be placed right in front of the player.
Old PAG page:
This is a work in Progress
You read that right, this is a grammar for our grammar. That is, this defines the format for the grammars one can use for procedural generation.
PAG := Header 'grammar' Identifier ':' Section+
The PAG-Header will store information for the grammar system, such as which type of structure is created by this grammar, and provide the possibility to assign constants you can later use in the grammar rules.
Header := Declaration*
Declaration := '#'? Identifier ':=' expr ';'
A header declaration that starts with a #
will be interpreted as grammar info field, such as building type, or fitting biomes. You can define module dependencies for the grammar here as well:
#dependencies := ["myModule", "otherAwesomeModule"];
You may have noticed that different forms of expressions are allowed on the right side, we will come to that later. Simple constants can be defined in a similar way:
floor_height := 3;
Sections make up the grammar and group the grammar rules with the same priority. The priority is used to control the order in which derivations are selected. Of course it is possible to have just one section for all rules.
Section := 'Priority' decimalLiteral ':' ruleStatement+
Each ruleStatement
is of the form predecessor -> successor
. Note that every rule has to be ended by a semicolon. Furthermore, you can specify guards (boolean expressions that guard whether the rule can be applied or not) and probabilities. Guards and probabilities are optional for every rule.
ruleStatement := Predecessor (':' expression)? '->' Successor (':' expression)? ('|' Successor (':' expression)?)+ ';'
Predecessor := Identifier
The successor can either be an identifier, which denotes another rule, a base rule or a sequence of the former enclosed in braces.
Successor := Identifier | Baserule | '{' (Identifier | BaseRule)* '}'
The following set of expressions are supported by the grammar system. You can use standard Boolean and arithmetic operations, numbers (integer and decimal), identifiers and strings and lists of expressions. Furthermore, there are a few special operations/method calls.
expression := primary
| functionCall
| ('Shape' | 'Scope') '.' ('occ' | 'visible') '(' expression ')'
| '[' expression ']'
| ('+' | '-') expression
| '!' expression
| expression ('*' | '/' | '%') expression
| expression ('+' | '-') expression
| expression ('<=' | '>=' | '<' | '>') expression
| expression ('==' | '!=') expression
| expression '&&' expression
| expression '||' expression
primary := '(' expression ')' | literal 'r'? | Identifier
The only function call currently available is the random selection from either a list or a defined range.
functionCall := randomSelection
randomSelection := 'Random' '(' (exprList | rangeExpr) ')'
An expression list is simply a sequence of expressions:
exprList := expression (',' expression)*
You can define a range of integers with the following notation:
rangeExpr := expression '..' expression
E.g. you can select a random block type from a list or define a scale or measure of length randomly within a range from .. to.
wall_mat := Random("cobblestone", "stonebricks", "stone");
number_floors := Random(2..5);
The occlusion and visibility checks are useful as guards. They can be used to determine whether the current scope is occluded by any other shape or scope or if a specific shape is visible from the current scope. This can be used to place doors on walls that face to the street. Note that the occlusion test for scopes is faster but less accurate than the test against shapes.
wall : Shape.visible("street") -> door_wall;
wall : Scope.occ("nonparent") == "none" -> win_wall;
The following basic rules are supported by the grammar.
BaseRule := SetRule | DivideRule | SplitRule | RepeatRule | Invoke | TransformationRule
SetRule := 'set' '(' '"' qualifiedIdentifier '"' ')'
DivideRule := 'divide' Direction '{' ('[' Size ']' Successor)+ '}'
SplitRule := 'split' '{' ('[' SplitType ']' Successor)+ '}'
RepeatRule := 'repeat' Direction '['expression']' Successor
The invocation of other grammars is just a proposal for allowing the reuse of code. It may be erased from the specification if
it proves not to be practical.
Invoke := 'invoke' '(' qualifiedIdentifier ')'
Basic transformation of shapes is supported by the following rules.
TransformationRule := ScaleRule | TranslateRule | RotateRule
ScaleRule := 'S' '(' numericLiteral (',' numericLiteral ',' numericLiteral)? ')'
TranslateRule := 'T' '(' numericLiteral ',' numericLiteral ',' numericLiteral ')'
RotateRule := ('Rx' | 'Ry' | 'Rz') '(' numericLiteral ')'
Moreover, we need special rules for the roof construction:
Roof := 'Roof' '(' roofType ',' expression ')' '{' successor '}'
roofType := 'hipped' | ...
The following attributes are used in the base rules.
Direction := 'X' | 'x' | 'Y' | 'y' | 'Z' | 'z'
Size := decimalLiteral ('%')? | floatingPointLiteral
SplitType := 'faces' | 'sidefaces' | 'edges' | 'vertices' | 'walls' | 'floor'
literal := numericLiteral | booleanLiteral
booleanLiteral := 'true' | 'false'
numericLiteral := decimalLiteral | floatingPointLiteral
decimalLiteral := '0' | '1'..'9' Digit*
floatingPointLiteral := Digits '.' Digits? | '.' Digits | Digits 'f'
Digits := Digit*
Digit := '0'..'9'
Identifiers (such as predecessor and variable names) have to start with a letter, followed by any sequence of alphnumerical characters.
Qualified Identifiers will be used to specify assets (such as blocks or other grammar files).
Identifier := Letter (Letter | Digit)*
Letter := 'a'..'z' | 'A'..'Z' | '_'
qualifiedIdentifier := Identifier (':' Identifier)*
Comments, whitespaces and such are skipped during parsing and have no influence on the actual grammar functionality.
The rules are denoted using a syntax similar to ANTLR.
COMMENT := '/*' (.*)? '*/' -> channel(HIDDEN)
LINE_COMMENT := '//' ~[\r\n]* -> channel(HIDDEN)
WS := ( '\r' | '\t' | ' ' | '\n' )+ -> channel(HIDDEN)
I use the regular expression notation for + (1 or more), ? (at most 1), brackets for characters ranges, * (for 0 or
more), __ for escaping, ' ' for literals and parenthesis for grouping. Furthermore, . is a wildcard character and
~ denotes "everything until ...".
The following code is an example of a PAG-grammar. It is closely related to a example provided by Müller, Wonka et al.
#type := house;
window_spacing := 4;
window_width := 2;
window_depth := .5;
window_height := 1;
door_height := 2;
door_width := 2;
roof_angle := 45;
grammar TestHouse:
Priority 1:
footprint -> {
S(1r, building_height, 1r) facades
T(0, building_height, 0) I("prism") roof
};
Priority 2:
facades -> Split {
["sidefaces"] facade
};
facade : Shape.visible("street")
-> Divide "X" {
[1r] tiles
[door_width * 1.5] entrance
} : 0.5
-> Divide "X" {
[door_width * 1.5] entrance
[1r] tiles
} : 0.5
;
facade -> tiles;
tiles -> Repeat "X" [window_spacing] tile;
tile -> Divide "X" {
[1r] wall
[window_width] Divide "Y" {
[window_height] window
[1r] wall
}
[1r] wall
};
window : Scope.occ("noparent") != "none" -> wall;
window -> {
S(1r, 1r, window_depth) Set("enginge.glass")
};
entrance -> Divide "X" {
[1r] wall
[door_width] Divide "Y" {
[door_height] door
[1r] wall
}
[1r] wall
};
door -> Set("core.door");
wall -> Set(Random("cobblestone", "stonebricks"));
Priority 3:
roof -> Split {
["sidefaces"] covering
["sideedges"] roofedge
["topedge"] roofedge
};
covering -> Set("brick" : "stair");
roofedge -> Set("stone");
The Matrix4i class was moved.
Depends on MovingBlocks/Terasology#2093 and for a new TeraMath release to actually include it (code is there just not released)
There is not yet proper support for gradle builds, but adding libraries to individual modules can be done manually.
Using antlr sounds reasonable for parsing grammar files.
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.