diff --git a/Blocks3D.vcproj b/Blocks3D.vcproj
index ebaf57d..e67dd6c 100644
--- a/Blocks3D.vcproj
+++ b/Blocks3D.vcproj
@@ -670,6 +670,14 @@
>
+
+
+
+
+
+
+
+
ThumbnailGeneratorInstance::ThumbnailGeneratorInstance(void)
@@ -13,39 +14,37 @@ ThumbnailGeneratorInstance::ThumbnailGeneratorInstance(void)
ThumbnailGeneratorInstance::~ThumbnailGeneratorInstance(void) {}
+/*
+ * TODO:
+ * Move functions like toggleSky into their own "Lighting" instance
+ * Make this headless, and allow for resolutions greater than the screen resolution
+*/
std::string ThumbnailGeneratorInstance::click(std::string fileType, int cx, int cy, bool hideSky)
{
- // Important things we need
RenderDevice* rd = g_usableApp->getRenderDevice();
GuiRootInstance* guiRoot = g_dataModel->getGuiRoot();
-
const G3D::GImage::Format format = G3D::GImage::stringToFormat(fileType);
-
- // Hide the GUI
- guiRoot->hideGui(true);
+ int prevWidth = rd->width();
+ int prevHeight = rd->height();
+ G3D::GImage imgBuffer(cx, cy, 4);
+ G3D::BinaryOutput binOut;
+
+ guiRoot->hideGui(true);
+ g_usableApp->resize3DView(cx, cy);
- // Disable the sky
if(hideSky)
g_usableApp->toggleSky();
- // Update graphics
g_usableApp->onGraphics(rd);
-
- // Sky SHOULD be gone now, and alpha channel should be present
- G3D::GImage imgBuffer(cx, cy, 4);
rd->screenshotPic(imgBuffer, true, hideSky);
-
- G3D::BinaryOutput binOut;
imgBuffer.encode(format, binOut);
- // Temporary file saving
- std::string fileSave = "./click_output." + fileType;
- std::ofstream out(fileSave.c_str(), std::ios::out | std::ios::binary);
- out.write(reinterpret_cast(binOut.getCArray()), binOut.length());
-
- // Unhide GUI
+ // Convert to Base64 string
+ std::string base64ImgStr = base64_encode(reinterpret_cast(binOut.getCArray()), binOut.length(), false);
+
guiRoot->hideGui(false);
+ g_usableApp->resize3DView(prevWidth, prevHeight);
- return "boop!";
+ return base64ImgStr;
}
diff --git a/click_output.PNG b/click_output.PNG
index eaa12a9..18cdea8 100644
Binary files a/click_output.PNG and b/click_output.PNG differ
diff --git a/src/include/Application.h b/src/include/Application.h
index 0921f96..040c468 100644
--- a/src/include/Application.h
+++ b/src/include/Application.h
@@ -48,16 +48,18 @@ class Application { // : public GApp {
void setFocus(bool isFocused);
int getMode();
void unSetMode();
+
void toggleSky();
CameraController cameraController;
UserInput* userInput;
PropertyWindow* _propWindow;
- void generateShadowMap(const CoordinateFrame& lightViewMatrix) const;
+ void generateShadowMap(const CoordinateFrame& lightViewMatrix) const;
RenderDevice* getRenderDevice();
void selectInstance(Instance* selectedInstance,PropertyWindow* propWindow);
void setMode(int mode);
- SkyRef getSky();
-
+ SkyRef getSky();
+ void resize3DView(int w, int h);
+
Tool * tool;
void changeTool(Tool *);
Mouse mouse;
diff --git a/src/include/base64.h b/src/include/base64.h
new file mode 100644
index 0000000..866505e
--- /dev/null
+++ b/src/include/base64.h
@@ -0,0 +1,35 @@
+//
+// base64 encoding and decoding with C++.
+// Version: 2.rc.08 (release candidate)
+//
+
+#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
+#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
+
+#include
+
+#if __cplusplus >= 201703L
+#include
+#endif // __cplusplus >= 201703L
+
+std::string base64_encode (std::string const& s, bool url = false);
+std::string base64_encode_pem (std::string const& s);
+std::string base64_encode_mime(std::string const& s);
+
+std::string base64_decode(std::string const& s, bool remove_linebreaks = false);
+std::string base64_encode(unsigned char const*, size_t len, bool url = false);
+
+#if __cplusplus >= 201703L
+//
+// Interface with std::string_view rather than const std::string&
+// Requires C++17
+// Provided by Yannic Bonenberger (https://github.com/Yannic)
+//
+std::string base64_encode (std::string_view s, bool url = false);
+std::string base64_encode_pem (std::string_view s);
+std::string base64_encode_mime(std::string_view s);
+
+std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
+#endif // __cplusplus >= 201703L
+
+#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */
diff --git a/src/source/Application.cpp b/src/source/Application.cpp
index eece56f..a0121bf 100644
--- a/src/source/Application.cpp
+++ b/src/source/Application.cpp
@@ -111,6 +111,8 @@ Application::Application(HWND parentWindow) : _propWindow(NULL) { //: GApp(setti
_settings.writeLicenseFile = false;
_settings.logFilename = tempPath + "/g3dlog.txt";
_settings.window.center = true;
+ _settings.window.fsaaSamples = 8;
+
Win32Window* window = Win32Window::create(_settings.window,_hwndRenderer);
ShowWindow(_hwndRenderer, SW_SHOW);
ShowWindow(_hWndMain, SW_SHOW);
@@ -868,6 +870,7 @@ void Application::resizeWithParent(HWND parentWindow)
}
+// These should be moved into a "Lighting" class
G3D::SkyRef Application::getSky()
{
return sky;
@@ -878,6 +881,13 @@ void Application::toggleSky()
_hideSky = !_hideSky;
}
+void Application::resize3DView(int w, int h)
+{
+ Rect2D newViewport = Rect2D::xywh(0, 0, w, h);
+ renderDevice->notifyResize(w, h);
+ renderDevice->setViewport(newViewport);
+}
+
void Application::QuitApp()
{
PostQuitMessage(0);
diff --git a/src/source/Listener/MenuButtonListener.cpp b/src/source/Listener/MenuButtonListener.cpp
index 96add33..4e8575f 100644
--- a/src/source/Listener/MenuButtonListener.cpp
+++ b/src/source/Listener/MenuButtonListener.cpp
@@ -18,8 +18,8 @@ void MenuButtonListener::onButton1MouseClick(BaseButtonInstance* button)
AppendMenu(mainmenu, MF_SEPARATOR, 0, NULL);
// Temporary
- AppendMenu(mainmenu, MF_STRING, 103, "ThumbnailGenerator::click hideSky = true");
- AppendMenu(mainmenu, MF_STRING, 104, "ThumbnailGenerator::click hideSky = false");
+ // AppendMenu(mainmenu, MF_STRING, 103, "ThumbnailGenerator::click hideSky = true");
+ // AppendMenu(mainmenu, MF_STRING, 104, "ThumbnailGenerator::click hideSky = false");
POINT p;
GetCursorPos(&p);
@@ -36,12 +36,17 @@ void MenuButtonListener::onButton1MouseClick(BaseButtonInstance* button)
case 102:
g_usableApp->QuitApp();
break;
+
+ /*
+ // These are only here for future reference
case 103:
g_dataModel->getThumbnailGenerator()->click("PNG", 256, 256, true);
break;
case 104:
- g_dataModel->getThumbnailGenerator()->click("JPEG", 256, 256, false);
+ g_dataModel->getThumbnailGenerator()->click("JPEG", 105, 70, false);
break;
+ */
+
}
}
}
\ No newline at end of file
diff --git a/src/source/base64.cpp b/src/source/base64.cpp
new file mode 100644
index 0000000..7666ef8
--- /dev/null
+++ b/src/source/base64.cpp
@@ -0,0 +1,282 @@
+/*
+ base64.cpp and base64.h
+
+ base64 encoding and decoding with C++.
+ More information at
+ https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
+
+ Version: 2.rc.08 (release candidate)
+
+ Copyright (C) 2004-2017, 2020, 2021 René Nyffenegger
+
+ This source code is provided 'as-is', without any express or implied
+ warranty. In no event will the author 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 source code must not be misrepresented; you must not
+ claim that you wrote the original source code. If you use this source code
+ 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 source code.
+
+ 3. This notice may not be removed or altered from any source distribution.
+
+ René Nyffenegger rene.nyffenegger@adp-gmbh.ch
+
+*/
+
+#include "base64.h"
+
+#include
+#include
+
+ //
+ // Depending on the url parameter in base64_chars, one of
+ // two sets of base64 characters needs to be chosen.
+ // They differ in their last two characters.
+ //
+static const char* base64_chars[2] = {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "+/",
+
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "-_"};
+
+static unsigned int pos_of_char(const unsigned char chr) {
+ //
+ // Return the position of chr within base64_encode()
+ //
+
+ if (chr >= 'A' && chr <= 'Z') return chr - 'A';
+ else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1;
+ else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
+ else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
+ else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
+ else
+ //
+ // 2020-10-23: Throw std::exception rather than const char*
+ //(Pablo Martin-Gomez, https://github.com/Bouska)
+ //
+ throw std::runtime_error("Input is not valid base64-encoded data.");
+}
+
+static std::string insert_linebreaks(std::string str, size_t distance) {
+ //
+ // Provided by https://github.com/JomaCorpFX, adapted by me.
+ //
+ if (!str.length()) {
+ return "";
+ }
+
+ size_t pos = distance;
+
+ while (pos < str.size()) {
+ str.insert(pos, "\n");
+ pos += distance + 1;
+ }
+
+ return str;
+}
+
+template
+static std::string encode_with_line_breaks(String s) {
+ return insert_linebreaks(base64_encode(s, false), line_length);
+}
+
+template
+static std::string encode_pem(String s) {
+ return encode_with_line_breaks(s);
+}
+
+template
+static std::string encode_mime(String s) {
+ return encode_with_line_breaks(s);
+}
+
+template
+static std::string encode(String s, bool url) {
+ return base64_encode(reinterpret_cast(s.data()), s.length(), url);
+}
+
+std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) {
+
+ size_t len_encoded = (in_len +2) / 3 * 4;
+
+ unsigned char trailing_char = url ? '.' : '=';
+
+ //
+ // Choose set of base64 characters. They differ
+ // for the last two positions, depending on the url
+ // parameter.
+ // A bool (as is the parameter url) is guaranteed
+ // to evaluate to either 0 or 1 in C++ therefore,
+ // the correct character set is chosen by subscripting
+ // base64_chars with url.
+ //
+ const char* base64_chars_ = base64_chars[url];
+
+ std::string ret;
+ ret.reserve(len_encoded);
+
+ unsigned int pos = 0;
+
+ while (pos < in_len) {
+ ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
+
+ if (pos+1 < in_len) {
+ ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
+
+ if (pos+2 < in_len) {
+ ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
+ ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]);
+ }
+ else {
+ ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
+ ret.push_back(trailing_char);
+ }
+ }
+ else {
+
+ ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
+ ret.push_back(trailing_char);
+ ret.push_back(trailing_char);
+ }
+
+ pos += 3;
+ }
+
+
+ return ret;
+}
+
+template
+static std::string decode(String encoded_string, bool remove_linebreaks) {
+ //
+ // decode(…) is templated so that it can be used with String = const std::string&
+ // or std::string_view (requires at least C++17)
+ //
+
+ if (encoded_string.empty()) return std::string();
+
+ if (remove_linebreaks) {
+
+ std::string copy(encoded_string);
+
+ copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end());
+
+ return base64_decode(copy, false);
+ }
+
+ size_t length_of_string = encoded_string.length();
+ size_t pos = 0;
+
+ //
+ // The approximate length (bytes) of the decoded string might be one or
+ // two bytes smaller, depending on the amount of trailing equal signs
+ // in the encoded string. This approximation is needed to reserve
+ // enough space in the string to be returned.
+ //
+ size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
+ std::string ret;
+ ret.reserve(approx_length_of_decoded_string);
+
+ while (pos < length_of_string) {
+ //
+ // Iterate over encoded input string in chunks. The size of all
+ // chunks except the last one is 4 bytes.
+ //
+ // The last chunk might be padded with equal signs or dots
+ // in order to make it 4 bytes in size as well, but this
+ // is not required as per RFC 2045.
+ //
+ // All chunks except the last one produce three output bytes.
+ //
+ // The last chunk produces at least one and up to three bytes.
+ //
+
+ size_t pos_of_char_1 = pos_of_char(encoded_string[pos+1] );
+
+ //
+ // Emit the first output byte that is produced in each chunk:
+ //
+ ret.push_back(static_cast( ( (pos_of_char(encoded_string[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
+
+ if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045)
+ encoded_string[pos+2] != '=' &&
+ encoded_string[pos+2] != '.' // accept URL-safe base 64 strings, too, so check for '.' also.
+ )
+ {
+ //
+ // Emit a chunk's second byte (which might not be produced in the last chunk).
+ //
+ unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos+2] );
+ ret.push_back(static_cast( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
+
+ if ( ( pos + 3 < length_of_string ) &&
+ encoded_string[pos+3] != '=' &&
+ encoded_string[pos+3] != '.'
+ )
+ {
+ //
+ // Emit a chunk's third byte (which might not be produced in the last chunk).
+ //
+ ret.push_back(static_cast( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string[pos+3]) ));
+ }
+ }
+
+ pos += 4;
+ }
+
+ return ret;
+}
+
+std::string base64_decode(std::string const& s, bool remove_linebreaks) {
+ return decode(s, remove_linebreaks);
+}
+
+std::string base64_encode(std::string const& s, bool url) {
+ return encode(s, url);
+}
+
+std::string base64_encode_pem (std::string const& s) {
+ return encode_pem(s);
+}
+
+std::string base64_encode_mime(std::string const& s) {
+ return encode_mime(s);
+}
+
+#if __cplusplus >= 201703L
+//
+// Interface with std::string_view rather than const std::string&
+// Requires C++17
+// Provided by Yannic Bonenberger (https://github.com/Yannic)
+//
+
+std::string base64_encode(std::string_view s, bool url) {
+ return encode(s, url);
+}
+
+std::string base64_encode_pem(std::string_view s) {
+ return encode_pem(s);
+}
+
+std::string base64_encode_mime(std::string_view s) {
+ return encode_mime(s);
+}
+
+std::string base64_decode(std::string_view s, bool remove_linebreaks) {
+ return decode(s, remove_linebreaks);
+}
+
+#endif // __cplusplus >= 201703L