WIP: GUI Toolkit
This commit is contained in:
77
LinearLayout.cc
Normal file
77
LinearLayout.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
#include "LinearLayout.hh"
|
||||
|
||||
LinearLayout::LinearLayout(int direction, int width, int height, std::string name)
|
||||
: View(width, height, std::move(name)), direction_(direction)
|
||||
{
|
||||
}
|
||||
|
||||
LinearLayout::~LinearLayout()
|
||||
{
|
||||
}
|
||||
|
||||
void LinearLayout::setChildPadding(int pad)
|
||||
{
|
||||
if (pad != padChildren_) {
|
||||
padChildren_ = pad;
|
||||
|
||||
layout();
|
||||
}
|
||||
}
|
||||
|
||||
void LinearLayout::layout()
|
||||
{
|
||||
// TODO: Respect parent padding
|
||||
if ((width_ == MATCH_PARENT) && parent_)
|
||||
realWidth_ = parent_->getRealWidth();
|
||||
|
||||
if ((height_ == MATCH_PARENT) && parent_)
|
||||
realHeight_ = parent_->getRealHeight();
|
||||
|
||||
if (direction_ == DIR_VERTICAL) {
|
||||
int contentWidth = 0;
|
||||
|
||||
if (width_ == WRAP_CONTENT) {
|
||||
// Determine content width
|
||||
for(auto& ent : children_) {
|
||||
auto& child = *(std::get<1>(ent));
|
||||
assert(child.getHeight() != MATCH_PARENT);
|
||||
if (child.getWidth() == MATCH_PARENT)
|
||||
continue;
|
||||
if (child.getWidth() == WRAP_CONTENT)
|
||||
_layout(child);
|
||||
contentWidth = std::max(contentWidth, child.getRealWidth());
|
||||
}
|
||||
assert(contentWidth > 0);
|
||||
realWidth_ = contentWidth + padLeft_ + padRight_;
|
||||
printf("Inner width: %d, outer width: %d\n", contentWidth, realWidth_);
|
||||
}
|
||||
|
||||
int currentY = padTop_;
|
||||
|
||||
// Layout children
|
||||
for(auto& ent : children_) {
|
||||
auto& child = *(std::get<1>(ent));
|
||||
if (child.getWidth() == MATCH_PARENT)
|
||||
_layout(child);
|
||||
|
||||
SDL_Rect cr;
|
||||
cr.x = padLeft_;
|
||||
cr.y = currentY;
|
||||
if ((realWidth_ - padLeft_ - padRight_) > child.getRealWidth())
|
||||
cr.w = child.getRealWidth();
|
||||
else
|
||||
cr.w = realWidth_ - padLeft_ - padRight_;
|
||||
cr.h = child.getRealHeight();
|
||||
|
||||
std::get<2>(ent) = cr;
|
||||
|
||||
currentY += child.getRealHeight() + padChildren_;
|
||||
}
|
||||
|
||||
if (height_ == WRAP_CONTENT)
|
||||
realHeight_ = currentY - padChildren_ + padBottom_;
|
||||
}
|
||||
|
||||
invalidateGL();
|
||||
}
|
||||
27
LinearLayout.hh
Normal file
27
LinearLayout.hh
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef __OPENGLPLAYGROUND_LINEARLAYOUT_HH__
|
||||
#define __OPENGLPLAYGROUND_LINEARLAYOUT_HH__
|
||||
|
||||
#include "View.hh"
|
||||
|
||||
static const int DIR_VERTICAL = 0;
|
||||
static const int DIR_HORIZONTAL = 0;
|
||||
|
||||
class LinearLayout : public View {
|
||||
public:
|
||||
LinearLayout(int direction = DIR_VERTICAL, int width = WRAP_CONTENT, int height = WRAP_CONTENT, std::string name = "");
|
||||
|
||||
LinearLayout(LinearLayout const& copy) = delete;
|
||||
LinearLayout& operator=(LinearLayout const& copy) = delete;
|
||||
|
||||
~LinearLayout();
|
||||
|
||||
void setChildPadding(int pad);
|
||||
|
||||
protected:
|
||||
void layout() override;
|
||||
|
||||
int direction_;
|
||||
int padChildren_;
|
||||
};
|
||||
|
||||
#endif
|
||||
4
Makefile
4
Makefile
@@ -1,8 +1,8 @@
|
||||
CXX=g++
|
||||
CXXOPTS=-O2 -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -Wno-sign-compare -std=c++14 -flto
|
||||
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -Wno-sign-compare -std=c++14 -flto
|
||||
LDOPTS=
|
||||
LIBS=-lglbinding -lSDL2 -lSDL2_image -lobj -lSDL2_ttf -lprotobuf
|
||||
CXXSRCS=main.cc objectParser.cc shaders.cc Object.cc VBOManager.cc texture.cc font.cc Overlay.cc TextWidget.cc
|
||||
CXXSRCS=main.cc objectParser.cc shaders.cc Object.cc VBOManager.cc texture.cc font.cc Overlay.cc TextWidget.cc Widget.cc View.cc LinearLayout.cc
|
||||
BINIFY_SRCS=binifyObj.cc objectParser.cc object.pb.cc
|
||||
OBJS=$(addprefix objs/,$(CXXSRCS:.cc=.o))
|
||||
BINIFY_OBJS=$(addprefix objs/,$(BINIFY_SRCS:.cc=.o))
|
||||
|
||||
43
Object.cc
43
Object.cc
@@ -12,16 +12,15 @@
|
||||
|
||||
using namespace gl;
|
||||
|
||||
Object::Object(VBOManager& vboManager, std::vector<objVertexAttribs> const& vas,
|
||||
std::vector<uint16_t> indices, Program& prog)
|
||||
: _vboManager(vboManager), _prog(prog), _indices(std::move(indices)), _vaID(0)
|
||||
Object::Object(std::vector<objVertexAttribs> const& vas,
|
||||
std::vector<uint16_t> indices)
|
||||
: _indices(std::move(indices)), _vaID(0)
|
||||
{
|
||||
construct(vas);
|
||||
}
|
||||
|
||||
Object::Object(VBOManager& vboManager, std::string const& filename,
|
||||
Program& prog)
|
||||
: _vboManager(vboManager), _prog(prog), _vaID(0)
|
||||
Object::Object(std::string const& filename)
|
||||
: _vaID(0)
|
||||
{
|
||||
auto tmp = readObject(filename);
|
||||
_indices = std::get<1>(tmp);
|
||||
@@ -33,22 +32,17 @@ Object::~Object()
|
||||
glDeleteVertexArrays(1, &_vaID);
|
||||
}
|
||||
|
||||
void Object::draw(glm::mat4 const& modelview, Program *override) const
|
||||
void Object::draw() const
|
||||
{
|
||||
glBindVertexArray(_vaID);
|
||||
if (override)
|
||||
override->use();
|
||||
else
|
||||
_prog.use();
|
||||
glUniformMatrix4fv(_prog.getUniformLocation("model_matrix"), 1, GL_FALSE,
|
||||
glm::value_ptr(modelview));
|
||||
|
||||
glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_SHORT,
|
||||
_indices.data());
|
||||
}
|
||||
|
||||
void Object::construct(std::vector<objVertexAttribs> const& vas)
|
||||
{
|
||||
_vbo = _vboManager.alloc(sizeof(objVertexAttribs)*vas.size());
|
||||
_vbo = VBOManager::getInstance().alloc(sizeof(objVertexAttribs)*vas.size());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo.getVBOId());
|
||||
glBufferSubData(GL_ARRAY_BUFFER, _vbo.getOfs(),
|
||||
sizeof(objVertexAttribs)*vas.size(), (void*)vas.data());
|
||||
@@ -56,22 +50,17 @@ void Object::construct(std::vector<objVertexAttribs> const& vas)
|
||||
glGenVertexArrays(1, &_vaID);
|
||||
glBindVertexArray(_vaID);
|
||||
|
||||
GLint al;
|
||||
if((al = _prog.getAttribLocation("vertex")) != -1) {
|
||||
glEnableVertexAttribArray(al);
|
||||
glVertexAttribPointer(al, 3, GL_FLOAT, GL_FALSE, sizeof(objVertexAttribs),
|
||||
glEnableVertexAttribArray(ATTRIB_VERTEX_POS);
|
||||
glVertexAttribPointer(ATTRIB_VERTEX_POS, 3, GL_FLOAT, GL_FALSE, sizeof(objVertexAttribs),
|
||||
(void*)(_vbo.getOfs()+offsetof(objVertexAttribs, vertex)));
|
||||
}
|
||||
if((al = _prog.getAttribLocation("vertexTC")) != -1) {
|
||||
glEnableVertexAttribArray(al);
|
||||
glVertexAttribPointer(al, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
|
||||
glEnableVertexAttribArray(ATTRIB_VERTEX_TC);
|
||||
glVertexAttribPointer(ATTRIB_VERTEX_TC, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
sizeof(objVertexAttribs),
|
||||
(void*)(_vbo.getOfs()+offsetof(objVertexAttribs, texCoords)));
|
||||
}
|
||||
if((al = _prog.getAttribLocation("vertexNorm")) != -1) {
|
||||
glEnableVertexAttribArray(al);
|
||||
glVertexAttribPointer(al, 4, GL_INT_2_10_10_10_REV, GL_TRUE,
|
||||
|
||||
glEnableVertexAttribArray(ATTRIB_VERTEX_NORM);
|
||||
glVertexAttribPointer(ATTRIB_VERTEX_NORM, 4, GL_INT_2_10_10_10_REV, GL_TRUE,
|
||||
sizeof(objVertexAttribs),
|
||||
(void*)(_vbo.getOfs()+offsetof(objVertexAttribs, normal)));
|
||||
}
|
||||
}
|
||||
|
||||
12
Object.hh
12
Object.hh
@@ -7,14 +7,12 @@
|
||||
#include "objectParser.hh"
|
||||
#include "VBOManager.hh"
|
||||
|
||||
class Program;
|
||||
|
||||
class Object {
|
||||
public:
|
||||
Object(VBOManager& vboManager, std::vector<objVertexAttribs> const& vas,
|
||||
std::vector<uint16_t> indices, Program& prog);
|
||||
Object(std::vector<objVertexAttribs> const& vas,
|
||||
std::vector<uint16_t> indice);
|
||||
|
||||
Object(VBOManager& vboManager, std::string const& filename, Program& prog);
|
||||
Object(std::string const& filename);
|
||||
|
||||
Object(Object const& copy) = delete;
|
||||
|
||||
@@ -22,14 +20,12 @@ public:
|
||||
|
||||
Object& operator=(Object const& copy) = delete;
|
||||
|
||||
void draw(glm::mat4 const& modelview, Program *override = nullptr) const;
|
||||
void draw() const;
|
||||
|
||||
private:
|
||||
void construct(std::vector<objVertexAttribs> const& vas);
|
||||
|
||||
VBOManager& _vboManager;
|
||||
VBOManager::VBOAlloc _vbo;
|
||||
Program& _prog;
|
||||
std::vector<uint16_t> _indices;
|
||||
gl::GLuint _vaID;
|
||||
};
|
||||
|
||||
30
Overlay.cc
30
Overlay.cc
@@ -6,10 +6,9 @@
|
||||
|
||||
using namespace gl;
|
||||
|
||||
Overlay::Overlay(VBOManager& vboManager, std::vector<ovlVertexAttribs> const& vas,
|
||||
Program& prog)
|
||||
: vboManager_(vboManager), vbo_(vboManager_.alloc(sizeof(ovlVertexAttribs)*vas.size())),
|
||||
prog_(prog), vaID_(0), vertices_(vas.size())
|
||||
Overlay::Overlay(std::vector<ovlVertexAttribs> const& vas)
|
||||
: vbo_(VBOManager::getInstance().alloc(sizeof(ovlVertexAttribs)*vas.size())),
|
||||
vaID_(0), vertices_(vas.size())
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_.getVBOId());
|
||||
glBufferSubData(GL_ARRAY_BUFFER, vbo_.getOfs(),
|
||||
@@ -19,18 +18,16 @@ Overlay::Overlay(VBOManager& vboManager, std::vector<ovlVertexAttribs> const& va
|
||||
glGenVertexArrays(1, &vaID_);
|
||||
try {
|
||||
glBindVertexArray(vaID_);
|
||||
GLint al;
|
||||
if((al = prog_.getAttribLocation("vertex")) != -1) {
|
||||
glEnableVertexAttribArray(al);
|
||||
glVertexAttribPointer(al, 2, GL_SHORT, GL_TRUE, sizeof(ovlVertexAttribs),
|
||||
|
||||
glEnableVertexAttribArray(ATTRIB_VERTEX_POS);
|
||||
glVertexAttribPointer(ATTRIB_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
|
||||
sizeof(ovlVertexAttribs),
|
||||
(void*)(vbo_.getOfs()+offsetof(ovlVertexAttribs, vertex)));
|
||||
}
|
||||
if((al = prog_.getAttribLocation("vertexTC")) != -1) {
|
||||
glEnableVertexAttribArray(al);
|
||||
glVertexAttribPointer(al, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
|
||||
glEnableVertexAttribArray(ATTRIB_VERTEX_TC);
|
||||
glVertexAttribPointer(ATTRIB_VERTEX_TC, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
sizeof(ovlVertexAttribs),
|
||||
(void*)(vbo_.getOfs()+offsetof(ovlVertexAttribs, texCoords)));
|
||||
}
|
||||
} catch(...) {
|
||||
glDeleteVertexArrays(1, &vaID_);
|
||||
throw;
|
||||
@@ -42,12 +39,9 @@ Overlay::~Overlay()
|
||||
glDeleteVertexArrays(1, &vaID_);
|
||||
}
|
||||
|
||||
void Overlay::draw(Program *override) const
|
||||
void Overlay::draw() const
|
||||
{
|
||||
glBindVertexArray(vaID_);
|
||||
if (override)
|
||||
override->use();
|
||||
else
|
||||
prog_.use();
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, vertices_);
|
||||
}
|
||||
|
||||
13
Overlay.hh
13
Overlay.hh
@@ -6,29 +6,24 @@
|
||||
|
||||
#include "VBOManager.hh"
|
||||
|
||||
class Program;
|
||||
|
||||
struct ovlVertexAttribs {
|
||||
uint16_t vertex[2];
|
||||
int16_t vertex[2];
|
||||
uint16_t texCoords[2];
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__));
|
||||
|
||||
class Overlay {
|
||||
public:
|
||||
Overlay(VBOManager& vboManager, std::vector<ovlVertexAttribs> const& vas,
|
||||
Program& prog);
|
||||
Overlay(std::vector<ovlVertexAttribs> const& vas);
|
||||
|
||||
Overlay(Overlay const& copy) = delete;
|
||||
Overlay& operator=(Overlay const& copy) = delete;
|
||||
|
||||
~Overlay();
|
||||
|
||||
void draw(Program *override = nullptr) const;
|
||||
void draw() const;
|
||||
|
||||
private:
|
||||
VBOManager& vboManager_;
|
||||
VBOManager::VBOAlloc vbo_;
|
||||
Program& prog_;
|
||||
gl::GLuint vaID_;
|
||||
size_t vertices_;
|
||||
};
|
||||
|
||||
84
TextWidget.cc
Normal file
84
TextWidget.cc
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#include "font.hh"
|
||||
#include "TextWidget.hh"
|
||||
|
||||
TextWidget::TextWidget(Font& font, std::string text, int width, int height)
|
||||
: Widget(width, height), text_(std::move(text)), font_(font),
|
||||
textSurf_(nullptr)
|
||||
{
|
||||
layout();
|
||||
}
|
||||
|
||||
TextWidget::~TextWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void TextWidget::setText(std::string text)
|
||||
{
|
||||
if (text != text_) {
|
||||
text_ = std::move(text);
|
||||
invalidateGL();
|
||||
layout();
|
||||
}
|
||||
}
|
||||
|
||||
void TextWidget::setForegroundColor(SDL_Color fg)
|
||||
{
|
||||
Widget::setForegroundColor(fg);
|
||||
|
||||
// Trigger text rerender
|
||||
layout();
|
||||
}
|
||||
|
||||
void TextWidget::layout()
|
||||
{
|
||||
// Determine text size
|
||||
int width, height;
|
||||
if(TTF_SizeUTF8(font_.getFont(), text_.c_str(), &width, &height) != 0)
|
||||
throw TTFException{};
|
||||
|
||||
if ((width > (width_ - padLeft_ - padRight_)) && (width_ != WRAP_CONTENT)) {
|
||||
textSurf_.reset(TTF_RenderUTF8_Blended_Wrapped(font_.getFont(),
|
||||
text_.c_str(),
|
||||
fg_, width_- padLeft_ - padRight_));
|
||||
if (!textSurf_)
|
||||
throw TTFException{};
|
||||
|
||||
if (height_ == WRAP_CONTENT)
|
||||
// TODO: Get proper tight bounding box for multiline text
|
||||
if (realHeight_ != (textSurf_->h - // TTF_FontLineSkip(font_.getFont())
|
||||
+ padTop_ + padBottom_)) {
|
||||
realHeight_ = textSurf_->h - // TTF_FontLineSkip(font_.getFont())
|
||||
+ padTop_ + padBottom_;
|
||||
invalidateGL();
|
||||
}
|
||||
} else {
|
||||
textSurf_.reset(TTF_RenderUTF8_Blended(font_.getFont(), text_.c_str(), fg_));
|
||||
|
||||
if (!textSurf_)
|
||||
throw TTFException{};
|
||||
|
||||
if (width_ == WRAP_CONTENT)
|
||||
if (realWidth_ != (textSurf_->w + padLeft_ + padRight_)) {
|
||||
realWidth_ = textSurf_->w + padLeft_ + padRight_;
|
||||
invalidateGL();
|
||||
}
|
||||
if (height_ == WRAP_CONTENT)
|
||||
if (realHeight_ != (textSurf_->h + padTop_ + padBottom_)) {
|
||||
realHeight_ = textSurf_->h + padTop_ + padBottom_;
|
||||
invalidateGL();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TextWidget::render(SDL_Surface *dst, SDL_Rect *dstRect) const
|
||||
{
|
||||
Widget::render(dst, dstRect);
|
||||
|
||||
SDL_Rect rect = calcContentRect(dst, dstRect, textSurf_->clip_rect);
|
||||
|
||||
if (SDL_BlitSurface(textSurf_.get(), nullptr, dst, &rect) != 0)
|
||||
throw SDLException{};
|
||||
}
|
||||
37
TextWidget.hh
Normal file
37
TextWidget.hh
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef __OPENGLPLAYGROUND_TEXTWIDGET_HH__
|
||||
#define __OPENGLPLAYGROUND_TEXTWIDGET_HH__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common.hh"
|
||||
#include "Widget.hh"
|
||||
|
||||
class Font;
|
||||
|
||||
class TextWidget final : public Widget {
|
||||
public:
|
||||
TextWidget(Font& font, std::string text = "",
|
||||
int width = WRAP_CONTENT, int height = WRAP_CONTENT);
|
||||
|
||||
TextWidget(TextWidget const& copy) = delete;
|
||||
TextWidget& operator=(TextWidget const& copy) = delete;
|
||||
|
||||
~TextWidget();
|
||||
|
||||
void setText(std::string text);
|
||||
std::string const& getText() const { return text_; }
|
||||
|
||||
void setForegroundColor(SDL_Color fg) override;
|
||||
|
||||
void render(SDL_Surface *dst, SDL_Rect *dstRect) const override;
|
||||
|
||||
protected:
|
||||
void layout() override;
|
||||
|
||||
private:
|
||||
std::string text_;
|
||||
Font& font_;
|
||||
SDLSurfaceUPtr textSurf_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,10 +1,26 @@
|
||||
#include <glbinding/gl/gl.h>
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
|
||||
#include "VBOManager.hh"
|
||||
#include "common.hh"
|
||||
|
||||
using namespace gl;
|
||||
|
||||
std::unique_ptr<VBOManager> VBOManager::instance{nullptr};
|
||||
static std::once_flag instance_flag;
|
||||
|
||||
VBOManager& VBOManager::getInstance()
|
||||
{
|
||||
std::call_once(instance_flag, init);
|
||||
return *instance;
|
||||
}
|
||||
|
||||
void VBOManager::init()
|
||||
{
|
||||
instance.reset(new VBOManager{});
|
||||
}
|
||||
|
||||
VBOManager::VBOManager()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2,20 +2,26 @@
|
||||
#define __OPENGLPLAYGROUND_VBOMANAGER_HH__
|
||||
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
#include <glbinding/gl/types.h>
|
||||
|
||||
class VBOManager {
|
||||
public:
|
||||
VBOManager();
|
||||
static VBOManager& getInstance();
|
||||
|
||||
~VBOManager();
|
||||
|
||||
VBOManager(VBOManager const& copy) = delete;
|
||||
VBOManager& operator=(VBOManager const& copy) = delete;
|
||||
|
||||
private:
|
||||
VBOManager();
|
||||
|
||||
static void init();
|
||||
static std::unique_ptr<VBOManager> instance;
|
||||
|
||||
class VBO;
|
||||
|
||||
@@ -54,6 +60,10 @@ public:
|
||||
return _vbo->getID();
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return (_vbo != nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
VBOAlloc(VBO &vbo, size_t ofs, size_t size);
|
||||
|
||||
|
||||
109
View.cc
Normal file
109
View.cc
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "View.hh"
|
||||
|
||||
View::View(int width, int height, std::string name)
|
||||
: Widget(width, height, std::move(name))
|
||||
{
|
||||
}
|
||||
|
||||
View::~View()
|
||||
{
|
||||
}
|
||||
|
||||
void View::addChild(std::unique_ptr<Widget> child)
|
||||
{
|
||||
_setParent(*child);
|
||||
children_.push_back(make_tuple(child->getName(), std::move(child), SDL_Rect{0, 0, 0, 0}));
|
||||
|
||||
layout();
|
||||
}
|
||||
|
||||
Widget& View::getChildByName(std::string name)
|
||||
{
|
||||
if (name == "")
|
||||
throw ChildNotFoundException{};
|
||||
|
||||
for(auto& ent : children_) {
|
||||
if (std::get<0>(ent) == name)
|
||||
return *std::get<1>(ent);
|
||||
}
|
||||
|
||||
throw ChildNotFoundException{};
|
||||
}
|
||||
|
||||
Widget const& View::getChildByName(std::string name) const
|
||||
{
|
||||
if (name == "")
|
||||
throw ChildNotFoundException{};
|
||||
|
||||
for(auto& ent : children_) {
|
||||
if (std::get<0>(ent) == name)
|
||||
return *std::get<1>(ent);
|
||||
}
|
||||
|
||||
throw ChildNotFoundException{};
|
||||
}
|
||||
|
||||
std::unique_ptr<Widget> View::removeChild(std::string name)
|
||||
{
|
||||
if (name == "")
|
||||
throw ChildNotFoundException{};
|
||||
|
||||
for(auto it = children_.begin(); it != children_.end(); ++it) {
|
||||
if (std::get<0>(*it) == name) {
|
||||
auto child = std::move(std::get<1>(*it));
|
||||
children_.erase(it);
|
||||
_clearParent(*child);
|
||||
_layout(*child);
|
||||
|
||||
layout();
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
throw ChildNotFoundException{};
|
||||
}
|
||||
|
||||
std::unique_ptr<Widget> View::removeChild(Widget& child)
|
||||
{
|
||||
for(auto it = children_.begin(); it != children_.end(); ++it) {
|
||||
if (std::get<1>(*it).get() == &child) {
|
||||
auto child = std::move(std::get<1>(*it));
|
||||
children_.erase(it);
|
||||
|
||||
_clearParent(*child);
|
||||
_layout(*child);
|
||||
|
||||
layout();
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
throw ChildNotFoundException{};
|
||||
}
|
||||
|
||||
|
||||
void View::render(SDL_Surface *dst, SDL_Rect *dstRect) const
|
||||
{
|
||||
Widget::render(dst, dstRect);
|
||||
|
||||
SDL_Rect rect;
|
||||
if (dstRect)
|
||||
memcpy(&rect, dstRect, sizeof(SDL_Rect));
|
||||
else {
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.w = dst->w;
|
||||
rect.h = dst->h;
|
||||
}
|
||||
|
||||
for (auto& ent : children_) {
|
||||
SDL_Rect childDst = std::get<2>(ent), childDstCliped;
|
||||
childDst.x += rect.x;
|
||||
childDst.y += rect.y;
|
||||
SDL_IntersectRect(&rect, &childDst, &childDstCliped);
|
||||
|
||||
std::get<1>(ent)->render(dst, &childDst);
|
||||
}
|
||||
}
|
||||
51
View.hh
Normal file
51
View.hh
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef __OPENGLPLAYGROUND_VIEW_HH__
|
||||
#define __OPENGLPLAYGROUND_VIEW_HH__
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
|
||||
#include "Widget.hh"
|
||||
#include "common.hh"
|
||||
|
||||
class ChildNotFoundException : public Exception {
|
||||
public:
|
||||
ChildNotFoundException() : Exception() {
|
||||
}
|
||||
|
||||
std::string toString() const override {
|
||||
return "ChildNotFoundException"s;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* Base class for all Widgets containing user-specified other Widgets
|
||||
(i.e. Views/Layouts) */
|
||||
class View : public Widget {
|
||||
public:
|
||||
View(int width = WRAP_CONTENT, int height = WRAP_CONTENT, std::string name = "");
|
||||
|
||||
View(View const& copy) = delete;
|
||||
View& operator=(View const& copy) = delete;
|
||||
|
||||
~View();
|
||||
|
||||
void addChild(std::unique_ptr<Widget> child);
|
||||
|
||||
Widget& getChildByName(std::string name);
|
||||
|
||||
Widget const& getChildByName(std::string name) const;
|
||||
|
||||
std::unique_ptr<Widget> removeChild(std::string name);
|
||||
std::unique_ptr<Widget> removeChild(Widget& child);
|
||||
|
||||
void render(SDL_Surface *dst, SDL_Rect *dstRect) const override;
|
||||
|
||||
protected:
|
||||
SDL_Rect childrenBB_;
|
||||
|
||||
std::vector<std::tuple<std::string, std::unique_ptr<Widget>, SDL_Rect > > children_;
|
||||
};
|
||||
|
||||
#endif
|
||||
274
Widget.cc
Normal file
274
Widget.cc
Normal file
@@ -0,0 +1,274 @@
|
||||
#include <vector>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <glm/gtc/packing.hpp>
|
||||
|
||||
#include "Widget.hh"
|
||||
#include "texture.hh"
|
||||
#include "shaders.hh"
|
||||
|
||||
Widget::Widget(int width, int height, std::string name)
|
||||
: name_(std::move(name)), width_(width), height_(height),
|
||||
background_(nullptr),
|
||||
bg_(SDL_Color{0, 0, 0, 0}), fg_(SDL_Color{255, 255, 255, 255}),
|
||||
padLeft_(0), padTop_(0), padRight_(0), padBottom_(0),
|
||||
alignHoriz_(ALIGN_LEFT), alignVert_(ALIGN_TOP),
|
||||
renderTop_(0), renderLeft_(0),
|
||||
renderTexValid_(false), renderAttribsValid_(false),
|
||||
renderTex_(nullptr), vaID_(0)
|
||||
{
|
||||
if (width_ == WRAP_CONTENT)
|
||||
realWidth_ = 0;
|
||||
else
|
||||
realWidth_ = width_;
|
||||
|
||||
if (height_ == WRAP_CONTENT)
|
||||
realHeight_ = 0;
|
||||
else
|
||||
realHeight_ = height_;
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
glDeleteVertexArrays(1, &vaID_);
|
||||
}
|
||||
|
||||
void Widget::setSize(int width, int height)
|
||||
{
|
||||
if ((width_ != width) || (height_ != height)) {
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
||||
if (width_ != WRAP_CONTENT)
|
||||
if (realWidth_ != width_) {
|
||||
realWidth_ = width_;
|
||||
}
|
||||
|
||||
if (height_ != WRAP_CONTENT)
|
||||
if (realHeight_ != height_) {
|
||||
realHeight_ = height_;
|
||||
}
|
||||
|
||||
layout();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setBackground(SDL_Surface* surf)
|
||||
{
|
||||
if (background_ != surf) {
|
||||
background_ = surf;
|
||||
invalidateGL();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setBackgroundColor(SDL_Color bg)
|
||||
{
|
||||
if (bg_ != bg) {
|
||||
bg_ = bg;
|
||||
invalidateGL();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setForegroundColor(SDL_Color fg)
|
||||
{
|
||||
if (fg_ != fg) {
|
||||
fg_ = fg;
|
||||
invalidateGL();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setPadding(int left, int top, int right, int bottom)
|
||||
{
|
||||
if ((padLeft_ != left) ||
|
||||
(padTop_ != top) ||
|
||||
(padRight_ != right) ||
|
||||
(padBottom_ != bottom)) {
|
||||
padLeft_ = left;
|
||||
padTop_ = top;
|
||||
padRight_ = right;
|
||||
padBottom_ = bottom;
|
||||
|
||||
layout();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setAlignment(int horiz, int vert) {
|
||||
if ((alignHoriz_ != horiz) ||
|
||||
(alignVert_ != vert)) {
|
||||
alignHoriz_ = horiz;
|
||||
alignVert_ = vert;
|
||||
|
||||
invalidateGL();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setParent(Widget *parent)
|
||||
{
|
||||
parent_ = parent;
|
||||
}
|
||||
|
||||
void Widget::setGLRenderPos(int left, int top)
|
||||
{
|
||||
if ((top != renderTop_) ||
|
||||
(left != renderLeft_)) {
|
||||
renderAttribsValid_ = false;
|
||||
renderTop_ = top;
|
||||
renderLeft_ = left;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::render(SDL_Surface *dst, SDL_Rect *dstRect) const
|
||||
{
|
||||
if (background_) {
|
||||
if (SDL_BlitScaled(background_, nullptr, dst, dstRect) != 0)
|
||||
throw SDLException{};
|
||||
} else {
|
||||
// Skip completely transparent background
|
||||
if (bg_.a == 0)
|
||||
return;
|
||||
|
||||
// Simply write completely intransparent bg
|
||||
if (bg_.a == 255) {
|
||||
SDLSurfaceScopedLock lock{dst};
|
||||
if (SDL_FillRect(dst, dstRect,
|
||||
SDL_MapRGBA(dst->format, bg_.r, bg_.g, bg_.b, bg_.a)) != 0)
|
||||
throw SDLException{};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Do proper blending blit for all other bgs
|
||||
int w = dstRect?dstRect->w:dst->w;
|
||||
int h = dstRect?dstRect->h:dst->h;
|
||||
|
||||
uint32_t rmask, gmask, bmask, amask;
|
||||
int bpp;
|
||||
if (!SDL_PixelFormatEnumToMasks(dst->format->format,
|
||||
&bpp, &rmask, &gmask, &bmask, &amask))
|
||||
throw SDLException{};
|
||||
|
||||
SDLSurfaceUPtr tmp{SDL_CreateRGBSurface(0, w, h, bpp,
|
||||
rmask, gmask, bmask, amask)};
|
||||
if (!tmp)
|
||||
throw SDLException{};
|
||||
|
||||
{
|
||||
SDLSurfaceScopedLock lock{tmp};
|
||||
if (SDL_FillRect(tmp.get(), nullptr,
|
||||
SDL_MapRGBA(tmp->format, bg_.r, bg_.g, bg_.b, bg_.a)) != 0)
|
||||
throw SDLException{};
|
||||
}
|
||||
|
||||
if (SDL_BlitSurface(tmp.get(), nullptr, dst, dstRect) != 0)
|
||||
throw SDLException{};
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Rect Widget::calcContentRect(SDL_Surface *dst, SDL_Rect *dstRect, SDL_Rect contentRect) const
|
||||
{
|
||||
SDL_Rect rect;
|
||||
|
||||
if (dstRect) {
|
||||
rect.x = dstRect->x + padLeft_;
|
||||
rect.y = dstRect->y + padTop_;
|
||||
rect.w = dstRect->w - (padLeft_ + padRight_);
|
||||
rect.h = dstRect->h - (padTop_ + padBottom_);
|
||||
} else {
|
||||
rect.x = padLeft_;
|
||||
rect.y = padTop_;
|
||||
rect.w = dst->w - padLeft_ - padRight_;
|
||||
rect.h = dst->h - padTop_ - padBottom_;
|
||||
}
|
||||
|
||||
if (contentRect.w < rect.w) {
|
||||
auto space = rect.w - contentRect.w;
|
||||
if (alignHoriz_ == ALIGN_RIGHT) {
|
||||
rect.x += space;
|
||||
rect.w -= space;
|
||||
} else if (alignHoriz_ == ALIGN_CENTER) {
|
||||
rect.x += space/2;
|
||||
rect.w -= space/2;
|
||||
}
|
||||
}
|
||||
|
||||
if (contentRect.h < rect.h) {
|
||||
auto space = rect.h - contentRect.h;
|
||||
if (alignHoriz_ == ALIGN_BOTTOM) {
|
||||
rect.y += space;
|
||||
rect.h -= space;
|
||||
} else if (alignHoriz_ == ALIGN_CENTER) {
|
||||
rect.y += space/2;
|
||||
rect.h -= space/2;
|
||||
}
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
void Widget::renderToGL() const
|
||||
{
|
||||
const size_t NUM_TRIANGLES = 6;
|
||||
|
||||
if (!renderTexValid_) {
|
||||
uint32_t rmask, gmask, bmask, amask;
|
||||
int bpp;
|
||||
if (!SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888,
|
||||
&bpp, &rmask, &gmask, &bmask, &amask))
|
||||
throw SDLException{};
|
||||
|
||||
SDLSurfaceUPtr tmp(SDL_CreateRGBSurface(0, realWidth_, realHeight_, bpp,
|
||||
rmask, gmask, bmask, amask));
|
||||
render(tmp.get(), nullptr);
|
||||
|
||||
if (!renderTex_ || (renderTex_->getWidth() != realWidth_) ||
|
||||
(renderTex_->getHeight() != realHeight_)) {
|
||||
|
||||
renderTex_ = make_unique<Texture2D>(tmp.get());
|
||||
|
||||
// Texture resize invalidates vertex attributes
|
||||
renderAttribsValid_ = false;
|
||||
} else {
|
||||
renderTex_->copyFromSurface(tmp.get());
|
||||
}
|
||||
renderTexValid_ = true;
|
||||
} else
|
||||
renderTex_->bind();
|
||||
|
||||
if (!renderAttribsValid_) {
|
||||
int t = renderTop_, l = renderLeft_, b = renderTop_+realHeight_,
|
||||
r = renderLeft_+realWidth_;
|
||||
std::vector<VertexAttribs> vertexAttribs{
|
||||
{{l, t}, {0, 0}},
|
||||
{{r, b}, {65535u, 65535u}},
|
||||
{{r, t}, {65535u, 0}},
|
||||
{{l, t}, {0, 0}},
|
||||
{{l, b}, {0, 65535u}},
|
||||
{{r, b}, {65535u, 65535u}}};
|
||||
|
||||
if (!vbo_) {
|
||||
vbo_ = VBOManager::getInstance().alloc(sizeof(VertexAttribs)*NUM_TRIANGLES);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_.getVBOId());
|
||||
glGenVertexArrays(1, &vaID_);
|
||||
glBindVertexArray(vaID_);
|
||||
|
||||
glEnableVertexAttribArray(ATTRIB_VERTEX_POS);
|
||||
glVertexAttribPointer(ATTRIB_VERTEX_POS, 2, GL_SHORT, GL_FALSE, sizeof(VertexAttribs),
|
||||
(void*)(vbo_.getOfs()+offsetof(VertexAttribs, vertex)));
|
||||
|
||||
glEnableVertexAttribArray(ATTRIB_VERTEX_TC);
|
||||
glVertexAttribPointer(ATTRIB_VERTEX_TC, 2, GL_UNSIGNED_SHORT, GL_TRUE,
|
||||
sizeof(VertexAttribs),
|
||||
(void*)(vbo_.getOfs()+offsetof(VertexAttribs, texCoords)));
|
||||
} else {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_.getVBOId());
|
||||
glBindVertexArray(vaID_);
|
||||
}
|
||||
glBufferSubData(GL_ARRAY_BUFFER, vbo_.getOfs(),
|
||||
sizeof(VertexAttribs)*NUM_TRIANGLES,
|
||||
static_cast<void const*>(vertexAttribs.data()));
|
||||
renderAttribsValid_ = true;
|
||||
} else
|
||||
glBindVertexArray(vaID_);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, NUM_TRIANGLES);
|
||||
}
|
||||
114
Widget.hh
Normal file
114
Widget.hh
Normal file
@@ -0,0 +1,114 @@
|
||||
#ifndef __OPENGLPLAYGROUND_WIDGET_HH__
|
||||
#define __OPENGLPLAYGROUND_WIDGET_HH__
|
||||
|
||||
#include <memory>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <glbinding/gl/types.h>
|
||||
|
||||
#include "common.hh"
|
||||
#include "VBOManager.hh"
|
||||
|
||||
/* Size the widget to wrap the content size */
|
||||
static const int WRAP_CONTENT = -1;
|
||||
|
||||
/* Size the widget to match the parent. If there is no parent, behaves like
|
||||
WRAP_CONTENT */
|
||||
static const int MATCH_PARENT = -2;
|
||||
|
||||
|
||||
static const int ALIGN_TOP = 0;
|
||||
static const int ALIGN_BOTTOM = 1;
|
||||
static const int ALIGN_CENTER = 2;
|
||||
static const int ALIGN_LEFT = 0;
|
||||
static const int ALIGN_RIGHT = 1;
|
||||
|
||||
class Texture2D;
|
||||
|
||||
class Widget {
|
||||
public:
|
||||
Widget(int width = WRAP_CONTENT, int height = WRAP_CONTENT, std::string name = "");
|
||||
|
||||
Widget(Widget const& copy) = delete;
|
||||
Widget& operator=(Widget const& copy) = delete;
|
||||
|
||||
virtual ~Widget();
|
||||
|
||||
std::string const& getName() const { return name_; }
|
||||
|
||||
Widget* getParent() { return parent_; }
|
||||
|
||||
int getWidth() const { return width_; }
|
||||
int getHeight() const { return height_; }
|
||||
int getRealWidth() const { return realWidth_; }
|
||||
int getRealHeight() const { return realHeight_; }
|
||||
|
||||
virtual void setSize(int width, int height);
|
||||
|
||||
/* Set background image. The image is scaled to the widgets actual size*/
|
||||
void setBackground(SDL_Surface* surf);
|
||||
/* Set background color. Only takes effect when the background image is NULL */
|
||||
void setBackgroundColor(SDL_Color bg);
|
||||
/* Set foreground color. Effect depends on widget type */
|
||||
virtual void setForegroundColor(SDL_Color fg);
|
||||
|
||||
/* Set the padding between the widget position and the content
|
||||
Exact effect depends on widget type. In general, when a widget is rendered
|
||||
the background is applied to the entire dstRect, and the content is
|
||||
rendered with padding*/
|
||||
void setPadding(int left, int top, int right, int bottom);
|
||||
|
||||
virtual void setAlignment(int horiz, int vert);
|
||||
|
||||
void setGLRenderPos(int left, int top);
|
||||
|
||||
virtual void render(SDL_Surface *dst, SDL_Rect *dstRect) const;
|
||||
void renderToGL() const;
|
||||
|
||||
protected:
|
||||
/* Update realWidth_ and realHeight_ where necessary
|
||||
(width_ or height_ == WRAP_CONTENT) */
|
||||
virtual void layout() = 0;
|
||||
|
||||
/* Inform the renderToGL() code that any cached presentations are now invalid */
|
||||
void invalidateGL() { renderTexValid_ = false; }
|
||||
|
||||
/* Helper to calculate the SDL_Rect with which to render the content,
|
||||
respecting alignment and padding */
|
||||
SDL_Rect calcContentRect(SDL_Surface *dst, SDL_Rect *dstRect, SDL_Rect contentRect) const;
|
||||
|
||||
void setParent(Widget *parent);
|
||||
|
||||
/* Helpers to allow Views to access protected methods of other Widgets */
|
||||
void _setParent(Widget& child) { child.setParent(this); }
|
||||
void _clearParent(Widget& child) { child.setParent(nullptr); }
|
||||
void _layout(Widget& child) { child.layout(); }
|
||||
|
||||
std::string name_;
|
||||
|
||||
int width_, height_;
|
||||
int realWidth_, realHeight_;
|
||||
|
||||
SDL_Surface *background_;
|
||||
SDL_Color bg_, fg_;
|
||||
|
||||
int padLeft_, padTop_, padRight_, padBottom_;
|
||||
|
||||
int alignHoriz_, alignVert_;
|
||||
|
||||
Widget *parent_;
|
||||
|
||||
private:
|
||||
struct VertexAttribs {
|
||||
int16_t vertex[2];
|
||||
uint16_t texCoords[2];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
int renderTop_, renderLeft_;
|
||||
|
||||
mutable bool renderTexValid_, renderAttribsValid_;
|
||||
mutable std::unique_ptr<Texture2D> renderTex_;
|
||||
mutable VBOManager::VBOAlloc vbo_;
|
||||
mutable gl::GLuint vaID_;
|
||||
};
|
||||
|
||||
#endif
|
||||
46
common.hh
46
common.hh
@@ -137,6 +137,9 @@ enum class VAFormats {
|
||||
VertexNormalTexcoord
|
||||
};
|
||||
|
||||
|
||||
// Some helpers to C++11-ify SDL
|
||||
|
||||
struct SDLSurfaceDeleter {
|
||||
void operator()(SDL_Surface* ptr) const
|
||||
{
|
||||
@@ -146,4 +149,47 @@ struct SDLSurfaceDeleter {
|
||||
|
||||
using SDLSurfaceUPtr = std::unique_ptr<SDL_Surface, SDLSurfaceDeleter>;
|
||||
|
||||
class SDLSurfaceScopedLock {
|
||||
public:
|
||||
SDLSurfaceScopedLock(SDL_Surface *surf) : surf_(surf) {
|
||||
if (SDL_MUSTLOCK(surf_))
|
||||
if (SDL_LockSurface(surf_) != 0)
|
||||
throw SDLException{};
|
||||
}
|
||||
|
||||
SDLSurfaceScopedLock(SDLSurfaceUPtr& surf) : surf_(surf.get()) {
|
||||
if (SDL_MUSTLOCK(surf_))
|
||||
if (SDL_LockSurface(surf_) != 0)
|
||||
throw SDLException{};
|
||||
}
|
||||
|
||||
SDLSurfaceScopedLock(SDLSurfaceScopedLock const& copy) = delete;
|
||||
SDLSurfaceScopedLock& operator=(SDLSurfaceScopedLock const& copy) = delete;
|
||||
|
||||
~SDLSurfaceScopedLock() {
|
||||
if (surf_ && SDL_MUSTLOCK(surf_))
|
||||
SDL_UnlockSurface(surf_);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
if (surf_ && SDL_MUSTLOCK(surf_))
|
||||
SDL_UnlockSurface(surf_);
|
||||
surf_ = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
SDL_Surface *surf_;
|
||||
};
|
||||
|
||||
static bool operator==(SDL_Color const& a, SDL_Color const& b) {
|
||||
return ((a.r == b.r) && (a.g == b.g) && (a.b == b.b) && (a.a == b.a));
|
||||
}
|
||||
|
||||
static bool operator!=(SDL_Color const& a, SDL_Color const& b) {
|
||||
return ((a.r != b.r) || (a.g != b.g) || (a.b != b.b) || (a.a != b.a));
|
||||
}
|
||||
|
||||
// Compatibility with C++11 where make_unique was not in std:: yet
|
||||
using std::make_unique;
|
||||
|
||||
#endif
|
||||
|
||||
105
main.cc
105
main.cc
@@ -25,6 +25,8 @@
|
||||
#include "Object.hh"
|
||||
#include "font.hh"
|
||||
#include "Overlay.hh"
|
||||
#include "TextWidget.hh"
|
||||
#include "LinearLayout.hh"
|
||||
|
||||
using namespace gl;
|
||||
|
||||
@@ -80,6 +82,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (!window) {
|
||||
std::printf("Could not create window: %s\n", SDL_GetError());
|
||||
TTF_Quit();
|
||||
IMG_Quit();
|
||||
SDL_Quit();
|
||||
return 1;
|
||||
}
|
||||
@@ -88,6 +92,8 @@ int main(int argc, char *argv[])
|
||||
if (!glcontext) {
|
||||
std::printf("Could not create GL context: %s\n", SDL_GetError());
|
||||
SDL_DestroyWindow(window);
|
||||
TTF_Quit();
|
||||
IMG_Quit();
|
||||
SDL_Quit();
|
||||
return 1;
|
||||
}
|
||||
@@ -136,8 +142,6 @@ int main(int argc, char *argv[])
|
||||
// sf::Time last = clock.getElapsedTime();
|
||||
auto last = SDL_GetTicks();
|
||||
|
||||
VBOManager vboManager;
|
||||
|
||||
Texture2D cubeTex("textures/Wood_Box_Texture.jpg");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<int>(GL_LINEAR_MIPMAP_LINEAR));
|
||||
if (SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic"))
|
||||
@@ -165,6 +169,7 @@ int main(int argc, char *argv[])
|
||||
// glm::vec3(0.0, 1.0, 0.0)};
|
||||
// const float lightIntensity[lights] = {75.0f, 25.0f};
|
||||
|
||||
glm::mat4 ovlProj = glm::ortho(0.0f, static_cast<float>(width), static_cast<float>(height), 0.0f);
|
||||
|
||||
Framebuffer shadowFB;
|
||||
|
||||
@@ -195,31 +200,46 @@ int main(int argc, char *argv[])
|
||||
glm::value_ptr(shadowProj));
|
||||
|
||||
ovlProg.use();
|
||||
glUniformMatrix4fv(ovlProg.getUniformLocation("projection_matrix"), 1, GL_FALSE,
|
||||
glm::value_ptr(ovlProj));
|
||||
glUniform1i(ovlProg.getUniformLocation("texBase"), 0);
|
||||
|
||||
Object box(vboManager, "objects/woodbox.obj", prog);
|
||||
Object pyramid(vboManager, "objects/pyramid.obj", prog);
|
||||
Object plane(vboManager, "objects/plane.obj", prog);
|
||||
|
||||
float px20_width = 2.0f*(60.0f/width);
|
||||
float px20_height = 2.0f*(20.0f/height);
|
||||
|
||||
std::vector<ovlVertexAttribs> ovlAttribs{
|
||||
{{glm::packSnorm1x16(1.0-px20_width), glm::packSnorm1x16(1.0)}, {0, 0}},
|
||||
{{glm::packSnorm1x16(1.0), glm::packSnorm1x16(1.0-px20_height)}, {65535u, 65535u}},
|
||||
{{glm::packSnorm1x16(1.0), glm::packSnorm1x16(1.0)}, {65535u, 0}},
|
||||
{{glm::packSnorm1x16(1.0-px20_width), glm::packSnorm1x16(1.0)}, {0, 0}},
|
||||
{{glm::packSnorm1x16(1.0-px20_width), glm::packSnorm1x16(1.0-px20_height)}, {0, 65535u}},
|
||||
{{glm::packSnorm1x16(1.0), glm::packSnorm1x16(1.0-px20_height)}, {65535u, 65535u}}};
|
||||
|
||||
Overlay ovl{vboManager, ovlAttribs, ovlProg};
|
||||
Object box("objects/woodbox.obj");
|
||||
Object pyramid("objects/pyramid.obj");
|
||||
Object plane("objects/plane.obj");
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
bool close = false;
|
||||
|
||||
Texture2D fpsTex{64, 64, true};
|
||||
unsigned fpsTime = 0, fpsCount = 0;
|
||||
TextWidget fpsText{font, "0 FPS"};
|
||||
fpsText.setBackgroundColor(SDL_Color{0, 255, 0, 128});
|
||||
fpsText.setPadding(8, 8, 8, 8);
|
||||
|
||||
auto laber = make_unique<TextWidget>(font, "Dies ist ein längerer\nText, der umgebrochen werden sollte. Bla laber schwafl, laber bullshit bingo",
|
||||
200, WRAP_CONTENT);
|
||||
laber->setBackgroundColor(SDL_Color{255, 0, 0, 128});
|
||||
laber->setPadding(4, 0, 4, 0);
|
||||
|
||||
SDLSurfaceUPtr buttonImg(IMG_Load("textures/button_100x30.png"));
|
||||
|
||||
if (!buttonImg)
|
||||
throw SDLException();
|
||||
|
||||
auto button = make_unique<TextWidget>(font, "Do stuff!", 100, 30);
|
||||
button->setPadding(6, 6, 6, 6);
|
||||
button->setBackground(buttonImg.get());
|
||||
button->setForegroundColor(SDL_Color{0, 0, 0, 255});
|
||||
button->setAlignment(ALIGN_CENTER, ALIGN_CENTER);
|
||||
|
||||
auto layout = make_unique<LinearLayout>();
|
||||
layout->setBackgroundColor(SDL_Color{0, 255, 255, 128});
|
||||
layout->addChild(std::move(laber));
|
||||
layout->addChild(std::move(button));
|
||||
layout->setChildPadding(4);
|
||||
layout->setPadding(4, 4, 4, 4);
|
||||
layout->setGLRenderPos(200, 200);
|
||||
|
||||
while (!close) {
|
||||
SDL_Event event;
|
||||
@@ -279,10 +299,18 @@ int main(int argc, char *argv[])
|
||||
glm::mat4 model = glm::translate(glm::vec3(0.5f, 0.5f, -0.5f)) *
|
||||
glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f)) *
|
||||
glm::translate(glm::vec3(-0.5f, -0.5f, 0.5f));
|
||||
box.draw(model, &shadowProg);
|
||||
plane.draw(glm::translate(glm::vec3(2.0f, -2.5f, 0.0f))*
|
||||
glm::rotate(0.35f, glm::vec3(0.0f, 1.0f, 0.0f)), &shadowProg);
|
||||
pyramid.draw(glm::translate(glm::vec3(-2.0f, 0.0f, 0.0f)), &shadowProg);
|
||||
glUniformMatrix4fv(shadowProg.getUniformLocation("model_matrix"), 1, GL_FALSE,
|
||||
glm::value_ptr(model));
|
||||
box.draw();
|
||||
model = glm::translate(glm::vec3(2.0f, -2.5f, 0.0f)) *
|
||||
glm::rotate(0.35f, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
glUniformMatrix4fv(shadowProg.getUniformLocation("model_matrix"), 1, GL_FALSE,
|
||||
glm::value_ptr(model));
|
||||
plane.draw();
|
||||
model = glm::translate(glm::vec3(-2.0f, 0.0f, 0.0f));
|
||||
glUniformMatrix4fv(shadowProg.getUniformLocation("model_matrix"), 1, GL_FALSE,
|
||||
glm::value_ptr(model));
|
||||
pyramid.draw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,24 +335,37 @@ int main(int argc, char *argv[])
|
||||
glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f)) *
|
||||
glm::translate(glm::vec3(-0.5f, -0.5f, 0.5f));
|
||||
cubeTex.bind();
|
||||
prog.use();
|
||||
|
||||
glUniformMatrix4fv(prog.getUniformLocation("model_matrix"), 1, GL_FALSE,
|
||||
glm::value_ptr(model));
|
||||
|
||||
// Shadow maps must be rendered before real drawing can begin
|
||||
glClientWaitSync(fence, SyncObjectMask(), 0xffffffffu);
|
||||
glDeleteSync(fence);
|
||||
|
||||
box.draw(model);
|
||||
|
||||
box.draw();
|
||||
|
||||
whiteTex.bind();
|
||||
plane.draw(glm::translate(glm::vec3(2.0f, -2.5f, 0.0f))*
|
||||
glm::rotate(0.35f, glm::vec3(0.0f, 1.0f, 0.0f)));
|
||||
model = glm::translate(glm::vec3(2.0f, -2.5f, 0.0f)) *
|
||||
glm::rotate(0.35f, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
glUniformMatrix4fv(prog.getUniformLocation("model_matrix"), 1, GL_FALSE,
|
||||
glm::value_ptr(model));
|
||||
plane.draw();
|
||||
|
||||
redTex.bind();
|
||||
pyramid.draw(glm::translate(glm::vec3(-2.0f, 0.0f, 0.0f)));
|
||||
model = glm::translate(glm::vec3(-2.0f, 0.0f, 0.0f));
|
||||
glUniformMatrix4fv(prog.getUniformLocation("model_matrix"), 1, GL_FALSE,
|
||||
glm::value_ptr(model));
|
||||
pyramid.draw();
|
||||
|
||||
auto now = SDL_GetTicks();
|
||||
auto elapsed = now - last;
|
||||
last = now;
|
||||
if (fpsTime+elapsed > 1000) {
|
||||
const std::string fpsText{std::to_string(fpsCount + 1) + " FPS"s};
|
||||
fpsTex = font.render(fpsText);
|
||||
fpsText.setText(std::to_string(fpsCount + 1) + " FPS");
|
||||
|
||||
fpsCount = 0;
|
||||
fpsTime = 0;
|
||||
} else {
|
||||
@@ -335,9 +376,10 @@ int main(int argc, char *argv[])
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
fpsTex.bind();
|
||||
ovlProg.use();
|
||||
|
||||
ovl.draw();
|
||||
fpsText.renderToGL();
|
||||
layout->renderToGL();
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
SDL_GL_SwapWindow(window);
|
||||
@@ -352,6 +394,7 @@ int main(int argc, char *argv[])
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
// Clean up
|
||||
TTF_Quit();
|
||||
IMG_Quit();
|
||||
SDL_Quit();
|
||||
|
||||
|
||||
20
shaders.cc
20
shaders.cc
@@ -121,14 +121,14 @@ GLint Program::getUniformLocation(std::string const& name) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
GLint Program::getAttribLocation(std::string const& name) const
|
||||
{
|
||||
auto search = _attribLocCache.find(name);
|
||||
if (search != _attribLocCache.end())
|
||||
return search->second;
|
||||
// GLint Program::getAttribLocation(std::string const& name) const
|
||||
// {
|
||||
// auto search = _attribLocCache.find(name);
|
||||
// if (search != _attribLocCache.end())
|
||||
// return search->second;
|
||||
|
||||
GLint ret = glGetAttribLocation(_progID, name.c_str());
|
||||
if (ret != -1)
|
||||
_attribLocCache.emplace(name, ret);
|
||||
return ret;
|
||||
}
|
||||
// GLint ret = glGetAttribLocation(_progID, name.c_str());
|
||||
// if (ret != -1)
|
||||
// _attribLocCache.emplace(name, ret);
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
#include "common.hh"
|
||||
|
||||
static const gl::GLint ATTRIB_VERTEX_POS = 0;
|
||||
static const gl::GLint ATTRIB_VERTEX_TC = 1;
|
||||
static const gl::GLint ATTRIB_VERTEX_NORM = 2;
|
||||
static const gl::GLint ATTRIB_VERTEX_COLOR = 3;
|
||||
|
||||
class ShaderException : public GLException {
|
||||
public:
|
||||
@@ -78,7 +82,7 @@ public:
|
||||
|
||||
gl::GLint getUniformLocation(std::string const& name) const;
|
||||
|
||||
gl::GLint getAttribLocation(std::string const& name) const;
|
||||
// gl::GLint getAttribLocation(std::string const& name) const;
|
||||
|
||||
private:
|
||||
GeometryShader* _geom;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
uniform mat4 projection_matrix;
|
||||
uniform mat4 modelview_matrix;
|
||||
|
||||
in vec3 vertex;
|
||||
in vec3 vertecColor;
|
||||
layout(location = 0) in vec3 vertex;
|
||||
layout(location = 3) in vec3 vertecColor;
|
||||
|
||||
out vec3 fragColor;
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#version 330 core
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
|
||||
uniform mat4 projection_matrix;
|
||||
|
||||
layout(location = 0) in vec2 vertex;
|
||||
layout(location = 1) in vec2 vertexTC;
|
||||
|
||||
out vec2 fragTC;
|
||||
|
||||
void main(void) {
|
||||
vec4 pos = vec4(vertex, 0.0, 1.0);
|
||||
vec4 pos = projection_matrix * vec4(vertex, 0.0, 1.0);
|
||||
gl_Position = pos;
|
||||
fragTC = vertexTC;
|
||||
}
|
||||
|
||||
15
texture.cc
15
texture.cc
@@ -101,10 +101,10 @@ void TextureCubeMap::bind() const
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, _texID);
|
||||
}
|
||||
|
||||
Texture2D::Texture2D()
|
||||
: texID_(0), width_(0), height_(0), alpha_(false)
|
||||
{
|
||||
}
|
||||
// Texture2D::Texture2D()
|
||||
// : texID_(0), width_(0), height_(0), alpha_(false)
|
||||
// {
|
||||
// }
|
||||
|
||||
Texture2D::Texture2D(unsigned width, unsigned height, bool alpha)
|
||||
: texID_(0), width_(width), height_(height), alpha_(alpha)
|
||||
@@ -202,14 +202,15 @@ void Texture2D::copyFromSurface(SDL_Surface *src)
|
||||
surf = src;
|
||||
}
|
||||
|
||||
if (SDL_MUSTLOCK(surf))
|
||||
SDL_LockSurface(surf);
|
||||
|
||||
SDLSurfaceScopedLock lock{surf};
|
||||
bind();
|
||||
if(surf->format->Amask == 0)
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGB, GL_UNSIGNED_BYTE, surf->pixels);
|
||||
else
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ private:
|
||||
|
||||
class Texture2D {
|
||||
public:
|
||||
Texture2D();
|
||||
// Texture2D();
|
||||
Texture2D(unsigned width, unsigned height, bool alpha = false);
|
||||
Texture2D(std::string const& file);
|
||||
Texture2D(SDL_Surface *surface);
|
||||
|
||||
BIN
textures/button_100x30.png
Normal file
BIN
textures/button_100x30.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 281 B |
Reference in New Issue
Block a user