Fixed some issues in the asset builder; User guide work

This commit is contained in:
Grayson Riffe (Laptop) 2022-01-05 10:48:22 -06:00
parent a85f77c023
commit f2bd6e457a
15 changed files with 150 additions and 51 deletions

View File

@ -7,11 +7,9 @@
#include <set>
void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
std::vector<char> obj(&OBJin[0], &OBJin[0] + OBJin.size());
std::vector<char> mtl(&MTLin[0], &MTLin[0] + MTLin.size());
std::unordered_map<std::string, TempMaterial*> mats;
parseMaterials(mats, mtl);
parseMaterials(mats, MTLin);
std::vector<float> vbRaw, tcRaw, vnRaw;
std::string usingMat;
@ -19,19 +17,16 @@ void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
bool tcPresent = false, vnPresent = false;
size_t position = 0;
while (true) {
size_t nextLine = std::search(obj.begin() + position, obj.end(), "\n", "\n" + std::strlen("\n")) - (obj.begin() + position);
if (!nextLine)
break;
std::vector<char> line(&obj[position], &obj[position + nextLine]);
position += nextLine + 1;
std::stringstream ss(std::string(&line[0], line.size()));
std::stringstream ss(OBJin);
std::string line;
while (std::getline(ss, line)) {
std::stringstream ss2(line);
std::string firstWord;
ss >> firstWord;
ss2 >> firstWord;
if (std::strcmp(&firstWord[0], "v") == 0) {
float x = 0.0f, y = 0.0f, z = 0.0f;
ss >> x >> y >> z;
ss2 >> x >> y >> z;
vbRaw.push_back(x);
vbRaw.push_back(y);
vbRaw.push_back(z);
@ -39,21 +34,21 @@ void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
else if (std::strcmp(&firstWord[0], "vt") == 0) {
tcPresent = true;
float u = 0.0f, v = 0.0f;
ss >> u >> v;
ss2 >> u >> v;
tcRaw.push_back(u);
tcRaw.push_back(v);
}
else if (std::strcmp(&firstWord[0], "vn") == 0) {
vnPresent = true;
float x = 0.0f, y = 0.0f, z = 0.0f;
ss >> x >> y >> z;
ss2 >> x >> y >> z;
vnRaw.push_back(x);
vnRaw.push_back(y);
vnRaw.push_back(z);
}
else if (std::strcmp(&firstWord[0], "usemtl") == 0) {
std::string matName;
ss >> matName;
ss2 >> matName;
usingMat = matName;
}
else if (std::strcmp(&firstWord[0], "f") == 0) {
@ -64,8 +59,8 @@ void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
unsigned int vertexIndex[3], uvIndex[3], vnIndex[3];
char temp;
ss >> vertexIndex[0] >> temp >> uvIndex[0] >> temp >> vnIndex[0] >> vertexIndex[1] >> temp >> uvIndex[1] >> temp >> vnIndex[1] >> vertexIndex[2] >> temp >> uvIndex[2] >> temp >> vnIndex[2];
if (ss.rdbuf()->in_avail() > 1)
ss2 >> vertexIndex[0] >> temp >> uvIndex[0] >> temp >> vnIndex[0] >> vertexIndex[1] >> temp >> uvIndex[1] >> temp >> vnIndex[1] >> vertexIndex[2] >> temp >> uvIndex[2] >> temp >> vnIndex[2];
if (ss2.rdbuf()->in_avail() > 1)
Error("Model has non-triangle faces!");
mats[usingMat]->vbIndices.push_back(vertexIndex[0]);
mats[usingMat]->vbIndices.push_back(vertexIndex[1]);
@ -262,43 +257,41 @@ void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
out.append((char*)vboIndices.data(), indicesSize);
}
void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::vector<char>& mtl) {
void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::string& mtl) {
std::string currMat;
size_t position = 0;
while (true) {
size_t nextLine = std::search(mtl.begin() + position, mtl.end(), "\n", "\n" + std::strlen("\n")) - (mtl.begin() + position);
if (position + nextLine >= mtl.size())
break;
std::vector<char> line(&mtl[position], &mtl[position + nextLine]);
position += nextLine + 1;
std::stringstream ss(std::string(&line[0], line.size()));
std::stringstream ss(mtl);
std::string line;
while (std::getline(ss, line)) {
std::stringstream ss2(line);
std::string firstWord;
ss >> firstWord;
ss2 >> firstWord;
if (std::strcmp(&firstWord[0], "newmtl") == 0) {
ss >> currMat;
ss2 >> currMat;
mats[currMat] = new TempMaterial;
}
else if (std::strcmp(&firstWord[0], "Kd") == 0) {
float r = 0.0f, g = 0.0f, b = 0.0f;
ss >> r >> g >> b;
ss2 >> r >> g >> b;
mats[currMat]->diffuseColor = Vec3(r, g, b);
}
else if (std::strcmp(&firstWord[0], "map_Kd") == 0) {
std::string texName = getNewLine(ss);
std::string texName = getTextureName(ss2);
mats[currMat]->diffuseTextureName = texName;
}
else if (std::strcmp(&firstWord[0], "map_Ks") == 0) {
std::string texName = getNewLine(ss);
std::string texName = getTextureName(ss2);
mats[currMat]->specularTextureName = texName;
}
else if (std::strcmp(&firstWord[0], "map_Bump") == 0) {
std::string texName = getNewLine(ss);
std::string texName = getTextureName(ss2);
mats[currMat]->normalTextureName = texName;
}
else if (std::strcmp(&firstWord[0], "Ns") == 0) {
float s = 0.0f;
ss >> s;
ss2 >> s;
mats[currMat]->shininess = s;
}
}
@ -330,4 +323,12 @@ std::vector<std::string> getNeededTextures(std::string mtl) {
for (const auto& curr : tex)
out.push_back(curr);
return out;
}
std::string getTextureName(std::stringstream& ss) {
std::string out;
std::getline(ss, out);
out = out.substr(out.find_last_of("\\/") + 1);
return out;
}

View File

@ -27,5 +27,6 @@ struct TempMaterial {
};
void cookModel(std::string& in, std::string& MTLin, std::string& out);
void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::vector<char>& mtl);
std::vector<std::string> getNeededTextures(std::string mtl);
void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::string& mtl);
std::vector<std::string> getNeededTextures(std::string mtl);
std::string getTextureName(std::stringstream& ss);

View File

@ -169,7 +169,7 @@ HTML_HEADER = header.html
HTML_FOOTER = footer.html
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET = theme.css
HTML_EXTRA_FILES = images/favicon.png
HTML_EXTRA_FILES = images/favicon.png videos/buttondemo.mp4
HTML_COLORSTYLE_HUE = 30
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80

BIN
docs/images/customfont.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 KiB

After

Width:  |  Height:  |  Size: 618 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 KiB

After

Width:  |  Height:  |  Size: 645 KiB

View File

@ -44,11 +44,10 @@ project (`NFApp` by default), can be renamed at any time.
@note The template project is setup to build *Debug* and *Release* configurations. The *Debug*
configuration includes a console window with debug output. The *Release* configuration does
not have this console window. By default, the current configuration can be changed in the
top toolbar.
not have this console window, and will run as fast as possible with maximum optimizations.
By default, the current configuration can be changed in the top toolbar.
Once the solution has been opened, you can find the `main.cpp` file inside the `src` folder
as shown below.
Once the solution has been opened, you can find the `main.cpp` file inside the `src` folder:
@image html blanktemplate.png "The template opened in Visual Studio" width=70%
@ -57,7 +56,7 @@ your assets. You can also also hit the default keyboard shortcut of `Ctrl-Shift-
both your app and assets.
@note When the "Build Assets" project is built, the resulting NFPacks are moved to
the output `assets` directory next to your .exe for you.
the output `assets` directory next to your `.exe` for you.
NF is a **statically-linked** library. This means that your build will not
rely on any external dlls other than the MSVC redistributable.
rely on any external dlls other than the MSVC redistributable. See @ref packagingTut.

View File

@ -15,13 +15,15 @@ main thread of an NF app might be typically doing in the program's lifetime.
@image html applifetime.png "The lifetime of a typical NF app" width=20%
Using the engine's architecture, you might not even write any functions that are called
Using this architecture, you might not even write any functions that are called
from `main`. Most of the code that programs the engine's behavior should be called in
your state's [update function](@ref nf::Gamestate::update).
To allow a translate unit to use the engine, you must include `NothinFancy.h`. This
header contains every class and function you will need.
---
@section createConfigTut Creating a Config
The first step to creating an app is creating an nf::Config. A config describes how the
@ -51,7 +53,7 @@ We then pass this config to an nf::Application
@section createAppTut Creating and Configuring an Application
The nf::Application class represents an instance of the engine. This is the point where
you will attach your states and run the engine.
you will attach your states and run your application.
@note In a program and on a single machine, there can only be one single instance of
this class at a time. Attempting to create mulitple will result in an error.
@ -63,7 +65,7 @@ nf::Application app(conf);
~~~
Constructing an application doesn't do much. It merely allows you to access the member
functions to setup your application.
functions to setup your application and run it later.
Here are some functions you might want to call at this point:
@ -85,7 +87,7 @@ Once these functions have been called, the app can be run:
~~~cpp
CustomGamestate* customState = new CustomGamestate; //Inherits nf::Gamestate
app.addState(customState, "State 1"); //"State One" is this state's identifier.
app.addState(customState, "State 1"); //"State 1" is this state's identifier.
app.setDefaultState("State 1"); //Will error without this
app.run(); //Blocks until exit
~~~
@ -422,6 +424,18 @@ sound.setPosition(nf::Vec3(10.0, 25.0, 15.0));
sound.setEntity(entity2);
~~~
@section gamestateSwitchTut Switching Gamestates
To unload the current state and load another state, call:
~~~cpp
app->changeState("State 2"); //String identifier we defined earlier
~~~
@note The currently running state that calls [changeState](@ref nf::Application::changeState)
does not stop running right away. The `update` and `render` functions of that state are called
until the loading screen fades in completely.
@section debuggingTut Debugging Your App
NF has a number of @ref macros that you can use in your debug builds to help you develop
@ -447,5 +461,6 @@ Other than that, a build can be very simple:
- **NFApp.exe** - The application binary which is named from the MSVC project
- **assets** - The folder which holds your NFPacks
- **base.nfpack** - The NFPack that holds both critical and default assets
- **Your Assets** - The rest of the NFPacks your application needs
These are the only files you need to package in your build.

View File

@ -28,6 +28,8 @@ function while passing in the name of the pack, including the extension.
5. Call the [get](@ref nf::AssetPack::get) function with the name of the asset file
to retrieve an Asset pointer to use in various `create` functions.
---
@section customModels Models
To import a custom model into NF, it must first meet some requirements:
@ -91,10 +93,89 @@ Used in the tutorial app, our model looks like this:
@image html custommodel.png "Our teapot in the engine" width=50%
---
@section customFonts Fonts
Custom fonts can be implemented very easily. All you need to do is include a TrueType
`.ttf` font in your assets and reference it when you create texts:
~~~cpp
text.create("Cool Font", nf::Vec2(0.1, 0.2), nf::Vec3(1.0f), 1.0f, 1.0f, ap.get("font.ttf"));
~~~
@image html customfont.png "A text using the font \"Corsiva\"" width=30%
---
@section customButtons Button Textures
The default button textures can be overridden by adding textures with certain names
to your assets where "name" can be anything you choose as an identifier.
- **name_buttonidle** - The texture that shows when the button is idle
- **name_buttonhover** - The texture that shows when the mouse hovers over the button
- **name_buttonpressed** - The texture that shows when the button clicked
These images can be of any accepted image format. They should all have the same dimensions.
@warning If a button texture set is incomplete, the engine will error when it reads the
NFPack.
Once the textures are in place, they can be accessed in your nf::AssetPack like
this:
~~~cpp
//Text can still be added on top, but I already have text on my texture, so I'll leave it blank.
button.create(nf::Vec2(0.1, 0.1), "", ap.get("name.button"));
~~~
With these three textures:
@image html examplebuttonidle.png "Idle" width=20%
@image html examplebuttonhover.png "Hover" width=20%
@image html examplebuttonpressed.png "Pressed" width=20%
We get this result:
@htmlonly
<video src="buttondemo.mp4" autoplay loop muted width=50%>
@endhtmlonly
---
@section customCubemaps Cubemaps
@section customSounds Sounds
Cubemaps are like button textures. Each cubemap consists of 6 textures that are mapped
to the inside of a giant, unreachable cube in your scene. The engine takes care of rendering
it. All you need to do is supply these 6 textures in your assets with specific filenames.
Here, "name" can be anything you choose as an identifier.
- **name_cmfront** - The front texture (-Z direction)
- **name_cmback** - The back texture (+Z direction)
- **name_cmright** - The right texture (+X direction)
- **name_cmleft** - The left texture (-X direction)
- **name_cmtop** - The top texture (+Y direction)
- **name_cmbottom** - The bottom texture (-Y direction)
Once the textures are in place, they can be accessed in your nf::AssetPack like
this:
~~~cpp
cubemap.create(ap.get("name.cm"));
~~~
---
@section customSounds Sounds
Sounds are the easiest to include.
All you need to do is place the sound file in your assets and reference it by name
when creating an nf::Sound object:
~~~cpp
sound.create(ap.get("sound.ogg"));
~~~

View File

@ -1,8 +1,9 @@
@tableofcontents
Nothin' Fancy (abbreviated as NF) is an experimental 3D game engine written in C++
for Windows. It was created by Grayson Riffe in 2021. This manual aims to aid the end-user
with using this engine to create games and visualizations. It contains the
for Windows. The engine allows the user to program 3D applications with high-level
C++. NF was created by Grayson Riffe in 2021. This manual aims to aid the user
with using NF to create games and visualizations. It contains the
[user guide](tutorial.html) and the [API reference](namespaces.html).
@image html logofull.png "Engine Logo" width=15%
@ -25,7 +26,7 @@ at any time.
- Customizable UI
- Text
- Textures
- Buttons also with customizable textures
- Buttons with customizable textures
Example App
===

View File

@ -3,14 +3,15 @@
text-align: left;
}
img:not([src='logofull.png']):not([src="search/mag_sel.svg"]):not([src="doxygen.svg"]):not([src="logo.png"])
video, img:not([src="logo.png"]):not([src='logofull.png']):not([src="search/mag_sel.svg"]):not([src="doxygen.svg"])
{
filter: drop-shadow(0.5em 0.5em 0.5em grey);
}
div.caption
{
margin-top: 0.5em;
margin-top: 0.2em;
margin-bottom: 0.5em;
}
#nav-sync

BIN
docs/videos/buttondemo.mp4 Normal file

Binary file not shown.