diff --git a/src/celengine/overlay.cpp b/src/celengine/overlay.cpp index f5d351e1..bee220db 100644 --- a/src/celengine/overlay.cpp +++ b/src/celengine/overlay.cpp @@ -11,14 +11,19 @@ #include #include #include +#include +#include #include "vecgl.h" #include "overlay.h" +#include "render.h" using namespace std; +using namespace Eigen; -Overlay::Overlay() : - ostream(&sbuf) +Overlay::Overlay(const Renderer& r) : + ostream(&sbuf), + renderer(r) { sbuf.setOverlay(this); } @@ -161,27 +166,99 @@ void Overlay::print(const char* s) } } -void Overlay::rect(float x, float y, float w, float h, bool fill) +static void drawRect(const Renderer& r, + const array& vertices, + const vector& colors, + Overlay::RectType type, + float linewidth) { - if (useTexture) + uint32_t p = 0; + switch (type) + { + case Overlay::RectType::Textured: + p |= ShaderProperties::HasTexture; + // [[ fallthrough ]] + case Overlay::RectType::Outlined: + case Overlay::RectType::Filled: + switch (colors.size()) + { + case 0: + break; + case 1: + p |= ShaderProperties::UniformColor; + break; + case 4: + p |= ShaderProperties::PerVertexColor; + break; + default: + fmt::fprintf(cerr, "Incorrect number of colors: %i\n", colors.size()); + break; + } + default: + break; + } + + auto prog = r.getShaderManager().getShader(ShaderProperties(p)); + if (prog == nullptr) + return; + + constexpr array texels = {0, 1, 1, 1, 1, 0, 0, 0}; + + auto s = static_cast(memsize(vertices) + memsize(texels) + 4*4*sizeof(GLfloat)); + static celgl::VertexObject vo{ GL_ARRAY_BUFFER, s, GL_DYNAMIC_DRAW }; + vo.bindWritable(); + + if (!vo.initialized()) + { + vo.allocate(); + vo.setBufferData(texels.data(), memsize(vertices), memsize(texels)); + vo.setVertices(2, GL_FLOAT); + vo.setTextureCoords(2, GL_SHORT, false, 0, memsize(vertices)); + vo.setColors(4, GL_FLOAT, false, 0, memsize(vertices) + memsize(texels)); + } + + vo.setBufferData(vertices.data(), 0, memsize(vertices)); + if (colors.size() == 4) + vo.setBufferData(colors.data(), memsize(vertices) + memsize(texels), 4*4*sizeof(GLfloat)); + + prog->use(); + if (type == Overlay::RectType::Textured) + prog->samplerParam("tex") = 0; + + if (colors.size() == 1) + prog->vec4Param("color") = colors[0]; + + if (type != Overlay::RectType::Outlined) + { + vo.draw(GL_TRIANGLE_FAN, 4); + } + else + { + if (linewidth != 1.0f) + glLineWidth(linewidth); + vo.draw(GL_LINE_LOOP, 4); + if (linewidth != 1.0f) + glLineWidth(1.0f); + } + + glUseProgram(0); + vo.unbind(); +} + +void Overlay::rect(const Overlay::Rectangle& r) +{ + if (useTexture && r.type != Overlay::RectType::Textured) { glDisable(GL_TEXTURE_2D); useTexture = false; } - if (fill) - { - glRectf(x, y, x + w, y + h); - } - else - { - glBegin(GL_LINE_LOOP); - glVertex3f(x, y, 0); - glVertex3f(x + w, y, 0); - glVertex3f(x + w, y + h, 0); - glVertex3f(x, y + h, 0); - glEnd(); - } + vector cv; + for (const Color& c : r.colors) + cv.push_back(c.toVector4()); + + array coord = { r.x, r.y, r.x+r.w, r.y, r.x+r.w, r.y+r.h, r.x, r.y+r.h }; + drawRect(renderer, coord, cv, r.type, r.lw); } diff --git a/src/celengine/overlay.h b/src/celengine/overlay.h index 4ffbb3ea..5b9fcbb2 100644 --- a/src/celengine/overlay.h +++ b/src/celengine/overlay.h @@ -12,10 +12,13 @@ #include #include +#include #include +#include class Overlay; +class Renderer; // Custom streambuf class to support C++ operator style output. The // output is completely unbuffered so that it can coexist with printf @@ -47,7 +50,8 @@ class OverlayStreamBuf : public std::streambuf class Overlay : public std::ostream { public: - Overlay(); + Overlay(const Renderer&); + Overlay() = delete; ~Overlay() = default; void begin(); @@ -56,7 +60,32 @@ class Overlay : public std::ostream void setWindowSize(int, int); void setFont(TextureFont*); - void rect(float x, float y, float w, float h, bool fill = true); + enum class RectType + { + Outlined = 0x0001, + Filled = 0x0002, + Textured = 0x0004 + }; + + struct Rectangle + { + Rectangle() = default; + Rectangle(float _x, float _y, float _w, float _h, const Color& _c, RectType _t, float _lw = 1.0f) : + x(_x), y(_y), w(_w), h(_h), type(_t), lw(_lw) + { + colors.push_back(_c); + }; + Rectangle(float _x, float _y, float _w, float _h, const std::vector& _c, RectType _t, float _lw = 1.0f) : + x(_x), y(_y), w(_w), h(_h), colors(_c), type(_t), lw(_lw) + { + }; + float x, y, w, h; + float lw { 1.0f }; + RectType type { RectType::Filled }; + std::vector colors; + }; + + void rect(const Rectangle&); void beginText(); void endText(); @@ -75,7 +104,11 @@ class Overlay : public std::ostream float xoffset{ 0.0f }; float yoffset{ 0.0f }; + float lineWidth { 1.0f }; + OverlayStreamBuf sbuf; + + const Renderer& renderer; }; #endif // _OVERLAY_H_ diff --git a/src/celestia/celestiacore.cpp b/src/celestia/celestiacore.cpp index 9c57cbf2..ad3764b8 100644 --- a/src/celestia/celestiacore.cpp +++ b/src/celestia/celestiacore.cpp @@ -49,6 +49,8 @@ #include #include #include +#include +#include #ifdef CELX #include @@ -1344,7 +1346,7 @@ void CelestiaCore::charEntered(const char *c_p, int modifiers) { MarkerRepresentation markerRep(MarkerRepresentation::Diamond); markerRep.setSize(10.0f); - markerRep.setColor(Color(0.0f, 1.0f, 0.0f, 0.9f)); + markerRep.setColor({0.0f, 1.0f, 0.0f, 0.9f}); sim->getUniverse()->markObject(sel, markerRep, 1); } @@ -3249,17 +3251,6 @@ static void displaySelectionName(Overlay& overlay, #endif -static void showViewFrame(const View* v, int width, int height) -{ - glBegin(GL_LINE_LOOP); - glVertex3f(v->x * width, v->y * height, 0.0f); - glVertex3f(v->x * width, (v->y + v->height) * height - 1, 0.0f); - glVertex3f((v->x + v->width) * width - 1, (v->y + v->height) * height - 1, 0.0f); - glVertex3f((v->x + v->width) * width - 1, v->y * height, 0.0f); - glEnd(); -} - - void CelestiaCore::setScriptImage(float duration, float xoffset, float yoffset, @@ -3270,7 +3261,7 @@ void CelestiaCore::setScriptImage(float duration, if (image == nullptr || image->isNewImage(filename)) { delete image; - image = new CelestiaCore::OverlayImage(filename); + image = new CelestiaCore::OverlayImage(filename, overlay); } image->setStartTime((float) currentTime); image->setDuration(duration); @@ -3280,10 +3271,10 @@ void CelestiaCore::setScriptImage(float duration, } -CelestiaCore::OverlayImage::OverlayImage(string f) +CelestiaCore::OverlayImage::OverlayImage(string f, Overlay* o) : + filename(std::move(f)), + overlay(o) { - filename = std::move(f); - delete texture; texture = LoadTextureFromFile(string("images/") + filename); } @@ -3315,16 +3306,10 @@ void CelestiaCore::OverlayImage::render(float curr_time, int width, int height) glEnable(GL_TEXTURE_2D); texture->bind(); - glBegin(GL_TRIANGLE_FAN); - glColor4f(1.0f, 1.0f, 1.0f, alpha); - glTexCoord2f(0.0f, 1.0f); glVertex2f(left, bottom); - glTexCoord2f(1.0f, 1.0f); glVertex2f(left + xSize, bottom); - glTexCoord2f(1.0f, 0.0f); glVertex2f(left + xSize, bottom + ySize); - glTexCoord2f(0.0f, 0.0f); glVertex2f(left, bottom + ySize); - glEnd(); + Overlay::Rectangle r(left, bottom, xSize, ySize, {Color::White, alpha}, Overlay::RectType::Textured); + overlay->rect(r); } - void CelestiaCore::renderOverlay() { #ifdef CELX @@ -3354,37 +3339,45 @@ void CelestiaCore::renderOverlay() if (views.size() > 1) { + Overlay::Rectangle r(0, 0, 0, 0, frameColor, Overlay::RectType::Outlined, 1); + // Render a thin border arround all views if (showViewFrames || resizeSplit) { - glLineWidth(1.0f); - glDisable(GL_TEXTURE_2D); - glColor4f(0.5f, 0.5f, 0.5f, 1.0f); for(const auto v : views) + { if (v->type == View::ViewWindow) - showViewFrame(v, width, height); + { + r.x = v->x * width; + r.y = v->y * height; + r.w = v->width * width - 1; + r.h = v->height * height - 1; + overlay->rect(r); + } + } } - glLineWidth(1.0f); // Render a very simple border around the active view - View* av = (*activeView); + View* av = *activeView; + + r.x = av->x * width; + r.y = av->y * height; + r.w = av->width * width - 1; + r.h = av->height * height - 1; if (showActiveViewFrame) { - glLineWidth(2.0f); - glDisable(GL_TEXTURE_2D); - glColor4f(0.5f, 0.5f, 1.0f, 1.0f); - showViewFrame(av, width, height); - glLineWidth(1.0f); + r.colors[0] = activeFrameColor; + r.lw = 2; + overlay->rect(r); } if (currentTime < flashFrameStart + 0.5) { - glLineWidth(8.0f); - glColor4f(0.5f, 0.5f, 1.0f, - (float) (1.0 - (currentTime - flashFrameStart) / 0.5)); - showViewFrame(av, width, height); - glLineWidth(1.0f); + float alpha = (float) (1.0 - (currentTime - flashFrameStart) / 0.5); + r.colors[0] = {activeFrameColor, alpha}; + r.lw = 8; + overlay->rect(r); } } @@ -3764,8 +3757,8 @@ void CelestiaCore::renderOverlay() { overlay->setFont(titleFont); glPushMatrix(); - glColor4f(0.7f, 0.7f, 1.0f, 0.2f); - overlay->rect(0.0f, 0.0f, (float) width, 100.0f); + Overlay::Rectangle r(0, 0, width, 100, consoleColor, Overlay::RectType::Filled); + overlay->rect(r); glTranslatef(0.0f, fontHeight * 3.0f + 35.0f, 0.0f); glColor4f(0.6f, 0.6f, 1.0f, 1.0f); overlay->beginText(); @@ -3844,11 +3837,15 @@ void CelestiaCore::renderOverlay() int movieWidth = movieCapture->getWidth(); int movieHeight = movieCapture->getHeight(); glPushMatrix(); - glColor4f(1, 0, 0, 1); - overlay->rect((float) ((width - movieWidth) / 2 - 1), - (float) ((height - movieHeight) / 2 - 1), - (float) (movieWidth + 1), - (float) (movieHeight + 1), false); + Color color(1, 0, 0, 1); + glColor(color); + Overlay::Rectangle r((width - movieWidth) / 2 - 1, + (height - movieHeight) / 2 - 1, + movieWidth + 1, + movieHeight + 1, + color, + Overlay::RectType::Outlined); + overlay->rect(r); glTranslatef((float) ((width - movieWidth) / 2), (float) ((height + movieHeight) / 2 + 2), 0.0f); overlay->beginText(); @@ -3918,20 +3915,14 @@ void CelestiaCore::renderOverlay() } logoTexture->bind(); - glBegin(GL_QUADS); - glColor4f(0.8f, 0.8f, 1.0f, botAlpha); - //glColor4f(1.0f, 1.0f, 1.0f, botAlpha); - glTexCoord2f(0.0f, 1.0f); - glVertex2i(left, bottom); - glTexCoord2f(1.0f, 1.0f); - glVertex2i(left + xSize, bottom); - glColor4f(0.6f, 0.6f, 1.0f, topAlpha); - //glColor4f(1.0f, 1.0f, 1.0f, topAlpha); - glTexCoord2f(1.0f, 0.0f); - glVertex2i(left + xSize, bottom + ySize); - glTexCoord2f(0.0f, 0.0f); - glVertex2i(left, bottom + ySize); - glEnd(); + vector c = { + {0.8f, 0.8f, 1.0f, botAlpha}, + {0.8f, 0.8f, 1.0f, botAlpha}, + {0.6f, 0.6f, 1.0f, topAlpha}, + {0.6f, 0.6f, 1.0f, topAlpha} + }; + Overlay::Rectangle r(left, bottom, xSize, ySize, c, Overlay::RectType::Textured); + overlay->rect(r); } else { @@ -4318,7 +4309,7 @@ bool CelestiaCore::initRenderer() titleFont = font; // Set up the overlay - overlay = new Overlay(); + overlay = new Overlay(*renderer); overlay->setWindowSize(width, height); if (config->labelFont == "") diff --git a/src/celestia/celestiacore.h b/src/celestia/celestiacore.h index 89994136..ea0ba61d 100644 --- a/src/celestia/celestiacore.h +++ b/src/celestia/celestiacore.h @@ -203,7 +203,7 @@ class CelestiaCore // : public Watchable class OverlayImage { public: - OverlayImage(string); + OverlayImage(string, Overlay*); ~OverlayImage() { delete texture; } OverlayImage() =default; OverlayImage(OverlayImage&) =delete; @@ -227,6 +227,7 @@ class CelestiaCore // : public Watchable bool fitscreen{ false }; std::string filename; Texture* texture{ nullptr }; + Overlay* overlay; }; public: @@ -412,7 +413,11 @@ class CelestiaCore // : public Watchable int messageVOffset{ 0 }; double messageStart{ 0.0 }; double messageDuration{ 0.0 }; - Color textColor{ Color(1.0f, 1.0f, 1.0f) }; + Color textColor{ 1.0f, 1.0f, 1.0f }; + + const Color frameColor{ 0.5f, 0.5f, 0.5f, 1.0f }; + const Color activeFrameColor{ 0.5f, 0.5f, 1.0f, 1.0f }; + const Color consoleColor{ 0.7f, 0.7f, 1.0f, 0.2f }; OverlayImage *image{ nullptr };