This commit is contained in:
John Alanbrook 2023-06-05 15:32:45 +00:00
parent 17fcbd26e7
commit 5a6a27772e
12 changed files with 374 additions and 120 deletions

View file

@ -30,6 +30,7 @@ struct point_vertex {
float radius;
};
static int point_c = 0;
static int point_sc = 0;
static struct point_vertex point_b[v_amt];
static sg_shader line_shader;
@ -44,6 +45,8 @@ struct line_vert {
};
static int line_c = 0;
static int line_v = 0;
static int line_sc = 0;
static int line_sv = 0;
static struct line_vert line_b[v_amt];
static uint16_t line_bi[v_amt];
@ -57,6 +60,8 @@ static sg_bindings poly_bind;
static sg_shader poly_shader;
static int poly_c = 0;
static int poly_v = 0;
static int poly_sc = 0;
static int poly_sv = 0;
struct poly_vertex {
cpVect pos;
float uv[2];
@ -69,6 +74,7 @@ static sg_pipeline circle_pipe;
static sg_bindings circle_bind;
static sg_shader csg;
static int circle_count = 0;
static int circle_sc = 0;
struct circle_vertex {
cpVect pos;
float radius;
@ -79,64 +85,88 @@ struct circle_vertex {
static struct circle_vertex circle_b[v_amt];
void debug_flush()
void debug_flush(HMM_Mat4 *view)
{
if (poly_c != 0) {
sg_apply_pipeline(poly_pipe);
sg_apply_bindings(&poly_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(projection));
sg_update_buffer(poly_bind.vertex_buffers[0], &(sg_range){
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
sg_append_buffer(poly_bind.vertex_buffers[0], &(sg_range){
.ptr = poly_b, .size = sizeof(struct poly_vertex)*poly_v});
sg_update_buffer(poly_bind.index_buffer, &(sg_range){
sg_append_buffer(poly_bind.index_buffer, &(sg_range){
.ptr = poly_bi, .size = sizeof(uint32_t)*poly_c});
sg_draw(0,poly_c,1);
poly_c = 0;
poly_v = 0;
sg_draw(poly_sc,poly_c,1);
}
if (point_c != 0) {
sg_apply_pipeline(point_pipe);
sg_apply_bindings(&point_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(projection));
sg_update_buffer(point_bind.vertex_buffers[0], &(sg_range){
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
sg_append_buffer(point_bind.vertex_buffers[0], &(sg_range){
.ptr = point_b,
.size = sizeof(struct point_vertex)*point_c});
sg_draw(0,point_c,1);
point_c = 0;
sg_draw(point_sc,point_c,1);
}
if (line_c != 0) {
sg_apply_pipeline(line_pipe);
sg_apply_bindings(&line_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(projection));
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
float time = lastTick;
sg_range tr = {
.ptr = &time,
.size = sizeof(float)
};
sg_apply_uniforms(SG_SHADERSTAGE_FS,0,&tr);
sg_update_buffer(line_bind.vertex_buffers[0], &(sg_range){
sg_append_buffer(line_bind.vertex_buffers[0], &(sg_range){
.ptr = line_b, .size = sizeof(struct line_vert)*line_v});
sg_update_buffer(line_bind.index_buffer, &(sg_range){
sg_append_buffer(line_bind.index_buffer, &(sg_range){
.ptr = line_bi, .size = sizeof(uint16_t)*line_c});
sg_draw(0,line_c,1);
line_c = 0;
line_v = 0;
sg_draw(line_sc,line_c,1);
}
if (circle_count != 0) {
sg_apply_pipeline(circle_pipe);
sg_apply_bindings(&circle_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection));
sg_update_buffer(circle_bind.vertex_buffers[0], &(sg_range){
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*view));
sg_append_buffer(circle_bind.vertex_buffers[0], &(sg_range){
.ptr = circle_b,
.size = sizeof(struct circle_vertex)*circle_count
});
sg_draw(0,4,circle_count);
circle_count = 0;
sg_draw(circle_sc,4,circle_count);
}
}
void debug_nextpass()
{
point_sc = point_c;
point_c = 0;
circle_sc = circle_count;
circle_count = 0;
line_sv = line_v;
line_v = 0;
line_sc = line_c;
line_c = 0;
poly_sc = poly_c;
poly_c = 0;
poly_sv = poly_v;
poly_v = 0;
}
void debug_newframe()
{
point_sc = 0;
point_c = 0;
circle_sc = circle_count = line_sv = line_v = line_sc = line_c = poly_sc = poly_c = 0;
poly_sv = poly_v = 0;
}
static sg_shader_uniform_block_desc projection_ubo = {
.size = sizeof(projection),
.uniforms = {
@ -171,7 +201,7 @@ void debugdraw_init()
});
point_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct point_vertex)*5000,
.size = sizeof(struct point_vertex)*v_amt,
.usage = SG_USAGE_STREAM
});
@ -197,12 +227,12 @@ void debugdraw_init()
});
line_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct line_vert)*5000,
.size = sizeof(struct line_vert)*v_amt,
.usage = SG_USAGE_STREAM
});
line_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(uint16_t)*5000,
.size = sizeof(uint16_t)*v_amt,
.usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_INDEXBUFFER
});
@ -343,8 +373,8 @@ void draw_line(cpVect *a_points, int a_n, struct rgba color, float seg_len, int
uint16_t idxs[i_c];
for (int i = 0, d = 0; i < n-1; i++, d+=2) {
idxs[d] = i + line_v;
idxs[d+1] = i+1 + line_v;
idxs[d] = i + line_v + line_sv;
idxs[d+1] = i+1 + line_v + line_sv;
}
sg_range vr = {
@ -467,7 +497,7 @@ void draw_edge(cpVect *points, int n, struct rgba color, int thickness, int clos
});
for (int i = 0; i < mesh->num_triangles*3; i++)
mesh->triangle_indices[i] += poly_v;
mesh->triangle_indices[i] += (poly_v+poly_sv);
struct poly_vertex vertices[mesh->num_vertices];
@ -595,7 +625,7 @@ void draw_poly(cpVect *points, int n, struct rgba color)
}
for (int i = 0; i < tric*3; i++)
tridxs[i] += poly_v;
tridxs[i] += poly_v+poly_sv;
sg_range trip = {
.ptr = tridxs,
@ -622,8 +652,3 @@ void draw_poly(cpVect *points, int n, struct rgba color)
poly_c += tric*3;
poly_v += n;
}
void debugdraw_flush()
{
}

View file

@ -2,6 +2,7 @@
#define DEBUGDRAW_H
#include <chipmunk/chipmunk.h>
#include "HandmadeMath.h"
struct rgba;
void debugdraw_init();
@ -19,9 +20,8 @@ void draw_poly(cpVect *points, int n, struct rgba color);
void draw_grid(int width, int span, struct rgba color);
void debug_flush();
void debugdraw_flush(); /* This is called once per frame to draw all queued elements */
void debug_flush(HMM_Mat4 *view);
void debug_newframe();
cpVect inflatepoint(cpVect a, cpVect b, cpVect c, float d);
void inflatepoints(cpVect *r, cpVect *p, float d, int n);

View file

@ -1564,6 +1564,25 @@ JSValue duk_make_timer(JSContext *js, JSValueConst this, int argc, JSValueConst
return JS_NewInt64(js, id);
}
JSValue duk_cmd_points(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
{
int n = js_arrlen(argv[1]);
cpVect points[n];
for (int i = 0; i < n; i++)
points[i] = js2vec2(js_arridx(argv[1], i));
int cmd = js2int(argv[0]);
switch(cmd) {
case 0:
draw_poly(points, n, js2color(argv[2]));
break;
}
return JS_NULL;
}
#define DUK_FUNC(NAME, ARGS) JS_SetPropertyStr(js, globalThis, #NAME, JS_NewCFunction(js, duk_##NAME, #NAME, ARGS));
void ffi_load() {
@ -1592,6 +1611,8 @@ void ffi_load() {
DUK_FUNC(cmd_edge2d, 6)
DUK_FUNC(make_timer, 3)
DUK_FUNC(cmd_points, 5);
DUK_FUNC(cmd, 6)
DUK_FUNC(register, 3)
DUK_FUNC(register_collide, 6)

View file

@ -190,8 +190,10 @@ struct sFont *MakeFont(const char *fontfile, int height) {
}
stbtt_GetFontVMetrics(&fontinfo, &newfont->ascent, &newfont->descent, &newfont->linegap);
float emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16);
newfont->linegap = (newfont->ascent - newfont->descent)* 2 * emscale;
newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16);
newfont->linegap = (newfont->ascent - newfont->descent)* 2 * newfont->emscale;
YughWarn("Font ascent descent is %g", (newfont->ascent-newfont->descent)*newfont->emscale);
newfont->texID = sg_make_image(&(sg_image_desc){
.type = SG_IMAGETYPE_2D,
@ -218,8 +220,8 @@ struct sFont *MakeFont(const char *fontfile, int height) {
r.t1 = (glyph.y1) / (float)packsize;
stbtt_GetCodepointHMetrics(&fontinfo, c, &newfont->Characters[c].Advance, &newfont->Characters[c].leftbearing);
newfont->Characters[c].Advance *= emscale;
newfont->Characters[c].leftbearing *= emscale;
newfont->Characters[c].Advance *= newfont->emscale;
newfont->Characters[c].leftbearing *= newfont->emscale;
// newfont->Characters[c].Advance = glyph.xadvance; /* x distance from this char to the next */
newfont->Characters[c].Size[0] = glyph.x1 - glyph.x0;
@ -268,7 +270,7 @@ void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgb
float lsize = 1.0 / 1024.0;
float oline = 1.0;
float oline = 0.0;
vert.pos.x = cursor.X + c.Bearing[0] * scale + oline;
vert.pos.y = cursor.Y - c.Bearing[1] * scale - oline;
@ -348,9 +350,16 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
}
}
float height = cursor.Y + (font->linegap*scale);
float height = cursor.Y + (font->height*scale);
float width = lw > 0 ? lw : cursor.X;
struct boundingbox bb = {};
bb.l = 0;
bb.t = font->ascent * font->emscale * scale;
bb.b = font->descent * font->emscale * scale;
bb.r = cursor.X;
return bb;
return cwh2bb((HMM_Vec2){0,0}, (HMM_Vec2){width,height});
}

View file

@ -24,6 +24,7 @@ struct sFont {
int ascent;
int descent;
int linegap;
float emscale;
struct Character Characters[127];
sg_image texID;
};

View file

@ -329,9 +329,7 @@ void openglRender(struct window *window) {
sprite_draw_all();
sprite_flush();
call_draw();
// debug_flush();
//// DEBUG
if (debugDrawPhysics) {
@ -339,13 +337,15 @@ void openglRender(struct window *window) {
call_debugs();
}
debug_flush();
debug_flush(&projection);
////// TEXT && GUI
debug_nextpass();
call_gui();
text_flush();
debug_flush(&hudproj);
nuke_start();
call_nk_gui();
nuke_end();
@ -358,8 +358,9 @@ void openglRender(struct window *window) {
sg_draw(0,6,1);
sg_end_pass();
sg_commit();
debug_newframe();
}
sg_shader sg_compile_shader(const char *v, const char *f, sg_shader_desc *d)

View file

@ -19,6 +19,7 @@ struct TextureOptions TEX_SPRITE = {1, 0, 0};
static struct sprite *sprites;
static int first = -1;
static sg_shader shader_sprite;
static sg_pipeline pip_sprite;
static sg_bindings bind_sprite;
@ -28,6 +29,23 @@ struct sprite_vert {
struct rgba color;
};
static sg_shader slice9_shader;
static sg_pipeline slice9_pipe;
static sg_bindings slice9_bind;
static float slice9_points[8] = {
0.0, 0.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0
};
struct slice9_vert {
HMM_Vec2 pos;
struct uv_n uv;
unsigned short border[4];
HMM_Vec2 scale;
struct rgba color;
};
int make_sprite(int go) {
struct sprite sprite = {
.color = color_white,
@ -118,7 +136,7 @@ void sprite_settex(struct sprite *sprite, struct Texture *tex) {
sprite_setframe(sprite, &ST_UNIT);
}
sg_shader shader_sprite;
void sprite_initialize() {
shader_sprite = sg_compile_shader("shaders/spritevert.glsl", "shaders/spritefrag.glsl", &(sg_shader_desc){
@ -134,8 +152,7 @@ void sprite_initialize() {
.image_type = SG_IMAGETYPE_2D,
.sampler_type = SG_SAMPLERTYPE_FLOAT,
},
.fs.uniform_blocks[0] = {.size = 12, .uniforms = {[0] = {.name = "spriteColor", .type = SG_UNIFORMTYPE_FLOAT3}}}});
});
pip_sprite = sg_make_pipeline(&(sg_pipeline_desc){
.shader = shader_sprite,
@ -159,6 +176,40 @@ void sprite_initialize() {
.usage = SG_USAGE_STREAM,
.label = "sprite vertex buffer",
});
slice9_shader = sg_compile_shader("shaders/slice9_v.glsl", "shaders/slice9_f.glsl", &(sg_shader_desc) {
.vs.uniform_blocks[0] = {
.size = 64,
.layout = SG_UNIFORMLAYOUT_STD140,
.uniforms = { [0] = {.name = "projection", .type = SG_UNIFORMTYPE_MAT4},
}},
.fs.images[0] = {
.name = "image",
.image_type = SG_IMAGETYPE_2D,
.sampler_type = SG_SAMPLERTYPE_FLOAT
},
});
slice9_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = slice9_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2,
[1].format = SG_VERTEXFORMAT_USHORT4N,
[2].format = SG_VERTEXFORMAT_FLOAT2,
[3].format = SG_VERTEXFORMAT_UBYTE4N
}},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
});
slice9_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct slice9_vert) * 100,
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_STREAM,
});
}
/* offset given in texture offset, so -0.5,-0.5 results in it being centered */
@ -179,7 +230,6 @@ void tex_draw(struct Texture *tex, HMM_Vec2 pos, float angle, HMM_Vec2 size, HMM
tex->height * st_s_h(r) * size.Y
};
for (int i = 0; i < 4; i++) {
sposes[i] = HMM_AddV2(sposes[i], offset);
sposes[i] = HMM_MulV2(sposes[i], t_scale);
@ -217,6 +267,8 @@ void sprite_draw(struct sprite *sprite) {
}
}
void sprite_setanim(struct sprite *sprite, struct TexAnim *anim, int frame) {
if (!sprite) return;
sprite->tex = anim->tex;
@ -232,6 +284,47 @@ void gui_draw_img(const char *img, HMM_Vec2 pos, float scale, float angle) {
tex_draw(tex, pos, 0.f, size, offset, tex_get_rect(tex), color_white);
}
void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba color)
{
sg_apply_pipeline(slice9_pipe);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
struct Texture *tex = texture_loadfromfile(img);
struct glrect r = tex_get_rect(tex);
struct slice9_vert verts[4];
HMM_Vec2 sposes[4] = {
{0.0,0.0},
{1.0,0.0},
{0.0,1.0},
{1.0,1.0},
};
for (int i = 0; i < 4; i++) {
verts[i].pos = HMM_MulV2(sposes[i], dimensions);
//verts[i].uv =z sposes[i];
verts[i].color = color;
}
verts[0].uv.u = r.s0 * USHRT_MAX;
verts[0].uv.v = r.t1 * USHRT_MAX;
verts[1].uv.u = r.s1 * USHRT_MAX;
verts[1].uv.v = r.t1 * USHRT_MAX;
verts[2].uv.u = r.s0 * USHRT_MAX;
verts[2].uv.v = r.t0 * USHRT_MAX;
verts[3].uv.u = r.s1 * USHRT_MAX;
verts[3].uv.v = r.t0 * USHRT_MAX;
bind_sprite.fs_images[0] = tex->id;
sg_append_buffer(bind_sprite.vertex_buffers[0], SG_RANGE_REF(verts));
sg_apply_bindings(&bind_sprite);
sg_draw(sprite_count * 4, 4, 1);
sprite_count++;
}
void sprite_setframe(struct sprite *sprite, struct glrect *frame) {
sprite->frame = *frame;
}

View file

@ -1,18 +1,3 @@
var fns = [
() => {
var ttt = {};
Object.defineProperty(ttt, 'a', {});
ttt.a = 5;
},
() => { Log.warn("did it"); }
];
//fns.forEach(x => x());
/* Prototypes out an object and extends with values */
function clone(proto, binds) {
var c = Object.create(proto);
@ -539,6 +524,15 @@ function points2bb(points) {
return b;
};
function bb2points(bb)
{
return [
[bb.l,bb.t],
[bb.r,bb.t],
[bb.r,bb.b],
[bb.l,bb.b]
];
}
function bb2cwh(bb) {
if (!bb) return undefined;
@ -552,6 +546,23 @@ function bb2cwh(bb) {
return cwh;
};
function pointinbb(bb, p)
{
if (bb.t < p.y || bb.b > p.y || bb.l > p.x || bb.r < p.x)
return false;
return true;
}
function movebb(bb, pos) {
var newbb = Object.assign({}, bb);
newbb.t += pos.y;
newbb.b += pos.y;
newbb.l += pos.x;
newbb.r += pos.x;
return newbb;
};
function bb_expand(oldbb, x) {
if (!oldbb || !x) return;
var bb = {};

View file

@ -8,7 +8,6 @@ var Gizmos = {
var Shape = {
circle(pos, radius, color) {
cmd(115, pos, radius, color);
},
};
@ -31,6 +30,10 @@ var Debug = {
cmd(81, start, end, color, capsize);
},
poly(points, color) {
cmd_points(0,points,color);
},
box(pos, wh, color) {
color = color ? color : Color.white;
cmd(53, pos, wh, color);

View file

@ -162,30 +162,32 @@ var GUI = {
return cwh2bb([0,0], wh);
},
nodrawbb: {
draw() { return cwh2bb([0,0],[0,0]); }
},
image_fn(defn) {
var def = Object.create(this.defaults);
Object.assign(def,defn);
if (!def.path) {
Log.warn("GUI image needs a path.");
return GUI.nodrawbb;
def.draw = function(){};
return def;
}
return {
draw(pos) {
def.draw = function(pos) {
def.calc_bb(pos);
var wh = cmd(64,def.path);
gui_img(def.path, pos, def.scale, def.angle);
this.bb = cwh2bb([0,0],wh);
}
gui_img(def.path, pos.sub(def.anchor.scale(wh)), def.scale, def.angle, def.color);
};
def.calc_bb = function(cursor) {
var wh = cmd(64,def.path).scale(def.scale);
def.bb = cwh2bb(wh.scale([0.5,0.5]), wh);
def.bb = movebb(def.bb, cursor.sub(wh.scale(def.anchor)));
};
return def;
},
defaults: {
padding:[0,0],
padding:[2,2], /* Each element inset with this padding on all sides */
font: "fonts/LessPerfectDOSVGA.ttf",
font_size: 1,
text_align: "left",
@ -198,7 +200,7 @@ var GUI = {
},
text_outline: 1, /* outline in pixels */
color: [255,255,255,255],
margin: [5,5],
margin: [5,5], /* Distance between elements for things like columns */
width: 0,
height: 0,
},
@ -208,19 +210,32 @@ var GUI = {
var def = Object.create(this.defaults);
Object.assign(def,defn);
return {
draw: function(cursor) {
var wh = bb2wh(cmd(118,str,def.font_size,def.width));
var pos = cursor.sub(wh.scale(def.anchor));
ui_text(str, pos, def.font_size, def.color, def.width);
this.bb = cwh2bb(pos,wh);
return cwh2bb(pos,wh);
def.draw = function(cursor) {
def.calc_bb(cursor);
var old = def;
def = Object.create(def);
if (def.hovered && pointinbb(def.bb, Mouse.screenpos) || def.selected) {
Object.assign(def, def.hovered);
def.calc_bb(cursor);
}
var pos = cursor.sub(bb2wh(def.bb).scale(def.anchor));
ui_text(str, pos, def.font_size, def.color, def.width);
def = old;
};
},
button_fn(str, cb, defn) {
def.calc_bb = function(cursor) {
var bb = cmd(118, str, def.font_size, def.width);
var wh = bb2wh(bb);
var pos = cursor.sub(wh.scale(def.anchor));
def.bb = movebb(bb,pos);
};
return def;
},
column(defn) {
@ -229,12 +244,20 @@ var GUI = {
if (!def.items) {
Log.warn("Columns needs items.");
return GUI.nodrawbb;
def.draw = function(){};
return def;
};
def.items.forEach(function(item,idx) {
Object.setPrototypeOf(def.items[idx], def);
});
def.draw = function(pos) {
var c = Color.red.slice();
c.a = 100;
def.items.forEach(function(item) {
item.draw(pos);
item.draw.call(this,pos);
Debug.poly(bb2points(item.bb), c);
var wh = bb2wh(item.bb);
pos.y -= wh.y;
pos.y -= def.padding.x*2;
@ -457,6 +480,12 @@ var Mouse = {
return cmd(45);
},
get screenpos() {
var p = this.pos;
p.y = Window.dimensions.y - p.y;
return p;
},
get worldpos() {
return screen2world(cmd(45));
},

View file

@ -0,0 +1,37 @@
#version 330
in vec2 uv; /* image uv */
in vec4 border; /* uv length of border, normalized to image dimensions; left, bottom, right, top */
in vec2 scale; /* polygon dimensions / texture dimensions */
in vec4 fcolor;
out vec4 color;
uniform sampler2d image;
float map(float value, float min1, float max1, float min2, float max2)
{
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
float processAxis(float coord, float texBorder, float winBorder)
{
if (coord < winBorder)
return map(coord, 0, winBorder, 0, texBorder);
if (coord < 1 - winBorder)
return map(coord, winBorder, 1 - winBorder, texBorder, 1 - texBorder);
return map(coord, 1 - winBorder, 1, 1 - texBorder, 1);
}
uv9slice(vec2 uv, vec2 s, vec4 b)
{
vec2 t = clamp((s * uv - b.xy) / (s - b.xy - b.zw), 0.0, 1.0);
return mix(uv * s, 1.0 - s * (1.0 - uv), t);
}
void main()
{
uv = uv9slice(uv, scale, border);
color = fcolor * texture(image, uv);
}

View file

@ -0,0 +1,24 @@
#version 330 core
layout (location = 0) in vec2 vert;
layout (location = 1) in vec2 uv;
layout (location = 2) in vec4 vborder;
layout (location = 3) in vec2 vscale;
layout (location = 4) in vec4 vcolor;
out vec2 uv;
out vec4 border;
out vec2 scale;
out vec4 fcolor;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(vert, 0.0, 1.0);
uv = vert;
border = vborder;
scale = vscale;
fcolor = vcolor;
}