Fixed some issues in the asset builder; User guide work
@ -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;
|
||||
}
|
@ -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);
|
@ -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
After Width: | Height: | Size: 236 KiB |
Before Width: | Height: | Size: 547 KiB After Width: | Height: | Size: 618 KiB |
BIN
docs/images/examplebuttonhover.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
docs/images/examplebuttonidle.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
docs/images/examplebuttonpressed.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 706 KiB After Width: | Height: | Size: 645 KiB |
@ -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.
|
@ -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.
|
@ -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"));
|
||||
~~~
|
@ -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
|
||||
===
|
||||
|
@ -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
|
||||
|