diff --git a/NFAssetBuilder/src/Models.cpp b/NFAssetBuilder/src/Models.cpp index 4d0f83a..03f70ba 100644 --- a/NFAssetBuilder/src/Models.cpp +++ b/NFAssetBuilder/src/Models.cpp @@ -7,11 +7,9 @@ #include void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) { - std::vector obj(&OBJin[0], &OBJin[0] + OBJin.size()); - std::vector mtl(&MTLin[0], &MTLin[0] + MTLin.size()); std::unordered_map mats; - parseMaterials(mats, mtl); + parseMaterials(mats, MTLin); std::vector 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 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& mats, std::vector& mtl) { +void parseMaterials(std::unordered_map& 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 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 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; } \ No newline at end of file diff --git a/NFAssetBuilder/src/include/Models.h b/NFAssetBuilder/src/include/Models.h index 206843f..c9d6cb1 100644 --- a/NFAssetBuilder/src/include/Models.h +++ b/NFAssetBuilder/src/include/Models.h @@ -27,5 +27,6 @@ struct TempMaterial { }; void cookModel(std::string& in, std::string& MTLin, std::string& out); -void parseMaterials(std::unordered_map& mats, std::vector& mtl); -std::vector getNeededTextures(std::string mtl); \ No newline at end of file +void parseMaterials(std::unordered_map& mats, std::string& mtl); +std::vector getNeededTextures(std::string mtl); +std::string getTextureName(std::stringstream& ss); \ No newline at end of file diff --git a/docs/Doxyfile b/docs/Doxyfile index ceb6ad9..69ce232 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -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 diff --git a/docs/images/customfont.png b/docs/images/customfont.png new file mode 100644 index 0000000..a9cc95e Binary files /dev/null and b/docs/images/customfont.png differ diff --git a/docs/images/custommodel.png b/docs/images/custommodel.png index aadd4ba..83388c3 100644 Binary files a/docs/images/custommodel.png and b/docs/images/custommodel.png differ diff --git a/docs/images/examplebuttonhover.png b/docs/images/examplebuttonhover.png new file mode 100644 index 0000000..cf297ef Binary files /dev/null and b/docs/images/examplebuttonhover.png differ diff --git a/docs/images/examplebuttonidle.png b/docs/images/examplebuttonidle.png new file mode 100644 index 0000000..ff96834 Binary files /dev/null and b/docs/images/examplebuttonidle.png differ diff --git a/docs/images/examplebuttonpressed.png b/docs/images/examplebuttonpressed.png new file mode 100644 index 0000000..3ab6c86 Binary files /dev/null and b/docs/images/examplebuttonpressed.png differ diff --git a/docs/images/ui.png b/docs/images/ui.png index 734070a..9968f14 100644 Binary files a/docs/images/ui.png and b/docs/images/ui.png differ diff --git a/docs/pages/1_install.md b/docs/pages/1_install.md index 6b15cd8..56fc38b 100644 --- a/docs/pages/1_install.md +++ b/docs/pages/1_install.md @@ -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. \ No newline at end of file +rely on any external dlls other than the MSVC redistributable. See @ref packagingTut. \ No newline at end of file diff --git a/docs/pages/2_tutorial.md b/docs/pages/2_tutorial.md index 85b5be9..9816d03 100644 --- a/docs/pages/2_tutorial.md +++ b/docs/pages/2_tutorial.md @@ -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. \ No newline at end of file diff --git a/docs/pages/4_assets.md b/docs/pages/4_assets.md index e460bfb..51730c6 100644 --- a/docs/pages/4_assets.md +++ b/docs/pages/4_assets.md @@ -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 + +