#version 140 #define DB_GRADIENT_MAX 16 #define DB_COMMAND_MAX 64 #define CMD_POINT 1 #define CMD_LINE 2 #define CMD_RECT 3 #define STRIKE_CENTER 0 #define STRIKE_OUTSET 1 #define STRIKE_INSET 2 in vec3 v_v3Position; in vec2 v_v2TexCoords; flat in int v_iCmdIndex; out vec4 f_Color; uniform sampler2D txForeground; uniform sampler2D txBackground; struct Gradient_t { float fPosition; float pad0; float pad1; float pad2; vec4 v4Color; }; uniform GradientBlock { Gradient_t vstGradientStops[DB_GRADIENT_MAX]; }; vec4 getGradientColor(float position, int index, int count) { position = clamp(position, 0, 1); int i0 = 0; float p0 = vstGradientStops[index + i0].fPosition; int i1 = count - 1; float p1 = vstGradientStops[index + i1].fPosition; for (int i = 0; i < count; i++) { float px = vstGradientStops[index + i].fPosition; if (px > p0 && px <= position) { p0 = px; i0 = i; } if (px < p1 && px >= position) { p1 = px; i1 = i; } } vec4 c0 = vstGradientStops[index + i0].v4Color; vec4 c1 = vstGradientStops[index + i1].v4Color; float l = p1 - p0; float w = (l > 0) ? (position - p0) / (p1 - p0) : 0; return mix(c0, c1, w); } struct CommandInfo_t { int iCommand; int iFlags; float fArg0; float fArg1; int iFgGradientIndex; int iFgGradientCount; int iBgGradientIndex; int iBgGradientCount; vec4 v4FgColor; vec4 v4BgColor; }; uniform CommandBlock { CommandInfo_t vstCommandInfo[DB_COMMAND_MAX]; }; CommandInfo_t getCommandInfo() { return vstCommandInfo[v_iCmdIndex]; } vec4 fgColor() { return getCommandInfo().v4FgColor; } vec4 bgColor() { return getCommandInfo().v4BgColor; } void Point(void) { vec4 fg = fgColor(); if (dot(v_v2TexCoords, v_v2TexCoords) <= 0.25) f_Color = fg; else discard; } #define LINE_NORMALIZED_RADIUS(cmd) cmd.fArg0 void Line(void) { vec4 fg = fgColor(); CommandInfo_t cmd = getCommandInfo(); float t = clamp(v_v2TexCoords.x, 0, 1); vec2 dv = v_v2TexCoords - vec2(t, 0); float d = dot(dv, dv); float lim = LINE_NORMALIZED_RADIUS(cmd); lim *= lim; if (d <= lim) f_Color = fg; else discard; } #define RECT_ASPECT_RATIO(cmd) (cmd.fArg0) #define RECT_BORDER_WIDTH(cmd) (cmd.fArg1) #define RECT_FILL(cmd) ((cmd.iFlags & (1 << 0)) != 0) #define RECT_BORDER(cmd) ((cmd.iFlags & (1 << 1)) != 0) #define RECT_STRIKE_MASK 3 #define RECT_STRIKE_SHIFT 2 #define RECT_STRIKE_KIND(cmd) ((cmd.iFlags & RECT_STRIKE_MASK) >> RECT_STRIKE_SHIFT) void Rect(void) { vec4 fg = fgColor(); vec4 bg = bgColor(); CommandInfo_t cmd = getCommandInfo(); float aspect = RECT_ASPECT_RATIO(cmd); float border = RECT_BORDER_WIDTH(cmd); int strikeKind = RECT_STRIKE_KIND(cmd); vec2 p = abs(2*v_v2TexCoords - vec2(1)); p.x = p.x/aspect; float m0; float m1; if (!RECT_BORDER(cmd)) { m0 = 1; m1 = 1; } else if (strikeKind == STRIKE_OUTSET) { m0 = 1; m1 = border; } else if (strikeKind == STRIKE_INSET) { m0 = 1-border; m1 = 1; } else // strikeKind == STRIKE_CENTER { float h = 0.5 * border; m0 = 1-border; m1 = 1+border; } if (p.x > m1*aspect || p.y > m1) { discard; } if (RECT_FILL(cmd)) { if (p.x <= 1 && p.y <= 1) { f_Color = fg; } } if (RECT_BORDER(cmd)) { float x = clamp(p.x, aspect*m0, aspect*m1); float y = clamp(p.y, m0, m1); if (p.x == x || p.y == y) { f_Color = bg; } } } void main(void) { switch (getCommandInfo().iCommand) { case CMD_POINT: Point(); break; case CMD_LINE: Line(); break; case CMD_RECT: Rect(); break; default: // Unimplemented value. f_Color = vec4(1, 0, 1, 1); break; } }