float x0; float y0;
} vkvg_matrix_t;
+typedef struct {
+ float ascent;
+ float descent;
+ float height;
+ float max_x_advance;
+ float max_y_advance;
+} vkvg_font_extents_t;
+
+typedef struct {
+ float x_bearing;
+ float y_bearing;
+ float width;
+ float height;
+ float x_advance;
+ float y_advance;
+} vkvg_text_extents_t;
+
typedef struct _vkvg_context_t* VkvgContext;
typedef struct _vkvg_surface_t* VkvgSurface;
typedef struct _vkvg_device_t* VkvgDevice;
void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y);
void vkvg_set_source (VkvgContext ctx, VkvgPattern pat);
-void vkvg_select_font_face (VkvgContext ctx, const char* name);
-void vkvg_set_font_size (VkvgContext ctx, uint32_t size);
-void vkvg_show_text (VkvgContext ctx, const char* text);
-
void vkvg_save (VkvgContext ctx);
void vkvg_restore (VkvgContext ctx);
void vkvg_get_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix);
void vkvg_identity_matrix (VkvgContext ctx);
+//text
+void vkvg_select_font_face (VkvgContext ctx, const char* name);
+void vkvg_set_font_size (VkvgContext ctx, uint32_t size);
+void vkvg_show_text (VkvgContext ctx, const char* text);
+void vkvg_text_extents (VkvgContext ctx, const char* text, vkvg_text_extents_t* extents);
+void vkvg_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents);
+
//pattern
VkvgPattern vkvg_pattern_create ();
VkvgPattern vkvg_pattern_create_for_surface (VkvgSurface surf);
//set end idx of path to the same as start idx
ctx->pathes[ctx->pathPtr] = ctx->pathes [ctx->pathPtr-1];
//if last point of path is same pos as first point, remove it
- if (vec2_equ(ctx->points[ctx->pointCount-1], ctx->points[ctx->pathes[ctx->pathPtr]]))
- ctx->pointCount--;
+ //if (vec2_equ(ctx->points[ctx->pointCount-1], ctx->points[ctx->pathes[ctx->pathPtr]]))
+ // ctx->pointCount--;
_check_pathes_array(ctx);
ctx->pathPtr++;
}else
vec2 lastP = v;
v.x = cos(a)*radius + xc;
v.y = sin(a)*radius + yc;
- if (!vec2_equ (v,lastP))//this test should not be required
+ //if (!vec2_equ (v,lastP))//this test should not be required
_add_point (ctx, v.x, v.y);
}
void vkvg_arc_negative (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2) {
vec2 cp = _get_current_position(ctx);
_recursive_bezier (ctx, cp.x, cp.y, x1, y1, x2, y2, x3, y3, 0);
+ /*cp.x = x3;
+ cp.y = y3;
+ if (!vec2_equ(ctx->points[ctx->pointCount-1],cp))*/
_add_point(ctx,x3,y3);
}
void vkvg_rel_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) {
_init_cmd_buff (ctx);//push csts updated by init
}else
_update_push_constants (ctx);
-
- ctx->curRGBA.x = r;
- ctx->curRGBA.y = g;
- ctx->curRGBA.z = b;
- ctx->curRGBA.w = a;
}
void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y){
_flush_cmd_buff(ctx);
_record_draw_cmd (ctx);
}
+void vkvg_text_extents (VkvgContext ctx, const char* text, vkvg_text_extents_t* extents) {
+ _text_extents(ctx, text, extents);
+}
+void vkvg_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents) {
+ _font_extents(ctx, extents);
+}
+
void vkvg_save (VkvgContext ctx){
_flush_cmd_buff(ctx);
sav->pathes = (uint32_t*)malloc (sav->pathPtr * sizeof(uint32_t));
memcpy (sav->pathes, ctx->pathes, sav->pathPtr * sizeof(uint32_t));
- sav->curRGBA = ctx->curRGBA;
sav->lineWidth = ctx->lineWidth;
sav->lineCap = ctx->lineCap;
sav->lineWidth = ctx->lineWidth;
- sav->mat = ctx->pushConsts.mat;
- sav->matInv = ctx->pushConsts.matInv;
sav->selectedFont = ctx->selectedFont;
sav->selectedFont.fontFile = (char*)calloc(FONT_FILE_NAME_MAX_SIZE,sizeof(char));
memset (ctx->pathes, 0, ctx->sizePathes * sizeof(uint32_t));
memcpy (ctx->pathes, sav->pathes, ctx->pathPtr * sizeof(uint32_t));
- ctx->curRGBA = sav->curRGBA;
ctx->lineWidth = sav->lineWidth;
ctx->lineCap = sav->lineCap;
ctx->lineJoint = sav->lineJoint;
- ctx->pushConsts.mat = sav->mat;
- ctx->pushConsts.matInv = sav->matInv;
ctx->selectedFont.charSize = sav->selectedFont.charSize;
strcpy (ctx->selectedFont.fontFile, sav->selectedFont.fontFile);
#define m_approximation_scale 1.0
-#define m_angle_tolerance 0.5
-#define m_distance_tolerance 0.25
-#define m_cusp_limit 0.2
-#define curve_recursion_limit 32
-#define curve_collinearity_epsilon 0.01
-#define curve_angle_tolerance_epsilon 0.01
+#define m_angle_tolerance 0.05
+#define m_distance_tolerance 0.1
+#define m_cusp_limit 0.25
+#define curve_recursion_limit 16
+#define curve_collinearity_epsilon 0.001
+#define curve_angle_tolerance_epsilon 0.1
void _recursive_bezier (VkvgContext ctx,
float x1, float y1, float x2, float y2,
#include "vkh.h"
#include "vkvg_fonts.h"
-#define VKVG_PTS_SIZE 4096
+#define VKVG_PTS_SIZE 16384
#define VKVG_VBO_SIZE VKVG_PTS_SIZE * 2
#define VKVG_IBO_SIZE VKVG_VBO_SIZE * 2
-#define VKVG_PATHES_SIZE 128
+#define VKVG_PATHES_SIZE 256
#define VKVG_ARRAY_THRESHOLD 4
#define ROUND_DOWN(v,p) (floorf(v * p) / p)
vec2 curPos;
bool curPosExists;
- vec4 curRGBA;
float lineWidth;
vkvg_line_cap_t lineCap;
vkvg_line_join_t lineJoint;
- vkvg_matrix_t mat;
- vkvg_matrix_t matInv;
_vkvg_font_t selectedFont; //hold current face and size before cache addition
_vkvg_font_t* currentFont; //font ready for lookup
return NULL;
}
-void _show_text (VkvgContext ctx, const char* text){
+void _update_current_font (VkvgContext ctx) {
VkvgDevice dev = ctx->pSurf->dev;
-
if (ctx->currentFont == NULL){
ctx->currentFont = _tryFindVkvgFont (ctx);
if (ctx->currentFont == NULL){
- _font_cache_t* cache = (_font_cache_t*)dev->fontCache;
//create new font in cache
+ _font_cache_t* cache = dev->fontCache;
cache->fontsCount++;
if (cache->fontsCount == 1)
cache->fonts = (_vkvg_font_t*) malloc (cache->fontsCount * sizeof(_vkvg_font_t));
ctx->currentFont = &cache->fonts[cache->fontsCount-1];
}
}
+}
+hb_buffer_t * _get_hb_buffer (VkvgContext ctx, const char* text) {
hb_buffer_t *buf = hb_buffer_create();
const char *lng = "fr";
hb_script_t script = HB_SCRIPT_LATIN;
- script = hb_script_from_string(text,strlen(text));
+ script = hb_script_from_string (text, strlen (text));
hb_direction_t dir = hb_script_get_horizontal_direction(script);
//dir = HB_DIRECTION_TTB;
hb_buffer_set_direction (buf, dir);
hb_buffer_set_language (buf, hb_language_from_string(lng,strlen(lng)));
hb_buffer_add_utf8 (buf, text, strlen(text), 0, strlen(text));
- _vkvg_font_t* f = ctx->currentFont;
- hb_shape (f->hb_font, buf, NULL, 0);
+ hb_shape (ctx->currentFont->hb_font, buf, NULL, 0);
+ return buf;
+}
+void _font_extents (VkvgContext ctx, vkvg_font_extents_t *extents) {
+ _update_current_font (ctx);
+
+ //TODO: ensure correct metrics are returned (scalled/unscalled, etc..)
+ FT_BBox* bbox = &ctx->currentFont->face->bbox;
+ FT_Size_Metrics* metrics = &ctx->currentFont->face->size->metrics;
+ extents->ascent = metrics->ascender >> 6;
+ extents->descent= metrics->descender >> 6;
+ extents->height = metrics->height >> 6;
+ extents->max_x_advance = bbox->xMax >> 6;
+ extents->max_y_advance = bbox->yMax >> 6;
+}
+
+void _text_extents (VkvgContext ctx, const char* text, vkvg_text_extents_t *extents) {
+ _update_current_font (ctx);
+
+ hb_buffer_t* buf = _get_hb_buffer (ctx, text);
+ _vkvg_font_t* f = ctx->currentFont;
+ VkvgDevice dev = ctx->pSurf->dev;
+ unsigned int glyph_count;
+
+ hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions (buf, &glyph_count);
+
+ unsigned int string_width_in_pixels = 0;
+ for (int i=0; i < glyph_count; ++i)
+ string_width_in_pixels += glyph_pos[i].x_advance >> 6;
+
+ FT_Size_Metrics* metrics = &ctx->currentFont->face->size->metrics;
+ extents->x_advance = string_width_in_pixels;
+ extents->y_advance = glyph_pos[glyph_count-1].y_advance >> 6;
+ extents->x_bearing = -(glyph_pos[0].x_offset >> 6);
+ extents->y_bearing = -(glyph_pos[0].y_offset >> 6);
+
+ extents->height = (metrics->ascender + metrics->descender) >> 6;
+ extents->width = extents->x_advance;
+
+ //todo: populate other fields
+ hb_buffer_destroy (buf);
+}
+void _show_text (VkvgContext ctx, const char* text){
+
+ _update_current_font (ctx);
+
+ hb_buffer_t* buf = _get_hb_buffer (ctx, text);
+ _vkvg_font_t* f = ctx->currentFont;
+ VkvgDevice dev = ctx->pSurf->dev;
unsigned int glyph_count;
- hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos (buf, &glyph_count);
- hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions (buf, &glyph_count);
+ hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions (buf, &glyph_count);
unsigned int string_width_in_pixels = 0;
for (int i=0; i < glyph_count; ++i)
string_width_in_pixels += glyph_pos[i].x_advance >> 6;
+ hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos (buf, &glyph_count);
Vertex v = {};
vec2 pen = {0,0};
vkvg_move_to(ctx, pen.x, pen.y);
_flush_chars_to_tex(dev,f);
+ hb_buffer_destroy (buf);
//_show_texture(ctx); return;
}
-
+//debug function
void _show_texture (vkvg_context* ctx){
Vertex vs[] = {
{{0,0}, {0,0,1}},
void _select_font_face (VkvgContext ctx, const char* name);
void _set_font_size (VkvgContext ctx, uint32_t size);
void _show_text (VkvgContext ctx, const char* text);
+void _text_extents (VkvgContext ctx, const char* text, vkvg_text_extents_t *extents);
+void _font_extents (VkvgContext ctx, vkvg_font_extents_t* extents);
#endif
vkvg_stroke (ctx);
}
void vkvg_test_curves2 (VkvgContext ctx) {
- vkvg_set_source_rgba (ctx, 0.5,0.0,1.0,0.5);
- vkvg_set_line_width(ctx, 10);
-
vkvg_move_to (ctx, 100, 400);
vkvg_curve_to (ctx, 100, 100, 600,700,600,400);
-
- vkvg_move_to (ctx, 100, 100);
vkvg_curve_to (ctx, 1000, 100, 100, 800, 1000, 800);
- vkvg_move_to (ctx, 100, 150);
vkvg_curve_to (ctx, 1000, 500, 700, 500, 700, 100);
+ vkvg_close_path(ctx);
+
+ //vkvg_set_source_rgba (ctx, 0.5,0.0,1.0,0.5);
+ //vkvg_fill_preserve(ctx);
- vkvg_stroke (ctx);
+ vkvg_set_source_rgba (ctx, 0,0,0,1);
+ vkvg_set_line_width(ctx, 40);
+ vkvg_stroke(ctx);
}
void vkvg_test_curves (VkvgContext ctx){
//vkvg_select_font_face(ctx, "/usr/local/share/fonts/DroidSansMono.ttf");
//vkvg_select_font_face(ctx, "/usr/share/fonts/truetype/unifont/unifont.ttf");
- vkvg_set_font_size(ctx,size-10);
+ vkvg_set_font_size(ctx,12);
vkvg_select_font_face(ctx, "droid");
+ vkvg_font_extents_t fe;
+ vkvg_font_extents (ctx,&fe);
vkvg_move_to(ctx, penX,penY);
vkvg_set_source_rgba(ctx,0.7,0.7,0.7,1);
+ vkvg_text_extents_t te;
+ vkvg_text_extents(ctx,"abcdefghijk",&te);
vkvg_show_text (ctx,"abcdefghijk");
- penY+=size;
+ penX+= te.x_advance;
+ vkvg_move_to(ctx, penX,penY);
+ vkvg_show_text (ctx,"*abcdefghijk2");
+ penY+=2*size;
vkvg_select_font_face(ctx, "times");
vkvg_set_source_rgba(ctx,0.1,0.1,0.3,1.0);
vkvg_paint(ctx);
- vkvg_test_fill(ctx);
- vkvg_test_fill2(ctx);
+ //vkvg_test_fill(ctx);
+ //vkvg_test_fill2(ctx);
// vkvg_set_line_join(ctx,VKVG_LINE_JOIN_ROUND);
test_text(ctx);
- vkvg_test_stroke(ctx);
+ //vkvg_test_stroke(ctx);
// vkvg_translate(ctx, 10,10);
// vkvg_rotate(ctx, 0.2);
//vkvg_scale(ctx, 2,2);
- vkvg_test_gradient (ctx);
- vkvg_test_curves(ctx);
- vkvg_test_curves2(ctx);
+ //vkvg_test_gradient (ctx);
+ //vkvg_test_curves(ctx);
+ //vkvg_test_curves2(ctx);
//test_img_surface(ctx);
- test_line_caps(ctx);
+ //test_line_caps(ctx);
vkvg_destroy(ctx);
ctx = vkvg_create(surf);
vkvg_set_source_rgb (cr, 0, 0, 0);
vkvg_stroke (cr);
}
+void cairo_test_text (VkvgContext cr) {
+ vkvg_text_extents_t extents;
+
+ const char *utf8 = "vkvg";
+ float x,y;
+
+ vkvg_select_font_face (cr, "times");
+ vkvg_set_font_size (cr, 100.0);
+ vkvg_text_extents (cr, utf8, &extents);
+ vkvg_set_source_rgb(cr,0,0,0);
+
+ x=25.0;
+ y=150.0;
+
+ vkvg_move_to (cr, x,y);
+ vkvg_show_text (cr, utf8);
+
+ /* draw helping lines */
+ vkvg_set_source_rgba (cr, 1, 0.2, 0.2, 0.6);
+ vkvg_set_line_width (cr, 6.0);
+ vkvg_arc (cr, x, y, 10.0, 0, 2*M_PI);
+ vkvg_fill (cr);
+ vkvg_move_to (cr, x,y);
+ vkvg_rel_line_to (cr, 0, -extents.height);
+ vkvg_rel_line_to (cr, extents.width, 0);
+ vkvg_rel_line_to (cr, extents.x_bearing, -extents.y_bearing);
+ vkvg_stroke (cr);
+}
void cairo_test_clip (VkvgContext cr){
vkvg_arc (cr, 128.0, 128.0, 76.8, 0, 2 * M_PI);
vkvg_clip (cr);
vkvg_translate(ctx,250,0);
cairo_print_arc_neg(ctx);
+ vkvg_translate(ctx,250,0);
+ cairo_test_text(ctx);
+
vkvg_destroy(ctx);
}
vkvg_set_source_rgba(ctx,1.0,1.0,1.0,1);
vkvg_paint(ctx);
-
- vkvg_scale(ctx,0.5,0.5);
- vkvg_matrix_t m;
- vkvg_get_matrix(ctx, &m);
- vkvg_set_matrix(ctx, &m);
-
NSVGimage* svg;
NSVGshape* shape;
NSVGpath* path;
- svg = nsvgParseFromFile("/mnt/data/images/svg/tux.svg", "px", 96);
+ //svg = nsvgParseFromFile("/mnt/data/images/svg/tux.svg", "px", 96);
//svg = nsvgParseFromFile("/mnt/data/images/svg/world.svg", "px", 96);
//svg = nsvgParseFromFile("/mnt/data/images/svg/tiger.svg", "px", 96);
+ //svg = nsvgParseFromFile("/mnt/data/images/svg/koch_curve.svg", "px", 96);
+ //svg = nsvgParseFromFile("/mnt/data/images/svg/diamond1.svg", "px", 96);
+ //svg = nsvgParseFromFile("/mnt/data/images/svg/diamond2.svg", "px", 96);
+ //svg = nsvgParseFromFile("/home/jp/yahweh-protosinaitic.svg", "px", 96);
//svg = nsvgParseFromFile("/mnt/data/images/svg/WMD-biological.svg", "px", 96);
- //svg = nsvgParseFromFile("/mnt/data/images/svg/Skull_and_crossbones.svg", "px", 96);
+ svg = nsvgParseFromFile("/mnt/data/images/svg/Skull_and_crossbones.svg", "px", 96);
//svg = nsvgParseFromFile("/mnt/data/images/svg/IconAlerte.svg", "px", 96);
//svg = nsvgParseFromFile("/mnt/data/images/svg/Svg_example4.svg", "px", 96);
+ //vkvg_scale(ctx, 3,3);
vkvg_set_source_rgba(ctx,0.0,0.0,0.0,1);
for (shape = svg->shapes; shape != NULL; shape = shape->next) {
for (path = shape->paths; path != NULL; path = path->next) {
float* p = path->pts;
vkvg_move_to(ctx, p[0],p[1]);
- for (int i = 1; i < path->npts-4; i += 3) {
+ for (int i = 1; i < path->npts-2; i += 3) {
p = &path->pts[i*2];
vkvg_curve_to(ctx, p[0],p[1], p[2],p[3], p[4],p[5]);
}
}
vkvg_stroke(ctx);
-
- vkvg_flush(ctx);
}
nsvgDelete(svg);
+
vkvg_destroy(ctx);
}
int main(int argc, char *argv[]) {
- VkEngine* e = vke_create();
+ VkEngine* e = vke_create (VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, 1024, 800);
vke_set_key_callback (e, key_callback);
device = vkvg_device_create(e->phy, e->dev, e->renderer.queue, e->renderer.qFam);
(*qFamProps) = (VkQueueFamilyProperties*)malloc((*count) * sizeof(VkQueueFamilyProperties));
vkGetPhysicalDeviceQueueFamilyProperties (e->phy, count, (*qFamProps));
}
-VkEngine* vke_create () {
+VkEngine* vke_create (VkPhysicalDeviceType preferedGPU, uint32_t width, uint32_t height) {
VkEngine* e = (VkEngine*)calloc(1,sizeof(VkEngine));
glfwInit();
assert (glfwVulkanSupported()==GLFW_TRUE);
VkhPhyInfo pi = NULL;
for (int i=0; i<phyCount; i++){
pi = phys[i];
- if (pi->properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU){
+ if (pi->properties.deviceType == preferedGPU){
e->phy = pi->phy;
break;
}
assert (glfwGetPhysicalDevicePresentationSupport (e->app->inst, e->phy, pi->gQueue)==GLFW_TRUE);
- e->renderer.width = 1024;
- e->renderer.height = 800;
+ e->renderer.width = width;
+ e->renderer.height = height;
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
VkLoader loader;
}VkEngine;
-VkEngine* vke_create ();
+VkEngine* vke_create (VkPhysicalDeviceType preferedGPU, uint32_t width, uint32_t height);
void vke_destroy (VkEngine* e);
void initPhySurface(VkEngine* e, VkFormat preferedFormat, VkPresentModeKHR presentMode);