Added the doc merger as a demo.

This commit is contained in:
Relintai 2024-01-21 16:08:55 +01:00
parent ff59cac2dd
commit 8cb47aa0d5
11 changed files with 2361 additions and 0 deletions

View File

@ -0,0 +1,8 @@
$NAME$
----------------------------------------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
$CODE$
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -0,0 +1,4 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
$CODE$
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -0,0 +1,53 @@
You have 2 files: `sfw.h` and `sfw.cpp` or `sfwl.h` and `sfwl.cpp` depending on your choice.
Note: You might need to set c++14 level compatibility depending on your compiler. While the codebase is somwhere between
c++89 and c++11, threads use classes from the std namespace that were added in c++14. Nowadays these are usually available
without any special setting, but if your compiler is older (or set differently) you might need to add something like:
`-std=c++14` to your compile commands.
## IDE Setup
If you use an ide, just add these files to your project (so the .cpp file gets compiled), and you are done.
## Manual setup
### g++ / mingw
If you are using a compiler directly, then just add `sfw.cpp` or `sfwl.cpp` to the list of files that you are compiling:
```
g++ -g sfw.cpp main.cpp -o prog
```
Note: -g means add debug information to the executable.
If you are creating object files:
```
g++ -g -c sfw.cpp -o sfw.o
g++ -g -c main.cpp -o main.o
g++ -g sfw.o main.o -o prog
```
### MSVC
If you are using a compiler directly, then just add `sfw.cpp` or `sfwl.cpp` to the list of files that you are compiling:
```
cl /Zi /EHsc /Feprog-vc.exe sfw.cpp main.cpp
```
Note: /Zi means add debug information to the executable.
If you are creating object files:
```
cl /EHsc /Zi /c sfw.cpp /Fo:sfw.obj
cl /EHsc /Zi /c main.cpp /Fo:main.obj
cl /Zi /EHsc /Feprog-vc.exe sfw.obj main.obj
```

View File

@ -0,0 +1,11 @@
cp -u ../tools/merger/out/sfwl_core/sfwl.h sfwl.h
cp -u .../tools/merger/out/sfwl_core/sfwl.cpp sfwl.cpp
ccache g++ -Wall -g -c sfwl.cpp -o sfwl.o
ccache g++ -Wall -g -c main.cpp -o main.o
#-static-libgcc -static-libstdc++
ccache g++ -Wall -lpthread -static-libgcc -static-libstdc++ -g sfwl.o main.o -o game

View File

@ -0,0 +1,162 @@
<meta charset="utf-8">
**Sample API Doc**
1.1 Release
This is the markdeep generic "Company API" template. Replace
`company-logo-512.png` with your organization's logo and adjust the
`company-api.css` styling to match the desired colors.
See `CA::OpenHandle()` for an example of an auto-generated API link.
The rest of the information on this page is bogus placeholder to show the formatting.
API Modules
====================================================================================
The CA library is a layer on top of the resource manager and parsing libraries that
provides utilities for streaming processing and client-side process construction.
ENUMS
====================================================================================
$ENUMS$
STRUCTS
====================================================================================
$STRUCTS$
CLASSES
====================================================================================
$CLASSES$
Modules
----------------------------------------------------------------------------------------
The CA library contains the APIs for applications to allocate and exchange resources.
!!! Attention Attention
Always read all of the documentation.
[CA APIs](#CA)
: List of APIs to manage external processes.
CA Buffer List APIs
: Methods to process buffer resources separate from computation.
CA Data Structures
: Specifies the data structures used for complex cases.
## Handles
`CA::OpenHandle(const std::string&)`
: Open a reference handle.
`CA::ReadMetaData(const Handle&)`
: Metadata about the event.
`CA::CloseHandle(const Handle&)`
: Free all handle resources, recursively.
CA
====================================================================================
!!! Warning Warning
The API content represents the set of APIs you can use directly. Some APIs
are not documented and we advise you do not use them directly. Using undocumented
APIs can lead to incompatibility when upgrading to later releases.
These examples assume that your directory structure is:
**********************************************************
*
* 📂 ca1
* |
* +-- 📄 bar.txt
* |
* +-- 📂 foo
* | |
* | ⋮
* |
* +-- 📂 xsource
* | |
* | +-- 📂 data
* | | |
* | | +-- 📄 manifest.json
* | | |
* | ⋮ ⋮
* |
* ⋮
**********************************************************
[Directory structure.]
Table
------------------------------------------------------------------
Screen | Factor | Used | Efficiency
----------:|------------:|----------:|---------:
1366x768 | 3x | 1152x672 | 74%
1440x900 | 3x | 1152x672 | 60%
*1600x900* | *4x* | 1536x896 | *96%*
1680x1050 | 4x | 1536x896 | 78%
1920x1080 | 4x | 1536x896 | 66%
*1920x1200*| *5x* | 1920x1120 | *93%*
[A Table]
More Info
------------------------------------------------------------------
******************************************************************
* ^ y
* |
* .---------. .----|----.
* | | | | |
* | *-------> x | *--------> x
* | | | | |
* '----|----' '---------'
* |
* v y
******************************************************************
[Figure 1: Coordinate Example]
-----
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GLSL
vec3 sphNormal(in vec3 pos, in vec4 sph) {
return normalize(pos-sph.xyz);
}
vec3 camera(vec2 U, vec2 r, vec3 ro, vec3 la, float fl) {
vec2 uv = (U - r*.5)/r.y;
vec3 fwd = normalize(la-ro),
rgt = normalize(vec3(fwd.z, 0., -fwd.x));
return normalize(fwd + fl*uv.x*rgt + fl*uv.y*cross(fwd, rgt));
}
float vMap(vec3 p) {
float hit = 0.0;
vec2 h2 = hash22(floor(p.xz*0.25));
if (p.z > 0.0) {
if (p.y < -10.0 && h2.x > 0.5) hit=1.0;
if (p.y > 10.0 && h2.y > 0.5) hit=1.0;
}
return hit;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Code listing]
<script>markdeepOptions = {tocStyle:'long', definitionStyle:'long', linkAPIDefinitions: true};</script>
<link rel="stylesheet" href="slate.css">
<!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="markdeep.min.js"></script><script src="https://casual-effects.com/markdeep/latest/markdeep.min.js?"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>

View File

@ -0,0 +1,148 @@
RENDER CORE
<a name="LICENSE_GLAD"></a>
<details><summary>GLAD</summary>
This library uses the glad OpenGL Loader
https://glad.dav1d.de/
</details>
<a name="LICENSE_GLFW"></a>
<details><summary>GLFW</summary>
https://github.com/glfw/glfw
GLFW 3.3.7 - www.glfw.org
A library for OpenGL, window and input
Copyright (c) 2002-2006 Marcus Geelnard
Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would
be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
</details>
<a name="LICENSE_STB"></a>
<details><summary>STB</summary>
STB Single Header Libraries
https://github.com/nothings/stb
3rd_stb_image_write.h
3rd_stb_image.h
3rd_stb_truetype.h
This software is available under 2 licenses -- choose whichever you prefer.
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</details>
<a name="LICENSE_Font"></a>
<details><summary>Font</summary>
Font
bm-mini.zip (public domain font)
http://bitmapmania.m78.com
cooz@m78.com
</details>
<a name="LICENSE_Font_Data_Tables"></a>
<details><summary>Font Data Tables</summary>
Font Data Tables
The data tables are coming from Dear Imgui.
Re-licensed under permission as MIT-0.
Original License:
https://github.com/ocornut/imgui
The MIT License (MIT)
Copyright (c) 2014-2024 Omar Cornut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</details>

View File

@ -0,0 +1,611 @@
#include "sfwl.h"
void print_list(const List<String> &list) {
for (const List<String>::Element *E = list.front(); E; E = E->next()) {
ERR_PRINT(E->get());
}
}
void print_class_index_keys(const HashMap<String, String> &class_index) {
for (const HashMap<String, String>::Element *E = class_index.front(); E; E = E->next) {
ERR_PRINT(E->key());
}
}
String get_structure_name(const String &data) {
String fl = data.get_slicec('{', 0);
String l = fl.get_slicec('\n', fl.get_slice_count("\n") - 1);
l = l.get_slicec(':', 0);
l = l.replace("struct", "").replace("class", "").replace("enum", "").replace("union", "").strip_edges();
return l;
}
String get_structure_parents(const String &data) {
String fl = data.get_slicec('{', 0);
String l = fl.get_slicec('\n', fl.get_slice_count("\n") - 1);
if (!l.contains(":")) {
return String();
}
l = l.get_slicec(':', 1);
//l = l.replace("public", "").replace("protected", "").replace("private", "");
l = l.strip_edges();
return l;
}
bool is_structure_template_specialization_or_parent_is_template(const String &data) {
String fl = data.get_slicec('\n', 0);
if (fl.contains("<")) {
return true;
}
return get_structure_parents(data).contains("<");
}
String generate_section_class_list(const List<String> &list, const String &cls_prefix, const HashSet<String> &used_keywords) {
String code_template = FileAccess::get_file_as_string("code_remaining_template.md.html");
String d;
for (const List<String>::Element *E = list.front(); E; E = E->next()) {
String c = E->get();
String sname = get_structure_name(c);
if (sname.empty()) {
//ERR_PRINT(sname);
continue;
}
if (used_keywords.has(cls_prefix + sname)) {
continue;
}
d += code_template.replace("$CODE$", c.xml_escape(true)).replace("$NAME$", sname);
}
return d;
}
void generate_class_index(const List<String> &list, const String &cls_prefix, HashMap<String, String> *cls_index) {
ERR_FAIL_COND(!cls_index);
for (const List<String>::Element *E = list.front(); E; E = E->next()) {
String c = E->get();
String sname = get_structure_name(c);
if (sname.empty()) {
//ERR_PRINT(sname);
continue;
}
(*cls_index)[cls_prefix + sname] = c;
}
}
List<String> get_template_keywords(const String &tmpl) {
List<String> ret;
//awful, but oh well
Vector<String> sp = tmpl.split("|||");
ERR_FAIL_COND_V_MSG(sp.size() % 2 == 0, ret, "Template has unterminated keywords!");
for (int i = 1; i < sp.size(); i += 2) {
ret.push_back(sp[i]);
}
return ret;
}
List<String> process_classes_and_structs(const List<String> &list) {
List<String> ret;
for (const List<String>::Element *E = list.front(); E; E = E->next()) {
String s = E->get();
s = s.replace(" _FORCE_INLINE_ ", " ");
s = s.replace("_FORCE_INLINE_ ", "");
s = s.replace(" _NO_DISCARD_CLASS_ ", " ");
s = s.replace(" inline ", " ");
s = s.replace("inline ", "");
Vector<String> lines = s.split("\n");
if (lines.size() == 0) {
continue;
}
if (lines.size() == 1) {
ret.push_back(s);
continue;
}
String stripped;
//remove method implementations
int current_scope_count = 0;
int current_target_scope_count = -1;
int current_parenthesis_scope_count = 0;
bool in_method = false;
bool method_signature_found = false;
bool in_enum = false;
int enum_scope_start = 0;
String processed_line;
for (int i = 0; i < lines.size(); ++i) {
String l = lines[i];
if (l.strip_edges(true, false).begins_with("#")) {
// Skip #if-s
// Note this will fail for multi line defines, But those currently does not appear in class definitions
stripped += l + "\n";
continue;
}
if (l.contains("enum ")) {
in_enum = true;
enum_scope_start = current_scope_count;
}
for (int j = 0; j < l.length(); ++j) {
CharType current_char = l[j];
if (current_char == '{') {
++current_scope_count;
} else if (current_char == '}') {
--current_scope_count;
if (in_enum) {
if (enum_scope_start == current_scope_count) {
in_enum = false;
}
continue;
}
if (in_method) {
if (current_target_scope_count == current_scope_count) {
//found method end
in_method = false;
processed_line += ";";
}
}
}
if (in_enum) {
continue;
}
if (method_signature_found) {
if (current_char == '(') {
++current_parenthesis_scope_count;
continue;
} else if (current_char == ')') {
if (current_parenthesis_scope_count > 1) {
--current_parenthesis_scope_count;
continue;
} else {
method_signature_found = false;
in_method = true;
processed_line += l.substr_index(0, j + 1);
}
} else {
continue;
}
}
if (!in_method) {
if (current_char == '(') {
current_parenthesis_scope_count = 1;
method_signature_found = true;
current_target_scope_count = current_scope_count;
}
}
if (in_method) {
if (current_char == ';') {
if (current_target_scope_count == current_scope_count) {
//No implementation
in_method = false;
processed_line += ";";
}
}
}
}
if (!in_method) {
if (processed_line.size() != 0) {
stripped += processed_line + "\n";
processed_line.clear();
} else {
stripped += l + "\n";
}
}
}
ret.push_back(stripped.strip_edges());
}
return ret;
}
void process_file(const String &path, const String &out_file, const String &template_file, bool write_remaining) {
String file_data = FileAccess::get_file_as_string(path);
LOG_MSG("Processing file: " + path);
file_data = file_data.replace("\r", "");
// Strip comments probably in probably the worst (but simplest) way possible
List<String> file_lines_no_comments;
Vector<String> fl = file_data.split("\n");
file_data.clear();
bool in_multiline_comment = false;
bool in_comment = false;
for (int i = 0; i < fl.size(); ++i) {
String l = fl[i];
if (in_comment) {
if (l[l.length() - 1] != '\\') {
//if escaped newline in // style comment, then this will be skipped
in_comment = false;
continue;
}
}
String final_line;
CharType last_char = '\0';
int comment_start_index = 0;
bool had_comment = false;
for (int j = 0; j < l.length(); ++j) {
CharType current_char = l[j];
if (!in_multiline_comment) {
if (last_char == '/' && current_char == '*') {
in_multiline_comment = true;
had_comment = true;
final_line += l.substr_index(comment_start_index, j - 1);
comment_start_index = j - 1;
} else if (last_char == '/' && current_char == '/') {
had_comment = true;
final_line += l.substr_index(comment_start_index, j - 1);
in_comment = true;
break;
}
} else {
if (last_char == '*' && current_char == '/') {
comment_start_index = j + 1;
had_comment = true;
in_multiline_comment = false;
//to make sure */* wont be read as both the end and beginning of a comment block on the next iteration
++j;
current_char = '\0';
}
}
last_char = current_char;
}
if (in_comment) {
if (l[l.length() - 1] != '\\') {
//if escaped newline in // style comment, then this will be skipped
in_comment = false;
}
}
if (!had_comment && !in_multiline_comment) {
file_lines_no_comments.push_back(l);
} else {
if (!final_line.empty()) {
file_lines_no_comments.push_back(final_line);
}
}
}
fl.clear();
//print_list(file_lines_no_comments);
// Strip more than one empty lines in a row
List<String> file_lines_no_comments_processed;
int current_empty_line_count = 0;
for (const List<String>::Element *E = file_lines_no_comments.front(); E; E = E->next()) {
String l = E->get();
if (l.strip_edges().empty()) {
++current_empty_line_count;
if (current_empty_line_count <= 1) {
file_lines_no_comments_processed.push_back(l);
}
} else {
current_empty_line_count = 0;
file_lines_no_comments_processed.push_back(l);
}
}
//print_list(file_lines_no_comments_processed);
file_lines_no_comments.clear();
// in global scope
List<String> enums;
List<String> structs;
List<String> classes;
enum Types {
TYPE_NONE = 0,
TYPE_ENUM,
TYPE_STRUCT,
TYPE_CLASS,
};
Types current_type = TYPE_NONE;
int current_scope_level = 0;
String current_str;
for (const List<String>::Element *E = file_lines_no_comments_processed.front(); E; E = E->next()) {
String l = E->get();
if (current_type == TYPE_NONE) {
if (l.contains("template")) {
current_str = l + "\n";
continue;
}
//Not we should be able to do this, because of how the code style is
if (l.contains("enum ") && l.contains("{")) {
if (l.contains("}")) {
enums.push_back(current_str.strip_edges());
//ERR_PRINT("TYPE_ENUM");
//ERR_PRINT(current_str);
current_str.clear();
continue;
}
// We only care about global scope stuff, so this should always work
current_scope_level = 1;
current_type = TYPE_ENUM;
current_str += l + "\n";
continue;
} else if (l.contains("struct ") && l.contains("{")) {
if (l.contains("}")) {
structs.push_back(current_str);
//ERR_PRINT("TYPE_STRUCT");
//ERR_PRINT(current_str);
current_str.clear();
continue;
}
current_scope_level = 1;
current_type = TYPE_STRUCT;
current_str += l + "\n";
continue;
} else if (l.contains("class ") && l.contains("{")) {
if (l.contains("}")) {
classes.push_back(current_str);
//ERR_PRINT("TYPE_CLASS");
//ERR_PRINT(current_str);
current_str.clear();
continue;
}
current_scope_level = 1;
current_type = TYPE_CLASS;
current_str += l + "\n";
continue;
}
if (!current_str.empty()) {
current_str.clear();
}
} else {
for (int j = 0; j < l.length(); ++j) {
CharType current_char = l[j];
if (current_char == '}') {
--current_scope_level;
if (current_scope_level == 0) {
current_str += l + "\n";
switch (current_type) {
case TYPE_NONE:
//cant happen
break;
case TYPE_ENUM:
enums.push_back(current_str.strip_edges());
//ERR_PRINT("TYPE_ENUM");
break;
case TYPE_STRUCT:
structs.push_back(current_str);
//ERR_PRINT("TYPE_STRUCT");
break;
case TYPE_CLASS:
classes.push_back(current_str);
//ERR_PRINT("TYPE_CLASS");
break;
}
//ERR_PRINT(current_str);
current_type = TYPE_NONE;
current_str.clear();
continue;
}
} else if (current_char == '{') {
++current_scope_level;
}
}
current_str += l + "\n";
}
}
file_lines_no_comments_processed.clear();
structs = process_classes_and_structs(structs);
classes = process_classes_and_structs(classes);
//ERR_PRINT("ENUMS");
//print_list(enums);
//ERR_PRINT("STRUCTS");
//print_list(structs);
//ERR_PRINT("CLASSES");
//print_list(classes);
/*
ERR_PRINT("ENUMS");
for (const List<String>::Element *E = enums.front(); E; E = E->next()) {
ERR_PRINT(get_structure_name(E->get()));
}
ERR_PRINT("STRUCTS");
for (const List<String>::Element *E = structs.front(); E; E = E->next()) {
ERR_PRINT(get_structure_name(E->get()));
ERR_PRINT(get_structure_parents(E->get()));
ERR_PRINT("=====");
if (is_structure_template_specialization_or_parent_is_template(E->get())) {
ERR_PRINT("!!!!!!");
}
}
ERR_PRINT("CLASSES");
for (const List<String>::Element *E = classes.front(); E; E = E->next()) {
ERR_PRINT(get_structure_name(E->get()));
ERR_PRINT(get_structure_parents(E->get()));
ERR_PRINT("=====");
if (is_structure_template_specialization_or_parent_is_template(E->get())) {
ERR_PRINT("!!!!!!");
}
}*/
//ERR_PRINT("COUNT");
//ERR_PRINT(itos(enums.size()));
//ERR_PRINT(itos(structs.size()));
//ERR_PRINT(itos(classes.size()));
HashMap<String, String> class_index;
generate_class_index(enums, "ENUM_", &class_index);
generate_class_index(structs, "STRUCT_", &class_index);
generate_class_index(classes, "CLASS_", &class_index);
//print_class_index_keys(class_index);
String index_template = FileAccess::get_file_as_string(template_file);
String code_template = FileAccess::get_file_as_string("code_template.md.html");
List<String> index_template_keywords = get_template_keywords(index_template);
HashSet<String> used_keywords;
//print_list(index_template_keywords);
String index_str = index_template;
for (const List<String>::Element *E = index_template_keywords.front(); E; E = E->next()) {
String c = E->get();
ERR_CONTINUE_MSG(!class_index.has(c), "!class_index.has(): " + c);
String keyword = "|||" + E->get() + "|||";
String class_str = class_index[c];
//String class_name = get_structure_name(class_str);
index_str = index_str.replace(keyword, code_template.replace("$CODE$", class_str.xml_escape(true)));
used_keywords.insert(c);
}
String compilation_no_renderer = FileAccess::get_file_as_string("compilation_no_renderer.md.html");
String compilation_renderer = FileAccess::get_file_as_string("compilation_renderer.md.html");
String licenses_renderer = FileAccess::get_file_as_string("licenses_renderer.md.html");
String markdeep_min_js = FileAccess::get_file_as_string("markdeep.min.js");
String markdeep_theme = FileAccess::get_file_as_string("slate.css");
index_str = index_str.replace("$FILE_Compilation_No_Renderer$", compilation_no_renderer);
index_str = index_str.replace("$FILE_Compilation_Renderer$", compilation_renderer);
index_str = index_str.replace("$LICENSES_Renderer$", licenses_renderer);
index_str = index_str.replace("$MARKDEEP_MIN_JS$", markdeep_min_js);
index_str = index_str.replace("$MARKDEEP_THEME$", markdeep_theme);
FileAccess::write_file("out/" + out_file, index_str);
if (write_remaining) {
//Generate a list from the unused classes.
String index_remaining_template = FileAccess::get_file_as_string("index_remaining_template.md.html");
String d = index_remaining_template;
d = d.replace("$ENUMS$", generate_section_class_list(enums, "ENUM_", used_keywords));
d = d.replace("$STRUCTS$", generate_section_class_list(structs, "STRUCT_", used_keywords));
d = d.replace("$CLASSES$", generate_section_class_list(classes, "CLASS_", used_keywords));
FileAccess::write_file("out/index_remaining.gen.md.html", d);
}
}
int main(int argc, char **argv) {
SFWCore::setup();
DirAccess dir;
if (!dir.dir_exists("out")) {
dir.make_dir("out");
dir.copy("markdeep.min.js", "out/markdeep.min.js");
dir.copy("slate.css", "out/slate.css");
}
bool write_remaining = false;
List<String> args;
String out_file = "index.md.html";
String template_file = "index_template.md.html";
for (int i = 1; i < argc; ++i) {
String arg = String::utf8(argv[i]);
if (arg == "--remaining") {
write_remaining = true;
continue;
} else if (arg.begins_with("-o")) {
out_file = arg.trim_prefix("-o").strip_edges();
continue;
} else if (arg.begins_with("-t")) {
template_file = arg.trim_prefix("-t").strip_edges();
continue;
}
args.push_back(arg);
}
for (List<String>::Element *E = args.front(); E; E = E->next()) {
process_file(E->get(), out_file, template_file, write_remaining);
}
SFWCore::cleanup();
return 0;
}

10
demos/sfwl_doc_merger/markdeep.min.js vendored Normal file

File diff suppressed because one or more lines are too long

3
demos/sfwl_doc_merger/run.sh Executable file
View File

@ -0,0 +1,3 @@
./game sfwl.h -tsfw_full_template.html --remaining

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,306 @@
body#md {
font-weight: 400;
font-size: 16px;
font-family: Arial, Helvetica, "sans serif";
text-align: left;
line-height: 170%;
}
/* reset heading/link fonts to that of body */
.md a,
.md div.title, contents, .md .tocHeader,
.md h1, .md h2, .md h3, .md h4, .md h5, .md h6,
.md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4, .md .nonumberh5, .md .nonumberh6,
.md .shortTOC, .md .mediumTOC, .md .longTOC {
font-family: inherit;
}
.md .tocHeader {
border: none;
margin-top: 25px;
font-size: 100%;
font-family: inherit;
font-weight: 300;
}
.md .longTOC .level1 {
font-weight: 300;
margin-bottom: -30px;
}
.md div.title, .md div.subtitle, .md h1, .md h2, .md h3, .md h4, .md h5, .md h6 {
font-family: Arial, Helvetica, "sans serif";
font-weight: 300;
}
.md div.title {
font-size: 43px;
text-align: left;
margin-bottom: 0px;
}
.md div.subtitle {
text-align: left;
font-size: 115%;
}
.md div.afterTitles {
margin-top: 20px;
margin-left: -20px;
margin-right: -20px;
height: 0px;
border-bottom: 1px solid #000;
box-shadow: 0px 1px 2px rgba(0,0,0,0.5);
}
.md div.afterTitles + p {
margin-top: 30px;
}
.md h1 {
font-size: 175%;
margin-bottom: 25px;
margin-left:-20px;
margin-right:-20px;
padding-left:20px;
padding-top:25px;
border-bottom: none;
border-top:6px solid #5a5a5a;
}
.md h2 {
font-size: 150%;
border: none;
}
.md h3, .md h4, .md h5, .md h6 {
font-size: 120%;
}
.md code {
font-size: 90%;
background: #eee;
padding-left: 2px;
padding-right: 2px;
}
.md .longTOC {
font-family: 'Roboto', Arial, Helvetica, "sans serif";
font-weight: 300;
}
.md pre.listing {
font-size: 100%;
width: 97%; /*hack, i dont know how to align this width with every other element <@r-lyeh*/
margin-left: 8px;
}
.md pre.listing code {
font-weight: unset;
background: none;
color: unset;
}
/* Darkmode, wide screen: TOC on side */
@media screen and (min-device-width: 600px) {
.md .longTOC {
display: block;
white-space: nowrap;
width: 170px;
border-right: 1px solid #777;
overflow-y:scroll;
font-family: inherit;
background: #202020;
position: fixed;
left: 0px;
top: 0px;
bottom:0px;
margin: 0px;
padding: 0px;
padding-left:10px;
}
body {
position: absolute;
left: 200px;
right:0px;
margin: 0px;
padding: 0px;
max-width: unset;
padding-right: 15px;
}
}
/* Dark mode with side TOC on screen */
@media screen {
.md div.longTOC {
font-size: 15px;
}
.md svg.diagram {
stroke: #ccc;
fill: #ccc;
}
.md svg.diagram .opendot {
fill: #000;
}
.md table.table {
box-shadow: 0px 1px 2px rgba(0,0,0,0.5);
background-color: #2a2a2a;
}
.md table.table tr:nth-child(even) {
background-color: #202020;
}
.md table.table td, .md table.table th {
border: 1px solid #202020;
}
.md table.table th {
color: #000;
}
.md pre.listing {
background: #202020;
border: 1px solid #777;
box-shadow: 0px 1px 2px rgba(0,0,0,0.5);
}
.md code {
color: #fff;
background: unset;
}
.md .tocTop {
display: inline;
}
.md div.afterTitles {
border-bottom: 1px solid #fff;
}
.md div.title, .md div.subtitle, .md h1, .md h2, .md h3, .md h4, .md h5, .md h6 {
color: #fff;
}
.hljs-comment,.hljs-quote{color:#a0f0aa}.hljs-variable,.hljs-template-variable,.hljs-tag,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-regexp,.hljs-deletion{color:#cc6666}.hljs-number,.hljs-built_in,.hljs-builtin-name,.hljs-literal,.hljs-type,.hljs-params,.hljs-meta,.hljs-link{color:#de935f}.hljs-attribute{color:#f0c674}.hljs-string,.hljs-symbol,.hljs-bullet,.hljs-addition{color:#b5bd68}.hljs-title,.hljs-section{color:#81a2be}.hljs-keyword,.hljs-selector-tag{color:#b294bb}.hljs{display:block;overflow-x:auto;background:#1d1f21;color:#c5c8c6;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}
.hljs-function .hljs-title { color:#81a2be}
body {
color: #ccc;
background: #3a3a3a;
}
.md div.title, .md h1, .md h2, .md h3, .md h4, .md h5, .md h6, .md .longTOC a, .md .longTOC code, .md a:link, .md a:visited {
text-shadow: 0px 1px 2px rgba(0,0,0,0.5);
}
.md .admonition {
position: unset;
box-shadow: 0px 1px 2px rgba(0,0,0,0.5);
background: #202020;
border: 1px solid rgba(68,138,255,1);
border-left: 2.5rem solid rgba(68,138,255,1);
}
.md .admonition-title {
border-bottom: 1px solid rgba(68,138,255,1);
}
.md .admonition.warn, .md .admonition.warning {
border: 1px solid rgba(255,170,0,1);
border-left: 2.5rem solid rgba(255,170,0,1);
background: #202020;
}
.md .admonition.warn .admonition-title, .md .admonition.warning .admonition-title {
border-bottom: 1px solid rgba(68,138,255,1);
}
.md .admonition.tip {
border: 1px solid rgba(68,138,255,1);
border-left: 2.5rem solid rgba(68,138,255,1);
background: #202020;
}
.md .admonition.tip .admonition-title {
border-bottom: 1px solid rgba(68,138,255,1);
}
.md .admonition.error {
border: 1px solid rgba(255,23,68,1);
border-left: 2.5rem solid rgba(255,23,68,1);
background: #202020;
}
.md .admonition.error .admonition-title {
border-bottom: 1px solid rgba(255,23,68,1);
}
.md .longTOC a, .md .longTOC code, .md a:link, .md a:visited, .md a:link code, .md a:visited code {
color: #80bfff !important;
}
}
/* Cool details theme from FWK */
/* Stylize details/summary html tags */
/* Credits: https://dev.to/vtrpldn/show-and-hide-content-easily-with-details-and-summary-html-tags-3eif */
/* The --padding variable help us control the <details> and <summary> spacing */
:root {
--padding: 4px; /*16px;*/ /*<@r-lyeh*/
}
details {
padding: 0 var(--padding);
box-shadow: inset 0 0 0 0px; /*4px;*/ /*<@r-lyeh*/
border-radius: 1px; /*4px*/ /*<@r-lyeh*/
background-color:#333; /*<@r-lyeh*/
margin: -15px 0 0 0; /*<@r-lyeh*/ /*fits all <details> together */
}
summary {
padding-left: 16px; /*<@r-lyeh*/
text-overflow: ellipsis;
/* Both of the following are required for text-overflow */
white-space: nowrap;
overflow: hidden;
}
details[open] {
padding-bottom: var(--padding);
box-shadow: inset 0 0 0 1px; /*<@r-lyeh*/
background-color:transparent; /*<@r-lyeh*/
}
details > summary {
display: flex;
padding: var(--padding);
margin: 0 calc(var(--padding) * -1);
border-radius: 4px;
/*font-size: 24px;*/ /*<@r-lyeh*/
cursor: pointer;
justify-content: space-between;
list-style: none; /* Hides the default arrow */
}
details[open] > summary {
box-shadow: 0 0px; /*4px;*/ /*<@r-lyeh*/
}
/* Adds an (+) icon when the <details> is closed... */
details > summary::after {
content: "⇕";
}
/* ...and switches it when <details> is open (-) icon */
details[open] > summary::after {
content: "⇕";
}
/* Removes the ugly default arrow on Chrome */
details > summary::-webkit-details-marker {
display: none;
}