Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+480
View File
@@ -0,0 +1,480 @@
#include "gui/skin.h"
#include "num_util.h"
#include "main/references.h"
#include "main/logging.h"
#include <map>
const gui::skin::Element* currentDrawnElement = 0;
vec2i eleDestSize;
void shader_skin_margin_src(float* margin,unsigned short,void*) {
if(currentDrawnElement) {
margin[0] = (float)currentDrawnElement->margin.topLeft.x;
margin[1] = (float)currentDrawnElement->margin.topLeft.y;
margin[2] = (float)currentDrawnElement->margin.botRight.x;
margin[3] = (float)currentDrawnElement->margin.botRight.y;
}
}
void shader_skin_margin_dest(float* margin,unsigned short,void*) {
if(currentDrawnElement) {
recti destMargin = currentDrawnElement->getDestinationMargin(eleDestSize);
margin[0] = (float)destMargin.topLeft.x;
margin[1] = (float)destMargin.topLeft.y;
margin[2] = (float)destMargin.botRight.x;
margin[3] = (float)destMargin.botRight.y;
}
}
void shader_skin_src_pos(float* pos,unsigned short,void*) {
if(currentDrawnElement) {
pos[0] = (float)currentDrawnElement->area.topLeft.x;
pos[1] = (float)currentDrawnElement->area.topLeft.y;
}
}
void shader_skin_src_size(float* size,unsigned short,void*) {
if(currentDrawnElement) {
size[0] = (float)currentDrawnElement->area.getWidth();
size[1] = (float)currentDrawnElement->area.getHeight();
}
}
void shader_skin_dst_size(float* size,unsigned short,void*) {
if(currentDrawnElement) {
size[0] = (float)eleDestSize.x;
size[1] = (float)eleDestSize.y;
}
}
void shader_skin_mode(float* modes,unsigned short,void*) {
if(currentDrawnElement) {
modes[0] = (float)currentDrawnElement->horizMode;
modes[1] = (float)currentDrawnElement->vertMode;
}
}
void shader_skin_gradientCount(float* count,unsigned short,void*) {
if(currentDrawnElement) {
*count = (float)currentDrawnElement->gradients.size();
}
}
void shader_skin_gradientMode(float* count,unsigned short,void*) {
if(currentDrawnElement) {
*count = (float)currentDrawnElement->gradMode;
}
}
void shader_skin_gradientRects(float* rects, unsigned short n,void*) {
if(currentDrawnElement) {
unsigned short cnt = (unsigned short)currentDrawnElement->gradients.size();
if(cnt < n)
n = cnt;
if(n == 0)
return;
recti baseRect(0,0, eleDestSize.width, eleDestSize.height);
for(unsigned short i = 0; i < n; ++i) {
auto& gradient = currentDrawnElement->gradients[i];
recti rect = gradient.area.evaluate(baseRect);
rects[i*4+0] = (float)rect.topLeft.x;
rects[i*4+1] = (float)rect.topLeft.y;
rects[i*4+2] = (float)rect.botRight.x;
rects[i*4+3] = (float)rect.botRight.y;
}
}
}
void shader_skin_gradientCols(float* cols, unsigned short n, void*) {
if(currentDrawnElement) {
n /= 4;
unsigned short cnt = (unsigned short)currentDrawnElement->gradients.size();
if(cnt < n)
n = cnt;
if(n == 0)
return;
Colorf* fcols = (Colorf*)cols;
for(unsigned short i = 0; i < n; ++i, fcols += 4) {
auto& gradient = currentDrawnElement->gradients[i];
new(fcols+0) Colorf(gradient.colors[0]);
new(fcols+1) Colorf(gradient.colors[1]);
new(fcols+2) Colorf(gradient.colors[2]);
new(fcols+3) Colorf(gradient.colors[3]);
}
}
}
namespace gui {
namespace skin {
std::map<std::string,unsigned> dynStyleIndices;
std::map<std::string,unsigned> dynElementFlags;
std::map<std::string,unsigned> dynFontIndices;
std::map<std::string,unsigned> dynColorIndices;
std::map<unsigned,std::string> dynFlagNames;
unsigned nextElementFlag = 1;
bool elementLower(Element* x, Element* y) {
return x->flags < y->flags;
}
int getDynamicIndex(std::map<std::string, unsigned>& dyn, const std::string& name, bool addIfMissing) {
auto index = dyn.find(name);
if(index == dyn.end()) {
if(addIfMissing) {
unsigned newIndex = (unsigned)dyn.size();
dyn[name] = newIndex;
return newIndex;
}
else {
return -1;
}
}
return index->second;
}
unsigned getStyleCount() {
return (unsigned)dynStyleIndices.size();
}
int getStyleIndex(const std::string& name, bool addIfMissing) {
return getDynamicIndex(dynStyleIndices, name, addIfMissing);
}
int getElementFlag(const std::string& name, bool addIfMissing) {
if(name == "Normal")
return 0;
auto index = dynElementFlags.find(name);
if(index == dynElementFlags.end()) {
if(addIfMissing) {
if(nextElementFlag == 0) {
nextElementFlag = 1;
error("Error: Skin exceeded limit of 32 unique element flags.");
}
unsigned flag = nextElementFlag;
dynElementFlags[name] = flag;
dynFlagNames[flag] = name;
if(flag == 0x100000000)
nextElementFlag = 0;
else
nextElementFlag = nextElementFlag << 1;
return flag;
}
else {
return 0;
}
}
return index->second;
}
std::string getElementFlagName(unsigned flag) {
if(flag == 0)
return "Normal";
unsigned check = 0x1;
unsigned cnt = 0;
std::string name;
for(unsigned i = 0; i < 32; ++i, check <<= 1) {
if((flag & check) != 0) {
if(cnt != 0)
name += ", ";
auto it = dynFlagNames.find(check);
if(it != dynFlagNames.end())
name += it->second;
else
name += "???";
++cnt;
}
}
return name;
}
int getColorIndex(const std::string& name, bool addIfMissing) {
return getDynamicIndex(dynColorIndices, name, addIfMissing);
}
int getFontIndex(const std::string& name, bool addIfMissing) {
return getDynamicIndex(dynFontIndices, name, addIfMissing);
}
void clearDynamicIndices() {
dynElementFlags.clear();
dynFlagNames.clear();
dynFontIndices.clear();
dynColorIndices.clear();
dynStyleIndices.clear();
nextElementFlag = 1;
}
void enumerateStyleIndices(std::function<void(const std::string&,unsigned)> callback) {
foreach(i, dynStyleIndices)
callback(i->first,i->second);
}
void enumerateElementFlags(void (*cb)(const std::string&,unsigned)) {
(*cb)("Normal", 0);
foreach(i, dynElementFlags)
(*cb)(i->first,i->second);
}
void enumerateColorIndices(void (*cb)(const std::string&,unsigned)) {
foreach(i, dynColorIndices)
(*cb)(i->first,i->second);
}
void enumerateFontIndices(void (*cb)(const std::string&,unsigned)) {
foreach(i, dynFontIndices)
(*cb)(i->first,i->second);
}
void Style::addElement(Element* ele) {
auto at = std::lower_bound(elements.begin(), elements.end(), ele, elementLower);
if(at == elements.end())
elements.push_back(ele);
else
elements.insert(at, ele);
}
Element* Style::getExactElement(unsigned flags) const {
foreach(it, elements) {
if((*it)->flags == flags)
return *it;
}
return nullptr;
}
const Element* Style::getElement(unsigned flags) const {
if(elements.empty())
return nullptr;
Element ele;
ele.flags = flags;
auto at = std::lower_bound(elements.begin(), elements.end(), &ele, elementLower);
size_t index;
if(at == elements.end())
index = elements.size() - 1;
else
index = at - elements.begin();
if(elements[index]->flags == flags)
return elements[index];
while(index > 0 && (~flags & elements[index]->flags))
--index;
return elements[index];
}
bool Skin::hasStyle(unsigned index) const {
if(index >= styles.size())
return false;
if(!styles[index])
return false;
return true;
}
const Style& Skin::getStyle(unsigned index) const {
if(index >= styles.size())
return *errorStyle;
if(!styles[index])
return *errorStyle;
return *styles[index];
}
const Element& Skin::getElement(unsigned index, unsigned flags) const {
if(index < styles.size() && styles[index]) {
const Element* ele = styles[index]->getElement(flags);
if(ele)
return *ele;
}
return *errorElement;
}
const render::Font& Skin::getFont(unsigned index) const {
if(index < (unsigned)fonts.size() && fonts[index])
return *fonts[index];
return *errorFont;
}
Color Skin::getColor(unsigned index) const {
if(index < (unsigned)colors.size())
return colors[index];
return Color();
}
void Skin::setStyle(unsigned index, Style* style) {
if(index >= (unsigned)styles.size())
styles.resize(index+1, 0);
styles[index] = style;
}
void Skin::setColor(unsigned index, Color color) {
if(index >= (unsigned)colors.size())
colors.resize(index+1);
colors[index] = color;
}
void Skin::setFont(unsigned index, const render::Font* font) {
if(index >= (unsigned)fonts.size())
fonts.resize(index+1, 0);
fonts[index] = font;
}
Skin::Skin() : fonts(), material(0) {
errorFont = render::Font::createDummyFont();
errorElement = new Element();
errorStyle = new Style();
}
void Gradient::draw(render::RenderDriver& driver, recti pos,
const recti* clip) const {
recti absPos = area.evaluate(pos);
driver.drawRectangle(absPos, 0, 0, colors, clip);
}
void Layer::draw(render::RenderDriver& driver, recti pos,
const recti* clip, Color color) const {
if(!ele)
return;
recti absPos = area.evaluate(pos);
ele->draw(driver, absPos, clip, hasOverride ? override : color);
}
void Element::clear() {
layers.clear();
gradients.clear();
margin = recti();
filled = true;
horizMode = DM_Uniform;
vertMode = DM_Uniform;
aspectMargin = AMM_None;
}
void Element::draw(render::RenderDriver& driver, recti pos,
const recti* clip, Color color) const {
Color colors[4] = {color, color, color, color};
foreach(it, layers)
(*it).draw(driver, pos, clip, color);
//TODO: Support no fill
if(!area.empty() || gradMode == GM_Overlay) {
currentDrawnElement = this;
eleDestSize = pos.getSize();
driver.drawRectangle(pos, material, 0, colors, clip);
currentDrawnElement = 0;
}
}
recti Element::getDestinationMargin(vec2i size) const {
recti destMargin;
switch(aspectMargin) {
case AMM_None:
destMargin.topLeft.x = margin.topLeft.x;
destMargin.topLeft.y = margin.topLeft.y;
destMargin.botRight.x = margin.botRight.x;
destMargin.botRight.y = margin.botRight.y;
break;
case AMM_Horizontal: {
float l_ratio = ((float)margin.topLeft.x) / ((float)area.getHeight());
float r_ratio = ((float)margin.botRight.x) / ((float)area.getHeight());
destMargin.topLeft.x = (int)(l_ratio * (float)size.height);
destMargin.topLeft.y = margin.topLeft.y;
destMargin.botRight.x = (int)(r_ratio * (float)size.height);
destMargin.botRight.y = margin.botRight.y;
} break;
case AMM_Vertical: {
float l_ratio = ((float)margin.topLeft.y) / ((float)area.getWidth());
float r_ratio = ((float)margin.botRight.y) / ((float)area.getWidth());
destMargin.topLeft.x = margin.topLeft.x;
destMargin.topLeft.y = (int)(l_ratio * (float)size.width);
destMargin.botRight.x = margin.botRight.x;
destMargin.botRight.y = (int)(r_ratio * (float)size.width);
} break;
}
return destMargin;
}
bool Element::isPixelActive(recti box, vec2i px) const {
if(!material)
return true;
auto* tex = material->textures[0];
if(!tex)
return true;
recti dmargin = getDestinationMargin(box.getSize());
int tx = 0;
switch(horizMode) {
case DM_Uniform:
tx = px.x + area.topLeft.x;
break;
case DM_Scaled:
case DM_Tiled:
if(px.x < dmargin.topLeft.x) {
tx = (int)((float)px.x * (float)margin.topLeft.x / (float)dmargin.topLeft.x) + area.topLeft.x;
}
else if(px.x >= box.getWidth() - dmargin.botRight.x) {
tx = area.botRight.x - (box.getWidth() -
(int)((float)px.x * (float)margin.botRight.x / (float)dmargin.botRight.x));
}
else {
tx = area.topLeft.x + margin.topLeft.x;
if(horizMode == DM_Scaled) {
tx += (int)(((double)(px.x - dmargin.topLeft.x)/
(double)(box.getWidth() - dmargin.topLeft.x - dmargin.botRight.x))
* (double)(area.getWidth() - margin.topLeft.x - margin.botRight.x));
}
else {
tx += (px.x - dmargin.topLeft.x) % (area.getWidth() - margin.topLeft.x - margin.botRight.x);
}
}
break;
}
int ty = 0;
switch(vertMode) {
case DM_Uniform:
ty = px.y + area.topLeft.y;
break;
case DM_Scaled:
case DM_Tiled:
if(px.y < dmargin.topLeft.y) {
ty = (int)((float)px.y * (float)margin.topLeft.y / (float)dmargin.topLeft.y) + area.topLeft.y;
}
else if(px.y >= box.getWidth() - dmargin.botRight.y) {
ty = area.botRight.y - (box.getHeight() -
(int)((float)px.y * (float)margin.botRight.y / (float)dmargin.botRight.y));
}
else {
ty = area.topLeft.y + margin.topLeft.y;
if(horizMode == DM_Scaled) {
ty += (int)(((double)(px.y - dmargin.topLeft.y)/
(double)(box.getHeight() - dmargin.topLeft.y - dmargin.botRight.y))
* (double)(area.getHeight() - margin.topLeft.y - margin.botRight.y));
}
else {
ty += (px.y - dmargin.topLeft.y) % (area.getHeight() - margin.topLeft.y - margin.botRight.y);
}
}
break;
}
return tex->isPixelActive(vec2i(tx, ty));
}
};
};
+133
View File
@@ -0,0 +1,133 @@
#pragma once
#include "render/driver.h"
#include "render/font.h"
#include "render/render_state.h"
#include "color.h"
#include "rect.h"
#include <vector>
#include <functional>
enum DimensionMode {
DM_Uniform,
DM_Scaled,
DM_Tiled
};
enum AspectMarginMode {
AMM_None,
AMM_Horizontal,
AMM_Vertical,
};
enum GradientMode {
GM_Normal,
GM_Overlay,
};
namespace gui {
namespace skin {
class Element;
struct Gradient {
Color colors[4];
relrecti area;
void draw(render::RenderDriver& driver, recti pos,
const recti* clip = 0) const;
};
struct Layer {
relrecti area;
const Element* ele;
Color override;
bool hasOverride;
Layer() : ele(0), hasOverride(false) {
}
void draw(render::RenderDriver& driver, recti pos,
const recti* clip = 0, Color color = Color(0xffffffff)) const;
};
class Element {
public:
unsigned flags;
const render::RenderState* material;
recti area;
recti margin;
AspectMarginMode aspectMargin;
bool filled;
DimensionMode horizMode, vertMode;
GradientMode gradMode;
std::vector<Gradient> gradients;
std::vector<Layer> layers;
Element() : material(0), aspectMargin(AMM_None), filled(true),
horizMode(DM_Uniform), vertMode(DM_Uniform), gradMode(GM_Normal) {}
void clear();
recti getDestinationMargin(vec2i size) const;
bool isPixelActive(recti box, vec2i px) const;
void draw(render::RenderDriver& driver, recti pos,
const recti* clip = 0, Color color = Color(0xffffffff)) const;
};
class Style {
public:
std::vector<Element*> elements;
bool irregular;
Style() : irregular(false) {}
void addElement(Element* ele);
Element* getExactElement(unsigned flags) const;
const Element* getElement(unsigned flags) const;
};
class Skin {
const render::Font* errorFont;
const Style* errorStyle;
const Element* errorElement;
public:
const render::RenderState* material;
std::string materialName;
std::vector<Style*> styles;
std::vector<Color> colors;
std::vector<const render::Font*> fonts;
void setStyle(unsigned index, Style* style);
void setColor(unsigned index, Color color);
void setFont(unsigned index, const render::Font* font);
bool hasStyle(unsigned index) const;
const Style& getStyle(unsigned index) const;
const Element& getElement(unsigned index, unsigned flags) const;
const render::Font& getFont(unsigned index) const;
Color getColor(unsigned index) const;
Skin();
};
unsigned getStyleCount();
int getStyleIndex(const std::string& name, bool addIfMissing = false);
int getColorIndex(const std::string& name, bool addIfMissing = false);
int getFontIndex(const std::string& name, bool addIfMissing = false);
int getElementFlag(const std::string& name, bool addIfMissing = false);
std::string getElementFlagName(unsigned flag);
void enumerateStyleIndices(std::function<void(const std::string&,unsigned)> callback);
void enumerateColorIndices(void (*cb)(const std::string&,unsigned));
void enumerateFontIndices(void (*cb)(const std::string&,unsigned));
void enumerateElementFlags(void (*cb)(const std::string&,unsigned));
void clearDynamicIndices();
};
};