ba06f8bb |
1 | Coding Rules {#occt_dev_guides__coding_rules} |
f6e968a7 |
2 | ====================================== |
3 | |
4 | @tableofcontents |
5 | |
49663e13 |
6 | @section occt_coding_rules_1 Introduction |
f6e968a7 |
7 | |
49663e13 |
8 | The purpose of this document is to define a common programming style for Open CASCADE Technology. |
f6e968a7 |
9 | |
49663e13 |
10 | The common style facilitates understanding and maintaining a code developed cooperatively by several programmers. In addition, it enables construction of tools that incorporate knowledge of these standards to help in the programming. |
f6e968a7 |
11 | |
49663e13 |
12 | OCCT programming style follows common and appropriate best practices, so some guidelines have been excerpted from the public domain. |
13 | |
14 | The guide can be improved in the future as new ideas and enhancements are added. |
15 | |
16 | @subsection occt_coding_rules_1_1 Scope of the document |
17 | |
18 | Rules in this document refer to C++ code. However, with minor exceptions due to language restrictions, they are applicable to any sources in Open CASCADE Technology framework, including: |
f6e968a7 |
19 | - C/C++ |
20 | - GLSL programs |
21 | - OpenCL kernels |
22 | - TCL scripts and test cases |
23 | |
49663e13 |
24 | @section occt_coding_rules_2 Naming Conventions |
f6e968a7 |
25 | |
49663e13 |
26 | @subsection occt_coding_rules_2_1 General naming rules |
f6e968a7 |
27 | |
49663e13 |
28 | The names considered in this section mainly refer to the interface of Open CASCADE Technology libraries or source code itself. |
f6e968a7 |
29 | |
30 | ### International language [MANDATORY] |
49663e13 |
31 | |
32 | Open CASCADE Technology is an open source platform available for an international community, thus all names need to be composed of English words or their abbreviations. |
33 | |
34 | ### Meaningful names |
35 | |
36 | Names should be meaningful or, at least, contain a meaningful part. To better understand this requirement, let us examine the existing names of toolkits, packages, classes and methods: |
37 | - Packages containing words *Geom* or *Geom2d* in their names are related to geometrical data and operations. |
38 | - Packages containing words *TopoDS* or *BRep* in their names are related to topological data and operations. |
49663e13 |
39 | - Packages ending with <i>...Test</i> define Draw Harness plugins. |
40 | - Methods starting with *Get...* and *Set...* are usually responsible for correspondingly retrieving and storing data. |
f6e968a7 |
41 | |
42 | ### Related names |
49663e13 |
43 | |
44 | Names related to a logically connected functionality should have the same prefix (start with the same letters) or, at least, have any other common part. |
45 | For example, method *GetCoord* returns a triple of real values and is defined for directions, vectors and points. The logical connection is obvious. |
f6e968a7 |
46 | |
47 | ### Camel Case style |
48 | Camel Case style is preferred for names. |
49 | For example: |
50 | |
51 | ~~~~~{.cpp} |
52 | Standard_Integer awidthofbox; // this is bad |
53 | Standard_Integer width_of_box; // this is bad |
54 | Standard_Integer aWidthOfBox; // this is OK |
55 | ~~~~~ |
56 | |
49663e13 |
57 | @subsection occt_coding_rules_2_2 Names of development units |
f6e968a7 |
58 | |
49663e13 |
59 | Usually a unit (e.g. a package) is a set of classes, methods, enumerations or any other sources implementing a common functionality, which is self-contained and independent from other parts of the library. |
f6e968a7 |
60 | |
49663e13 |
61 | ### No underscores in unit names [MANDATORY] |
f6e968a7 |
62 | |
49663e13 |
63 | Names of units should not contain underscores, unless the use of underscores is allowed explicitly. |
f6e968a7 |
64 | |
49663e13 |
65 | ### File name extensions [MANDATORY] |
66 | |
67 | The following extensions should be used for source files, depending on their type: |
f6e968a7 |
68 | |
3f812249 |
69 | * <i>.cxx</i> -- C++ source files |
70 | * <i>.hxx</i> -- C++ header files |
d3013f55 |
71 | * <i>.lxx</i> -- additional headers containing definitions of inline methods and auxiliary code |
f6e968a7 |
72 | |
629362c6 |
73 | Note that .lxx files should be avoided in most cases - inline method should be placed in header file instead. |
74 | |
49663e13 |
75 | ### Prefix for toolkit names [MANDATORY] |
76 | |
77 | Toolkit names are prefixed by *TK*, followed by a meaningful part of the name explaining the domain of functionality covered by the toolkit (e.g. *TKOpenGl*). |
f6e968a7 |
78 | |
79 | ### Names of classes |
f6e968a7 |
80 | |
49663e13 |
81 | Usually the names of source files located in a unit start from the unit name separated from the other part of the file name by underscore "_". |
82 | |
83 | Thus, the names of files containing sources of C++ classes that belong to a package are constructed according to the following template: |
84 | |
85 | ~~~~~ |
04c2daa4 |
86 | <package-name>_<class-name>.cxx (or .hxx) |
49663e13 |
87 | ~~~~~ |
f6e968a7 |
88 | |
49663e13 |
89 | For example, file *Adaptor2d_Curve2d.cxx* belongs to the package *Adaptor2d* |
f6e968a7 |
90 | |
49663e13 |
91 | Files that contain sources related to the whole unit are called by the unit name with appropriate extension. |
f6e968a7 |
92 | |
93 | ### Names of functions |
49663e13 |
94 | |
95 | The term **function** here is defined as: |
f6e968a7 |
96 | - Any class method |
97 | - Any package method |
98 | - Any non-member procedure or function |
99 | |
49663e13 |
100 | It is preferred to start names of public methods from an upper case character and to start names of protected and private methods from a lower case character. |
101 | |
f6e968a7 |
102 | |
103 | ~~~~~{.cpp} |
104 | class MyPackage_MyClass |
105 | { |
106 | |
107 | public: |
108 | |
109 | Standard_Integer Value() const; |
110 | void SetValue (const Standard_Integer theValue); |
111 | |
112 | private: |
113 | |
114 | void setIntegerValue (const Standard_Integer theValue); |
115 | |
116 | }; |
117 | ~~~~~ |
118 | |
49663e13 |
119 | @subsection occt_coding_rules_2_3 Names of variables |
120 | |
121 | There are several rules that describe currently accepted practices for naming variables. |
f6e968a7 |
122 | |
123 | ### Naming of variables |
49663e13 |
124 | |
125 | Name of a variable should not conflict with the existing or possible global names (for packages, macros, functions, global variables, etc.). |
126 | |
127 | The name of a variable should not start with an underscore. |
f6e968a7 |
128 | |
129 | See the following examples: |
130 | |
131 | ~~~~~{.cpp} |
132 | Standard_Integer Elapsed_Time = 0; // this is bad - possible class name |
133 | Standard_Integer gp = 0; // this is bad - existing package name |
134 | Standard_Integer aGp = 0; // this is OK |
135 | Standard_Integer _KERNEL = 0; // this is bad |
136 | Standard_Integer THE_KERNEL = 0; // this is OK |
137 | ~~~~~ |
138 | |
139 | ### Names of function parameters |
49663e13 |
140 | |
141 | The name of a function (procedure, class method) parameter should start with prefix *the* followed by the meaningful part of the name starting with a capital letter. |
f6e968a7 |
142 | |
143 | See the following examples: |
144 | |
145 | ~~~~~{.cpp} |
146 | void Package_MyClass::MyFunction (const gp_Pnt& p); // this is bad |
147 | void Package_MyClass::MyFunction (const gp_Pnt& theP); // this is OK |
148 | void Package_MyClass::MyFunction (const gp_Pnt& thePoint); // this is preferred |
149 | ~~~~~ |
150 | |
151 | ### Names of class member variables |
49663e13 |
152 | |
153 | The name of a class member variable should start with prefix *my* followed by the meaningful of the name starting with a capital letter. |
f6e968a7 |
154 | |
155 | See the following examples: |
156 | |
157 | ~~~~~{.cpp} |
158 | Standard_Integer counter; // This is bad |
159 | Standard_Integer myC; // This is OK |
160 | Standard_Integer myCounter; // This is preferred |
161 | ~~~~~ |
162 | |
163 | ### Names of global variables |
49663e13 |
164 | |
f6e968a7 |
165 | It is strongly recommended to avoid defining any global variables. |
4ee1bdf4 |
166 | However, as soon as a global variable is necessary, its name should be prefixed by the name of a class or a package where it is defined followed with <i>_my</i>. |
f6e968a7 |
167 | |
168 | See the following examples: |
169 | |
170 | ~~~~~{.cpp} |
171 | Standard_Integer MyPackage_myGlobalVariable = 0; |
172 | Standard_Integer MyPackage_MyClass_myGlobalVariable = 0; |
173 | ~~~~~ |
174 | |
49663e13 |
175 | Static constants within the file should be written in upper-case and begin with prefix *THE_*: |
f6e968a7 |
176 | ~~~~~{.cpp} |
177 | namespace |
178 | { |
179 | static const Standard_Real THE_CONSTANT_COEF = 3.14; |
180 | }; |
181 | ~~~~~ |
182 | |
183 | ### Names of local variables |
f6e968a7 |
184 | |
49663e13 |
185 | The name of a local variable should be distinguishable from the name of a function parameter, a class member variable and a global variable. |
186 | |
187 | It is preferred to prefix local variable names with *a* and *an* (or *is*, *to* and *has* for Boolean variables). |
188 | |
189 | See the following example: |
f6e968a7 |
190 | |
191 | ~~~~~{.cpp} |
192 | Standard_Integer theI; // this is bad |
193 | Standard_Integer i; // this is bad |
194 | Standard_Integer index; // this is bad |
195 | Standard_Integer anIndex; // this is OK |
196 | ~~~~~ |
197 | |
198 | ### Avoid dummy names |
49663e13 |
199 | Avoid dummy names, such as <i>i, j, k</i>. Such names are meaningless and easy to mix up. |
200 | |
201 | The code becomes more and more complicated when such dummy names are used there multiple times with different meanings, or in cycles with different iteration ranges, etc. |
f6e968a7 |
202 | |
203 | See the following examples for preferred style: |
204 | |
205 | ~~~~~{.cpp} |
206 | void Average (const Standard_Real** theArray, |
207 | Standard_Integer theRowsNb, |
208 | Standard_Integer theRowLen, |
209 | Standard_Real& theResult) |
210 | { |
211 | theResult = 0.0; |
212 | for (Standard_Integer aRow = 0; aRow < aRowsNb; ++aRow) |
213 | { |
214 | for (Standard_Integer aCol = 0; aCol < aRowLen; ++aCol) |
215 | { |
216 | theResult += theArray[aRow][aCol]; |
217 | } |
218 | theResult /= Standard_Real(aRowsNb * aRowLen); |
219 | } |
220 | } |
221 | ~~~~~ |
222 | |
49663e13 |
223 | @section occt_coding_rules_3 Formatting rules |
f6e968a7 |
224 | |
49663e13 |
225 | To improve the open source readability and, consequently, maintainability, the following set of rules is applied. |
f6e968a7 |
226 | |
227 | ### International language [MANDATORY] |
49663e13 |
228 | |
f6e968a7 |
229 | All comments in all sources must be in English. |
230 | |
231 | ### Line length |
49663e13 |
232 | |
233 | Try to stay within the limit of 120 characters per line in all sources. |
f6e968a7 |
234 | |
235 | ### C++ style comments |
49663e13 |
236 | |
f6e968a7 |
237 | Prefer C++ style comments in C++ sources. |
238 | |
239 | ### Commenting out unused code |
49663e13 |
240 | |
ba06f8bb |
241 | Delete unused code instead of commenting it or using \#define. |
f6e968a7 |
242 | |
243 | ### Indentation in sources [MANDATORY] |
49663e13 |
244 | |
f6e968a7 |
245 | Indentation in all sources should be set to two space characters. |
246 | Use of tabulation characters for indentation is disallowed. |
247 | |
248 | ### Separating spaces |
49663e13 |
249 | |
250 | Punctuation rules follow the rules of the English language. |
251 | * C/C++ reserved words, commas, colons and semicolons should be followed by a space character if they are not at the end of a line. |
252 | * There should be no space characters after '(' and before ')'. Closing and opening brackets should be separated by a space character. |
564c82b4 |
253 | * For better readability it is also recommended to surround conventional operators by a space character. |
254 | Examples: |
f6e968a7 |
255 | |
256 | ~~~~~{.cpp} |
257 | while (true) // NOT: while( true ) ... |
258 | { |
259 | DoSomething (theA, theB, theC, theD); // NOT: DoSomething(theA,theB,theC,theD); |
260 | } |
261 | for (anIter = 0; anIter < 10; ++anIter) // NOT: for (anIter=0;anIter<10;++anIter){ |
262 | { |
263 | theA = (theB + theC) * theD; // NOT: theA=(theB+theC)*theD |
264 | } |
265 | ~~~~~ |
266 | |
564c82b4 |
267 | ### Declaration of pointers and references |
268 | |
269 | In declarations of simple pointers and references put asterisk (*) or ampersand (&) right after the type without extra space. |
270 | |
271 | Since declaration of several variables with mixed pointer types contrudicts this rule, it should be avoided. Instead, declare each variable independently with fully qualified type. |
272 | |
273 | Examples: |
274 | |
275 | ~~~~~{.cpp} |
276 | Standard_Integer *theVariable; // not recommended |
277 | Standard_Integer * theVariable; // not recommended |
278 | Standard_Integer* theVariable; // this is OK |
279 | |
280 | Standard_Integer *&theVariable; // not recommended |
281 | Standard_Integer *& theVariable; // not recommended |
282 | Standard_Integer*& theVariable; // this is OK |
283 | |
284 | Standard_Integer **theVariable; // not recommended |
285 | Standard_Integer ** theVariable; // not recommended |
286 | Standard_Integer** theVariable; // this is OK |
287 | |
288 | Standard_Integer *theA, theB, **theC; // not recommended (declare each variable independently) |
289 | ~~~~~ |
290 | |
f6e968a7 |
291 | ### Separate logical blocks |
49663e13 |
292 | |
f6e968a7 |
293 | Separate logical blocks of code with one blank line and comments. |
49663e13 |
294 | |
f6e968a7 |
295 | See the following example: |
296 | |
297 | ~~~~~{.cpp} |
298 | // check arguments |
299 | Standard_Integer anArgsNb = argCount(); |
300 | if (anArgsNb < 3 || isSmthInvalid) |
301 | { |
302 | return THE_ARG_INVALID; |
303 | } |
304 | |
305 | // read and check header |
306 | ... |
307 | ... |
308 | |
309 | // do our job |
310 | ... |
311 | ... |
312 | ~~~~~ |
313 | |
314 | Notice that multiple blank lines should be avoided. |
315 | |
316 | ### Separate function bodies [MANDATORY] |
49663e13 |
317 | |
f6e968a7 |
318 | Use function descriptive blocks to separate function bodies from each other. |
49663e13 |
319 | Each descriptive block should contain at least a function name and purpose description. |
320 | |
f6e968a7 |
321 | See the following example: |
322 | |
323 | ~~~~~{.cpp} |
f3fb84ce |
324 | // ======================================================================= |
f6e968a7 |
325 | // function : TellMeSmthGood |
326 | // purpose : Gives me good news |
f3fb84ce |
327 | // ======================================================================= |
f6e968a7 |
328 | void TellMeSmthGood() |
329 | { |
330 | ... |
331 | } |
332 | |
f3fb84ce |
333 | // ======================================================================= |
f6e968a7 |
334 | // function : TellMeSmthBad |
335 | // purpose : Gives me bad news |
f3fb84ce |
336 | // ======================================================================= |
f6e968a7 |
337 | void TellMeSmthBad() |
338 | { |
339 | ... |
340 | } |
341 | ~~~~~ |
342 | |
343 | ### Block layout [MANDATORY] |
49663e13 |
344 | Figure brackets <i>{ }</i> and each operator <i>(for, if, else, try, catch)</i> should be written on a dedicated line. |
345 | |
346 | In general, the layout should be as follows: |
f6e968a7 |
347 | |
348 | ~~~~~{.cpp} |
349 | while (expression) |
350 | { |
351 | ... |
352 | } |
353 | ~~~~~ |
354 | |
49663e13 |
355 | Entering a block increases and leaving a block decreases the indentation by one tabulation. |
f6e968a7 |
356 | |
357 | ### Single-line operators |
49663e13 |
358 | |
359 | Single-line conditional operators <i>(if, while, for,</i> etc.) can be written without brackets on the following line. |
f6e968a7 |
360 | |
361 | ~~~~~{.cpp} |
362 | if (!myIsInit) return Standard_False; // bad |
363 | |
364 | if (thePtr == NULL) // OK |
365 | return Standard_False; |
366 | |
367 | if (!theAlgo.IsNull()) // preferred |
368 | { |
369 | DoSomething(); |
370 | } |
371 | ~~~~~ |
372 | |
49663e13 |
373 | Having all code in the same line is less convenient for debugging. |
f6e968a7 |
374 | |
564c82b4 |
375 | ### Comparison expressions with constants |
376 | |
377 | In comparisons, put the variable (in the current context) on the left side and constant on the right side of expression. |
378 | That is, the so called "Yoda style" is to be avoided. |
379 | |
380 | ~~~~~{.cpp} |
381 | if (NULL != thePointer) // Yoda style, not recommended |
382 | if (thePointer != NULL) // OK |
383 | |
384 | if (34 < anIter) // Yoda style, not recommended |
385 | if (anIter > 34) // OK |
386 | |
387 | if (theNbValues >= anIter) // bad style (constant function argument vs. local variable) |
388 | if (anIter <= theNbValues) // OK |
389 | |
390 | if (THE_LIMIT == theValue) // bad style (global constant vs. variable) |
391 | if (theValue == THE_LIMIT) // OK |
392 | ~~~~~ |
393 | |
49663e13 |
394 | ### Alignment |
395 | |
396 | Use alignment wherever it enhances the readability. See the following example: |
f6e968a7 |
397 | |
398 | ~~~~~{.cpp} |
399 | MyPackage_MyClass anObject; |
400 | Standard_Real aMinimum = 0.0; |
401 | Standard_Integer aVal = theVal; |
402 | switch (aVal) |
403 | { |
404 | case 0: computeSomething(); break; |
405 | case 12: computeSomethingElse (aMinimum); break; |
406 | case 3: |
407 | default: computeSomethingElseYet(); break; |
408 | } |
409 | ~~~~~ |
410 | |
411 | ### Indentation of comments |
49663e13 |
412 | |
413 | Comments should be indented in the same way as the code to which they refer or they can be in the same line if they are short. |
414 | |
415 | The text of the comment should be separated from the slash character by a single space character. |
416 | |
f6e968a7 |
417 | See the following example: |
418 | |
419 | ~~~~~{.cpp} |
420 | while (expression) //bad comment |
421 | { |
422 | // this is a long multi-line comment |
423 | // which is really required |
424 | DoSomething(); // maybe, enough |
425 | DoSomethingMore(); // again |
426 | } |
427 | ~~~~~ |
428 | |
429 | ### Early return statement |
49663e13 |
430 | |
431 | Use an early return condition rather than collect indentations. |
432 | |
433 | Write like this: |
f6e968a7 |
434 | |
435 | ~~~~~{.cpp} |
436 | Standard_Integer ComputeSumm (const Standard_Integer* theArray, |
437 | const Standard_Size theSize) |
438 | { |
439 | Standard_Integer aSumm = 0; |
440 | if (theArray == NULL || theSize == 0) |
441 | { |
442 | return 0; |
443 | } |
444 | |
445 | ... computing summ ... |
446 | return aSumm; |
447 | } |
448 | ~~~~~ |
449 | |
49663e13 |
450 | Rather than: |
f6e968a7 |
451 | |
452 | ~~~~~{.cpp} |
453 | Standard_Integer ComputeSumm (const Standard_Integer* theArray, |
454 | const Standard_Size theSize) |
455 | { |
456 | Standard_Integer aSumm = 0; |
457 | if (theArray != NULL && theSize != 0) |
458 | { |
459 | ... computing summ ... |
460 | } |
461 | return aSumm; |
462 | } |
463 | ~~~~~ |
464 | |
49663e13 |
465 | This helps to improve readability and reduce the unnecessary indentation depth. |
f6e968a7 |
466 | |
467 | ### Trailing spaces |
49663e13 |
468 | |
469 | Trailing spaces should be removed whenever possible. |
470 | Spaces at the end of a line are useless and do not affect functionality. |
f6e968a7 |
471 | |
472 | ### Headers order |
49663e13 |
473 | |
474 | Split headers into groups: system headers, headers per each framework, project headers; sort the list of includes alphabetically. |
629362c6 |
475 | Within the class source file, the class header file should be included first. |
49663e13 |
476 | |
477 | This rule improves readability, allows detecting useless multiple header inclusions and makes 3rd-party dependencies clearly visible. |
629362c6 |
478 | Inclusion of class header on top verifies consistency of the header (e.g. that header file does not use any undefined declarations due to missing includes of dependencies). |
f6e968a7 |
479 | |
629362c6 |
480 | An exception to the rule is ordering system headers generating a macros declaration conflicts (like "windows.h" or "X11/Xlib.h") - these headers should be placed in the way solving the conflict. |
f6e968a7 |
481 | |
629362c6 |
482 | ~~~~~{.cpp} |
483 | // the header file of implemented class |
484 | #include <PackageName_ClassName.hxx> |
f6e968a7 |
485 | |
486 | // OCCT headers |
487 | #include <gp_Pnt.hxx> |
488 | #include <gp_Vec.hxx> |
489 | #include <NCollection_List.hxx> |
629362c6 |
490 | |
491 | // Qt headers |
492 | #include <QDataStream> |
493 | #include <QString> |
494 | |
495 | // system headers |
496 | #include <iostream> |
497 | #include <windows.h> |
f6e968a7 |
498 | ~~~~~ |
499 | |
49663e13 |
500 | @section occt_coding_rules_4 Documentation rules |
f6e968a7 |
501 | |
502 | The source code is one of the most important references for documentation. |
49663e13 |
503 | The comments in the source code should be complete enough to allow understanding the corresponding code and to serve as basis for other documents. |
f6e968a7 |
504 | |
49663e13 |
505 | The main reasons why the comments are regarded as documentation and should be maintained are: |
3f812249 |
506 | - The comments are easy to reach -- they are always together with the source code; |
49663e13 |
507 | - It is easy to update a description in the comment when the source is modified; |
508 | - The source by itself is a good context to describe various details that would require much more explanations in a separate document; |
509 | - As a summary, this is the most cost-effective documentation. |
f6e968a7 |
510 | |
511 | The comments should be compatible with Doxygen tool for automatic documentation generation (thus should use compatible tags). |
512 | |
513 | ### Documenting classes [MANDATORY] |
49663e13 |
514 | |
04c2daa4 |
515 | Each class should be documented in its header file (.hxx). |
49663e13 |
516 | The comment should give enough details for the reader to understand the purpose of the class and the main way of work with it. |
f6e968a7 |
517 | |
518 | ### Documenting class methods [MANDATORY] |
49663e13 |
519 | |
04c2daa4 |
520 | Each class or package method should be documented in the header file (.hxx). |
49663e13 |
521 | |
f6e968a7 |
522 | The comment should explain the purpose of the method, its parameters, and returned value(s). |
523 | Accepted style is: |
524 | |
525 | @verbatim |
526 | //! Method computes the square value. |
527 | //! @param theValue the input value |
528 | //! @return squared value |
529 | Standard_Export Standard_Real Square (Standard_Real theValue); |
530 | @endverbatim |
531 | |
532 | ### Documenting C/C++ sources |
49663e13 |
533 | |
f6e968a7 |
534 | It is very desirable to put comments in the C/C++ sources of the package/class. |
f6e968a7 |
535 | |
49663e13 |
536 | They should be detailed enough to allow any person to understand what each part of code does. |
537 | |
538 | It is recommended to comment all static functions (like methods in headers), and to insert at least one comment per each 10-100 lines in the function body. |
539 | |
67d7f07f |
540 | There are also some rules that define how comments should be formatted, see @ref occt_coding_rules_3 "Formatting Rules". |
49663e13 |
541 | |
542 | Following these rules is important for good comprehension of the comments. Moreover, this approach allows automatically generating user-oriented documentation directly from the commented sources. |
f6e968a7 |
543 | |
49663e13 |
544 | @section occt_coding_rules_5 Application design |
545 | |
546 | The following rules define the common style, which should be applied by any developer contributing to the open source. |
547 | |
548 | ### Allow possible inheritance |
f6e968a7 |
549 | |
f6e968a7 |
550 | Try to design general classes (objects) keeping possible inheritance in mind. |
49663e13 |
551 | This rule means that the user who makes possible extensions of your class should not encounter problems of private implementation. |
f6e968a7 |
552 | Try to use protected members and virtual methods wherever you expect extensions in the future. |
553 | |
554 | ### Avoid friend declarations |
49663e13 |
555 | |
556 | Avoid using 'friend' classes or functions except for some specific cases (for example, iteration) 'Friend' declarations increase coupling. |
f6e968a7 |
557 | |
558 | ### Set/get methods |
49663e13 |
559 | |
f6e968a7 |
560 | Avoid providing set/get methods for all fields of the class. |
561 | Intensive set/get functions break down encapsulation. |
562 | |
563 | ### Hiding virtual functions [MANDATORY] |
49663e13 |
564 | |
f6e968a7 |
565 | Avoid hiding a base class virtual function by a redefined function with a different signature. |
566 | Most of the compilers issue warning on this. |
567 | |
568 | ### Avoid mixing error reporting strategies |
49663e13 |
569 | |
570 | Try not to mix different error indication/handling strategies (exceptions or returned values) on the same application level. |
f6e968a7 |
571 | |
572 | ### Minimize compiler warnings [MANDATORY] |
49663e13 |
573 | |
f6e968a7 |
574 | When compiling the source pay attention to and try to minimize compiler warnings. |
575 | |
49663e13 |
576 | ### Avoid unnecessary inclusions |
f6e968a7 |
577 | |
49663e13 |
578 | Try to minimize compilation dependencies by removing unnecessary inclusions. |
f6e968a7 |
579 | |
49663e13 |
580 | @section occt_coding_rules_6 General C/C++ rules |
581 | |
582 | This section defines the rules for writing a portable and maintainable C/C++ source code. |
f6e968a7 |
583 | |
584 | ### Wrapping of global variables [MANDATORY] |
49663e13 |
585 | |
586 | Use package or class methods returning reference to wrap global variables to reduce possible name space conflicts. |
f6e968a7 |
587 | |
588 | ### Avoid private members |
49663e13 |
589 | |
590 | Use *protected* members instead of *private* wherever reasonable to enable future extensions. |
591 | Use *private* fields if future extensions should be disabled. |
f6e968a7 |
592 | |
593 | ### Constants and inlines over defines [MANDATORY] |
49663e13 |
594 | |
ba06f8bb |
595 | Use constant variables (const) and inline functions instead of defines (\#define). |
f6e968a7 |
596 | |
597 | ### Avoid explicit numerical values [MANDATORY] |
49663e13 |
598 | |
f6e968a7 |
599 | Avoid usage of explicit numeric values. Use named constants and enumerations instead. |
49663e13 |
600 | Numbers produce difficulties for reading and maintenance. |
f6e968a7 |
601 | |
602 | ### Three mandatory methods |
49663e13 |
603 | |
604 | If a class has a destructor, an assignment operator or a copy constructor, it usually needs the other two methods. |
f6e968a7 |
605 | |
606 | ### Virtual destructor |
49663e13 |
607 | |
f6e968a7 |
608 | A class with virtual function(s) ought to have a virtual destructor. |
609 | |
a3157439 |
610 | ### Overriding virtual methods |
611 | |
612 | Declaration of overriding method should contains specifiers "virtual" and "override" |
613 | (using Standard_OVERRIDE alias for compatibility with old compilers). |
614 | |
615 | ~~~~~{.cpp} |
616 | class MyPackage_BaseClass |
617 | { |
618 | |
619 | public: |
620 | |
621 | Standard_EXPORT virtual Standard_Boolean Perform(); |
622 | |
623 | }; |
624 | |
a3157439 |
625 | class MyPackage_MyClass : public MyPackage_BaseClass |
626 | { |
627 | |
628 | public: |
629 | |
630 | Standard_EXPORT virtual Standard_Boolean Perform() Standard_OVERRIDE; |
631 | |
632 | }; |
633 | ~~~~~ |
634 | |
635 | This makes class definition more clear (virtual methods become highlighted). |
636 | |
637 | Declaration of interface using pure virtual functions protects against |
638 | incomplete inheritance at first level, but does not help when method is overridden multiple times within nested inheritance |
639 | or when method in base class is intended to be optional. |
640 | |
641 | And here "override" specifier introduces additional protection against situations when interface changes might be missed |
642 | (class might contain old methods which will be never called). |
643 | |
f6e968a7 |
644 | ### Default parameter value |
49663e13 |
645 | |
f6e968a7 |
646 | Do not redefine a default parameter value in an inherited function. |
647 | |
648 | ### Use const modifier |
49663e13 |
649 | |
650 | Use *const* modifier wherever possible (functions parameters, return values, etc.) |
f6e968a7 |
651 | |
652 | ### Usage of goto [MANDATORY] |
49663e13 |
653 | Avoid *goto* statement unless it is really needed. |
f6e968a7 |
654 | |
655 | ### Declaring variable in for() header |
49663e13 |
656 | |
657 | Declare a cycle variable in the header of the *for()* statement if not used out of cycle. |
f6e968a7 |
658 | |
659 | ~~~~~{.cpp} |
660 | Standard_Real aMinDist = Precision::Infinite(); |
661 | for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter (theSequence); |
662 | aPntIter.More(); aPntIter.Next()) |
663 | { |
664 | aMinDist = Min (aMinDist, theOrigin.Distance (aPntIter.Value())); |
665 | } |
666 | ~~~~~ |
667 | |
668 | ### Condition statements within zero |
49663e13 |
669 | |
f6e968a7 |
670 | Avoid usage of C-style comparison for non-boolean variables: |
671 | |
672 | ~~~~~{.cpp} |
673 | void Function (Standard_Integer theValue, |
674 | Standard_Real* thePointer) |
675 | { |
676 | if (!theValue) // bad style - ambiguous logic |
677 | { |
678 | DoSome(); |
679 | } |
680 | |
681 | if (theValue == 0) // OK |
682 | { |
683 | DoSome(); |
684 | } |
685 | |
686 | if (thePointer != NULL) // OK, predefined NULL makes pointer comparison cleaner to reader |
687 | { // (nullptr should be used instead as soon as C++11 will be available) |
688 | DoSome2(); |
689 | } |
690 | } |
691 | ~~~~~ |
692 | |
49663e13 |
693 | @section occt_coding_rules_7 Portability issues |
f6e968a7 |
694 | |
695 | This chapter contains rules that are critical for cross-platform portability. |
696 | |
49663e13 |
697 | ### Provide code portability [MANDATORY] |
698 | |
699 | The source code must be portable to all platforms listed in the official 'Technical Requirements'. |
f6e968a7 |
700 | The term 'portable' here means 'able to be built from source'. |
701 | |
702 | The C++ source code should meet C++03 standard. |
49663e13 |
703 | Any usage of compiler-specific features or further language versions (for example, C++11, until all major compilers on all supported platforms implement all its features) should be optional (used only with appropriate preprocessor checks) and non-exclusive (an alternative implementation compatible with other compilers should be provided). |
f6e968a7 |
704 | |
705 | ### Avoid usage of global variables [MANDATORY] |
49663e13 |
706 | |
707 | Avoid usage of global variables. Usage of global variables may cause problems when accessed from another shared library. |
708 | |
709 | Use global (package or class) functions that return reference to static variable local to this function instead of global variables. |
710 | |
f6e968a7 |
711 | Another possible problem is the order of initialization of global variables defined in various libraries that may differ depending on platform, compiler and environment. |
712 | |
713 | ### Avoid explicit basic types |
f6e968a7 |
714 | |
49663e13 |
715 | Avoid explicit usage of basic types (*int*, *float*, *double*, etc.), use Open CASCADE Technology types from package *Standard: Standard_Integer, Standard_Real, Standard_ShortReal, Standard_Boolean, Standard_CString* and others or a specific *typedef* instead. |
716 | |
717 | ### Use *sizeof()* to calculate sizes [MANDATORY] |
f6e968a7 |
718 | |
49663e13 |
719 | Do not assume sizes of types. Use *sizeof()* instead to calculate sizes. |
720 | |
721 | ### Empty line at the end of file [MANDATORY] |
722 | |
723 | In accordance with C++03 standard source files should be trailed by an empty line. |
f6e968a7 |
724 | It is recommended to follow this rule for any plain text files for consistency and for correct work of git difference tools. |
725 | |
49663e13 |
726 | @section occt_coding_rules_8 Stability issues |
f6e968a7 |
727 | |
728 | The rules listed in this chapter are important for stability of the programs that use Open CASCADE Technology libraries. |
729 | |
49663e13 |
730 | ### Use *OSD::SetSignal()* to catch exceptions |
731 | |
732 | When using Open CASCADE Technology in an application, call *OSD::SetSignal()* function when the application is initialized. |
733 | |
734 | This will install C handlers for run-time interrupt signals and exceptions, so that low-level exceptions (such as access violation, division by zero, etc.) will be redirected to C++ exceptions |
735 | that use *try {...} catch (Standard_Failure) {...}* blocks. |
736 | |
f6e968a7 |
737 | The above rule is especially important for robustness of modeling algorithms. |
738 | |
739 | ### Cross-referenced handles |
f6e968a7 |
740 | |
49663e13 |
741 | Take care about cycling of handled references to avoid chains, which will never be freed. For this purpose, use a pointer at one (subordinate) side. |
f6e968a7 |
742 | |
49663e13 |
743 | See the following example: |
744 | |
04c2daa4 |
745 | ~~~~{.cpp} |
746 | class Slave; |
49663e13 |
747 | |
04c2daa4 |
748 | class Master : public Standard_Transient |
749 | { |
f6e968a7 |
750 | ... |
04c2daa4 |
751 | void SetSlave (const Handle(Slave)& theSlave) |
752 | { |
753 | mySlave = theSlave; |
754 | } |
f6e968a7 |
755 | ... |
04c2daa4 |
756 | private: |
757 | Handle(Slave) theSlave; // smart pointer |
f6e968a7 |
758 | ... |
04c2daa4 |
759 | } |
f6e968a7 |
760 | |
04c2daa4 |
761 | class Slave : public Standard_Transient |
762 | { |
f6e968a7 |
763 | ... |
04c2daa4 |
764 | void SetMaster (const Handle(Master)& theMaster) |
765 | { |
766 | myMaster = theMaster.get(); |
767 | } |
f6e968a7 |
768 | ... |
04c2daa4 |
769 | private: |
770 | Master* theMaster; // simple pointer |
f6e968a7 |
771 | ... |
04c2daa4 |
772 | } |
49663e13 |
773 | ~~~~ |
f6e968a7 |
774 | |
f6e968a7 |
775 | ### C++ memory allocation |
f6e968a7 |
776 | |
49663e13 |
777 | In C++ use *new* and *delete* operators instead of *malloc()* and *free()*. Try not to mix different memory allocation techniques. |
778 | |
779 | ### Match *new* and *delete* [MANDATORY] |
780 | |
f6e968a7 |
781 | Use the same form of new and delete. |
782 | |
783 | ~~~~~{.cpp} |
784 | aPtr1 = new TypeA[n]; ... ; delete[] aPtr1; |
785 | aPtr2 = new TypeB(); ... ; delete aPtr2; |
786 | aPtr3 = Standard::Allocate (4096); ... ; Standard::Free (aPtr3); |
787 | ~~~~~ |
788 | |
789 | ### Methods managing dynamical allocation [MANDATORY] |
49663e13 |
790 | |
f6e968a7 |
791 | Define a destructor, a copy constructor and an assignment operator for classes with dynamically allocated memory. |
792 | |
793 | ### Uninitialized variables [MANDATORY] |
49663e13 |
794 | |
f6e968a7 |
795 | Every variable should be initialized. |
796 | |
797 | ~~~~~{.cpp} |
798 | Standard_Integer aTmpVar1; // bad |
799 | Standard_Integer aTmpVar2 = 0; // OK |
800 | ~~~~~ |
801 | |
49663e13 |
802 | Uninitialized variables might be kept only within performance-sensitive code blocks and only when their initialization is guaranteed by subsequent code. |
f6e968a7 |
803 | |
49663e13 |
804 | ### Do not hide global *new* |
805 | |
806 | Avoid hiding the global *new* operator. |
f6e968a7 |
807 | |
808 | ### Assignment operator |
49663e13 |
809 | |
810 | In *operator=()* assign to all data members and check for assignment to self. |
f6e968a7 |
811 | |
812 | ### Float comparison |
49663e13 |
813 | |
f6e968a7 |
814 | Don't check floats for equality or non-equality; check for GT, GE, LT or LE. |
815 | |
816 | ~~~~~{.cpp} |
817 | if (Abs (theFloat1 - theFloat2) < theTolerance) |
818 | { |
819 | DoSome(); |
820 | } |
821 | ~~~~~ |
822 | |
49663e13 |
823 | Package *Precision* provides standard values for SI units and widely adopted by existing modeling algorithms: |
824 | |
825 | - *Precision::Confusion()* for lengths in meters; |
826 | - *Precision::Angular()* for angles in radians. |
f6e968a7 |
827 | |
49663e13 |
828 | as well as definition of infinite values within normal range of double precision: |
829 | - *Precision::Infinite()* |
830 | - *Precision::IsInfinite()* |
831 | - *Precision::IsPositiveInfinite()* |
832 | - *Precision::IsNegativeInfinite()* |
f6e968a7 |
833 | |
834 | ### Non-indexed iteration |
49663e13 |
835 | |
f6e968a7 |
836 | Avoid usage of iteration over non-indexed collections of objects. |
49663e13 |
837 | If such iteration is used, make sure that the result of the algorithm does not depend on the order of iterated items. |
f6e968a7 |
838 | |
49663e13 |
839 | Since the order of iteration is unpredictable in case of a non-indexed collection of objects, it frequently leads to different behavior of the application from one run to another, thus embarrassing the debugging process. |
840 | |
841 | It mostly concerns mapped objects for which pointers are involved in calculating the hash function. For example, the hash function of *TopoDS_Shape* involves the address of *TopoDS_TShape* object. Thus the order of the same shape in the *TopTools_MapOfShape* will vary in different sessions of the application. |
f6e968a7 |
842 | |
843 | ### Do not throw in destructors |
49663e13 |
844 | |
845 | Do not throw from within a destructor. |
f6e968a7 |
846 | |
847 | ### Assigning to reference [MANDATORY] |
f6e968a7 |
848 | |
49663e13 |
849 | Avoid the assignment of a temporary object to a reference. This results in a different behavior for different compilers on different platforms. |
850 | |
851 | @section occt_coding_rules_9 Performance issues |
f6e968a7 |
852 | |
853 | These rules define the ways of avoiding possible loss of performance caused by ineffective programming. |
854 | |
855 | ### Class fields alignment |
49663e13 |
856 | |
857 | Declare fields of a class in the decreasing order of their size for better alignment. |
f6e968a7 |
858 | Generally, try to reduce misaligned accesses since they impact the performance (for example, on Intel machines). |
859 | |
860 | ### Fields initialization order [MANDATORY] |
49663e13 |
861 | |
f6e968a7 |
862 | List class data members in the constructor's initialization list in the order they are declared. |
863 | |
864 | ~~~~~{.cpp} |
865 | class MyPackage_MyClass |
866 | { |
867 | |
868 | public: |
869 | |
870 | MyPackage_MyClass() |
871 | : myPropertyA (1), |
872 | myPropertyB (2) {} |
873 | |
874 | // NOT |
875 | // : myPropertyB (2), |
876 | // myPropertyA (1) {} |
877 | |
878 | private: |
879 | |
880 | Standard_Integer myPropertyA; |
881 | Standard_Integer myPropertyB; |
882 | |
883 | }; |
884 | ~~~~~ |
885 | |
886 | ### Initialization over assignment |
49663e13 |
887 | |
888 | Prefer initialization over assignment in class constructors. |
f6e968a7 |
889 | |
890 | ~~~~~{.cpp} |
891 | MyPackage_MyClass() |
892 | : myPropertyA (1) // preferred |
893 | { |
894 | myPropertyB = 2; // not recommended |
895 | } |
896 | ~~~~~ |
897 | |
898 | ### Optimize caching |
49663e13 |
899 | |
900 | When programming procedures with extensive memory access, try to optimize them in terms of cache behavior. Here is an example of how the cache behavior can be impacted: |
901 | |
f6e968a7 |
902 | On x86 this code |
903 | |
904 | ~~~~~{.cpp} |
905 | Standard_Real anArray[4096][2]; |
906 | for (Standard_Integer anIter = 0; anIter < 4096; ++anIter) |
907 | { |
908 | anArray[anIter][0] = anArray[anIter][1]; |
909 | } |
910 | ~~~~~ |
911 | |
49663e13 |
912 | is more efficient then |
f6e968a7 |
913 | |
914 | ~~~~~{.cpp} |
915 | Standard_Real anArray[2][4096]; |
916 | for (Standard_Integer anIter = 0; anIter < 4096; ++anIter) |
917 | { |
918 | anArray[0][anIter] = anArray[1][anIter]; |
919 | } |
920 | ~~~~~ |
921 | |
49663e13 |
922 | since linear access does not invalidate cache too often. |
923 | |
924 | @section occt_coding_rules_10 Draw Harness command |
925 | |
926 | Draw Harness provides TCL interface for OCCT algorithms. |
927 | |
928 | There is no TCL wrapper over OCCT C++ classes, instead interface is provided through the set of TCL commands implemented in C++. |
929 | |
930 | There is a list of common rules which should be followed to implement well-formed Draw Harness command. |
931 | |
932 | ### Return value |
933 | |
934 | Command should return 0 in most cases even if the executed algorithm has failed. Returning 1 would lead to a TCL exception, thus should be used in case of a command line syntax error and similar issues. |
935 | |
936 | ### Validate input parameters |
937 | |
938 | Command arguments should be validated before usage. The user should see a human-readable error description instead of a runtime exception from the executed algorithm. |
939 | |
940 | ### Validate the number of input parameters |
941 | |
942 | Command should warn the user about unknown arguments, including cases when extra parameters have been pushed for the command with a fixed number of arguments. |
943 | |
944 | ~~~~~{.cpp} |
945 | if (theArgsNb != 3) |
946 | { |
947 | std::cout << "Syntax error - wrong number of arguments!\n"; |
948 | return 1; |
949 | } |
950 | |
951 | Standard_Integer anArgIter = 1; |
952 | Standard_CString aResName = theArgVec[anArgIter++]; |
953 | Standard_CString aFaceName = theArgVec[anArgIter++]; |
954 | TopoDS_Shape aFaceShape = DBRep::Get (aFaceName); |
955 | if (aFaceShape.IsNull() |
956 | || aFaceShape.ShapeType() != TopAbs_FACE) |
957 | { |
958 | std::cout << "Shape " << aFaceName << " is empty or not a Face!\n"; |
959 | return 1; |
960 | } |
961 | DBRep::Set (aResName, aFaceShape); |
962 | return 0; |
963 | ~~~~~ |
964 | |
965 | ### Message printing |
966 | |
3f812249 |
967 | Informative messages should be printed into standard output *std::cout*, whilst command results (if any) -- into Draw Interpreter. |
49663e13 |
968 | |
969 | Information printed into Draw Interpreter should be well-structured to allow usage in TCL script. |
970 | |
971 | ### Long list of arguments |
972 | |
973 | Any command with a long list of obligatory parameters should be considered as ill-formed by design. |
974 | Optional parameters should start with flag name (with '-' prefix) and followed by its values: |
975 | |
976 | ~~~~~{.tcl} |
977 | myCommand -flag1 value1 value2 -flag2 value3 |
978 | ~~~~~ |
f6e968a7 |
979 | |
49663e13 |
980 | ### Arguments parser |
f6e968a7 |
981 | |
f8eb9b17 |
982 | - Integer values should be read using *Draw::Atoi()* function. |
983 | - Real values should be read using *Draw::Atof()* function. |
49663e13 |
984 | - Flags names should be checked in case insensitive manner. |
985 | |
f8eb9b17 |
986 | Functions *Draw::Atof()* and *Draw::Atoi()* support expressions and read values in C-locale. |
49663e13 |
987 | |
988 | ~~~~~{.cpp} |
989 | Standard_Real aPosition[3] = {0.0, 0.0, 0.0}; |
990 | for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter) |
991 | { |
992 | Standard_CString anArg = theArgVec[anArgIter]; |
993 | TCollection_AsciiString aFlag (anArg); |
994 | aFlag.LowerCase(); //!< for case insensitive comparison |
995 | if (aFlag == "position") |
996 | { |
997 | if ((anArgIt + 3) >= theArgsNb) |
998 | { |
999 | std::cerr << "Wrong syntax at argument '" << anArg << "'!\n"; |
1000 | return 1; |
1001 | } |
1002 | aPosition[0] = Draw::Atof (theArgVec[++anArgIt]); |
1003 | aPosition[1] = Draw::Atof (theArgVec[++anArgIt]); |
1004 | aPosition[2] = Draw::Atof (theArgVec[++anArgIt]); |
1005 | } |
1006 | else |
1007 | { |
1008 | std::cout << "Syntax error! Unknown flag '" << anArg << "'\n"; |
1009 | return 1; |
1010 | } |
1011 | } |
1012 | ~~~~~ |
1013 | |
1014 | @section occt_coding_rules_11 Examples |
1015 | |
1016 | ### Sample documented class |
f6e968a7 |
1017 | |
1018 | @verbatim |
f6e968a7 |
1019 | class Package_Class |
1020 | { |
1021 | |
1022 | public: //! @name public methods |
1023 | |
1024 | //! Method computes the square value. |
1025 | //! @param theValue the input value |
1026 | //! @return squared value |
1027 | Standard_Export Standard_Real Square (const Standard_Real theValue); |
1028 | |
49663e13 |
1029 | private: //! \@name private methods |
f6e968a7 |
1030 | |
1031 | //! Auxiliary method |
1032 | void increment(); |
1033 | |
49663e13 |
1034 | private: //! \@name private fields |
f6e968a7 |
1035 | |
1036 | Standard_Integer myCounter; //!< usage counter |
1037 | |
1038 | }; |
49663e13 |
1039 | |
1040 | |
f6e968a7 |
1041 | @endverbatim |
1042 | |
49663e13 |
1043 | ~~~~~ |
f6e968a7 |
1044 | #include <Package_Class.hxx> |
f6e968a7 |
1045 | // ========================================================== |
1046 | // function : Square |
1047 | // purpose : Method computes the square value |
1048 | // ========================================================== |
1049 | Standard_Real Package_Class::Square (const Standard_Real theValue) |
1050 | { |
1051 | increment(); |
1052 | return theValue * theValue; |
1053 | } |
1054 | |
1055 | // ========================================================== |
1056 | // function : increment |
1057 | // purpose : |
1058 | // ========================================================== |
1059 | void Package_Class::increment() |
1060 | { |
1061 | ++myCounter; |
1062 | } |
1063 | ~~~~~ |
1064 | |
49663e13 |
1065 | ### TCL script for Draw Harness |
1066 | |
f6e968a7 |
1067 | ~~~~~{.tcl} |
1068 | # show fragments (solids) in shading with different colors |
1069 | proc DisplayColored {theShape} { |
1070 | set aSolids [uplevel #0 explode $theShape so] |
1071 | set aColorIter 0 |
1072 | set THE_COLORS {red green blue1 magenta1 yellow cyan1 brown} |
1073 | foreach aSolIter $aSolids { |
1074 | uplevel #0 vdisplay $aSolIter |
1075 | uplevel #0 vsetcolor $aSolIter [lindex $THE_COLORS [expr [incr aColorIter] % [llength $THE_COLORS]]] |
1076 | uplevel #0 vsetdispmode $aSolIter 1 |
1077 | uplevel #0 vsetmaterial $aSolIter plastic |
1078 | uplevel #0 vsettransparency $aSolIter 0.5 |
1079 | } |
1080 | } |
1081 | |
1082 | # load modules |
1083 | pload MODELING VISUALIZATION |
1084 | |
1085 | # create boxes |
1086 | box bc 0 0 0 1 1 1 |
1087 | box br 1 0 0 1 1 2 |
1088 | compound bc br c |
1089 | |
1090 | # show fragments (solids) in shading with different colors |
1091 | vinit View1 |
1092 | vclear |
1093 | vaxo |
1094 | vzbufftrihedron |
1095 | DisplayColored c |
1096 | vfit |
1097 | vdump $imagedir/${casename}.png 512 512 |
1098 | ~~~~~ |
1099 | |
49663e13 |
1100 | ### GLSL program: |
f6e968a7 |
1101 | ~~~~~{.fs} |
1102 | vec3 Ambient; //!< Ambient contribution of light sources |
1103 | vec3 Diffuse; //!< Diffuse contribution of light sources |
1104 | vec3 Specular; //!< Specular contribution of light sources |
1105 | |
1106 | //! Computes illumination from light sources |
1107 | vec4 ComputeLighting (in vec3 theNormal, |
1108 | in vec3 theView, |
1109 | in vec4 thePoint) |
1110 | { |
1111 | // clear the light intensity accumulators |
1112 | Ambient = occLightAmbient.rgb; |
1113 | Diffuse = vec3 (0.0); |
1114 | Specular = vec3 (0.0); |
1115 | vec3 aPoint = thePoint.xyz / thePoint.w; |
1116 | for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex) |
1117 | { |
1118 | int aType = occLight_Type (anIndex); |
1119 | if (aType == OccLightType_Direct) |
1120 | { |
1121 | directionalLight (anIndex, theNormal, theView); |
1122 | } |
1123 | else if (aType == OccLightType_Point) |
1124 | { |
1125 | pointLight (anIndex, theNormal, theView, aPoint); |
1126 | } |
1127 | } |
1128 | |
1129 | return vec4 (Ambient, 1.0) * occFrontMaterial_Ambient() |
1130 | + vec4 (Diffuse, 1.0) * occFrontMaterial_Diffuse() |
1131 | + vec4 (Specular, 1.0) * occFrontMaterial_Specular(); |
1132 | } |
1133 | |
1134 | //! Entry point to the Fragment Shader |
1135 | void main() |
1136 | { |
1137 | gl_FragColor = computeLighting (normalize (Normal), |
1138 | normalize (View), |
1139 | Position); |
1140 | } |
1141 | ~~~~~ |