diff options
-rw-r--r-- | vcl/Library_vcl.mk | 2 | ||||
-rwxr-xr-x | vcl/glyphy/demo.cxx | 19 | ||||
-rw-r--r-- | vcl/glyphy/demo/demo-atlas.cc | 144 | ||||
-rw-r--r-- | vcl/glyphy/demo/demo-buffer.cc | 191 | ||||
-rw-r--r-- | vcl/glyphy/demo/demo-font.cc | 333 | ||||
-rw-r--r-- | vcl/glyphy/demo/demo-shader.cc | 212 | ||||
-rw-r--r-- | vcl/glyphy/demo/matrix4x4.c | 481 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo.hxx | 21 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-atlas-glsl.h | 18 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-atlas.h | 54 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-buffer.h | 64 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-common.h | 186 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-font.h | 88 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-fshader-glsl.h | 88 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-shader.h | 47 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/demo-vshader-glsl.h | 24 | ||||
-rw-r--r-- | vcl/inc/glyphy/demo/matrix4x4.h | 107 | ||||
-rw-r--r-- | vcl/win/source/gdi/winlayout.cxx | 499 |
18 files changed, 2270 insertions, 308 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 983e10fd228a..f3981dd774e1 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -41,6 +41,7 @@ $(eval $(call gb_Library_set_include,vcl,\ $$(INCLUDE) \ -I$(SRCDIR)/vcl/inc \ $(if $(filter WNTGCC,$(OS)$(COM)),-I$(MINGW_SYSROOT)/include/gdiplus) \ + $(if $(filter WNT,$(OS)),-I$(SRCDIR)/vcl/inc/glyphy/demo) \ )) ifeq ($(ENABLE_DBUS),TRUE) @@ -690,6 +691,7 @@ endif ifeq ($(OS),WNT) $(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/glyphy/demo \ vcl/opengl/win/gdiimpl \ vcl/opengl/win/WinDeviceInfo \ vcl/opengl/win/blocklist_parser \ diff --git a/vcl/glyphy/demo.cxx b/vcl/glyphy/demo.cxx new file mode 100755 index 000000000000..7f4f12adc74e --- /dev/null +++ b/vcl/glyphy/demo.cxx @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <prewin.h> +#include <postwin.h> + +namespace GLyphyDemo { +#include "demo/demo-atlas.cc" +#include "demo/demo-buffer.cc" +#include "demo/demo-font.cc" +#include "demo/demo-shader.cc" +#include "demo/matrix4x4.c" +} diff --git a/vcl/glyphy/demo/demo-atlas.cc b/vcl/glyphy/demo/demo-atlas.cc new file mode 100644 index 000000000000..d84da068363a --- /dev/null +++ b/vcl/glyphy/demo/demo-atlas.cc @@ -0,0 +1,144 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-atlas.h" + + +struct demo_atlas_t { + unsigned int refcount; + + GLuint tex_unit; + GLuint tex_name; + GLuint tex_w; + GLuint tex_h; + GLuint item_w; + GLuint item_h_q; /* height quantum */ + GLuint cursor_x; + GLuint cursor_y; +}; + + +demo_atlas_t * +demo_atlas_create (unsigned int w, + unsigned int h, + unsigned int item_w, + unsigned int item_h_quantum) +{ + TRACE(); + + demo_atlas_t *at = (demo_atlas_t *) calloc (1, sizeof (demo_atlas_t)); + at->refcount = 1; + + glGetIntegerv (GL_ACTIVE_TEXTURE, (GLint *) &at->tex_unit); + glGenTextures (1, &at->tex_name); + at->tex_w = w; + at->tex_h = h; + at->item_w = item_w; + at->item_h_q = item_h_quantum; + at->cursor_x = 0; + at->cursor_y = 0; + + demo_atlas_bind_texture (at); + + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + gl(TexImage2D) (GL_TEXTURE_2D, 0, GL_RGBA, at->tex_w, at->tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + return at; +} + +demo_atlas_t * +demo_atlas_reference (demo_atlas_t *at) +{ + if (at) at->refcount++; + return at; +} + +void +demo_atlas_destroy (demo_atlas_t *at) +{ + if (!at || --at->refcount) + return; + + glDeleteTextures (1, &at->tex_name); + free (at); +} + +void +demo_atlas_bind_texture (demo_atlas_t *at) +{ + glActiveTexture (at->tex_unit); + glBindTexture (GL_TEXTURE_2D, at->tex_name); +} + +void +demo_atlas_set_uniforms (demo_atlas_t *at) +{ + GLuint program; + glGetIntegerv (GL_CURRENT_PROGRAM, (GLint *) &program); + + glUniform4i (glGetUniformLocation (program, "u_atlas_info"), + at->tex_w, at->tex_h, at->item_w, at->item_h_q); + glUniform1i (glGetUniformLocation (program, "u_atlas_tex"), at->tex_unit - GL_TEXTURE0); +} + +void +demo_atlas_alloc (demo_atlas_t *at, + glyphy_rgba_t *data, + unsigned int len, + unsigned int *px, + unsigned int *py) +{ + GLuint w, h, x, y; + + w = at->item_w; + h = (len + w - 1) / w; + + if (at->cursor_y + h > at->tex_h) { + /* Go to next column */ + at->cursor_x += at->item_w; + at->cursor_y = 0; + } + + if (at->cursor_x + w <= at->tex_w && + at->cursor_y + h <= at->tex_h) + { + x = at->cursor_x; + y = at->cursor_y; + at->cursor_y += (h + at->item_h_q - 1) & ~(at->item_h_q - 1); + } else + die ("Ran out of atlas memory"); + + demo_atlas_bind_texture (at); + if (w * h == len) + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data); + else { + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y, w, h - 1, GL_RGBA, GL_UNSIGNED_BYTE, data); + /* Upload the last row separately */ + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y + h - 1, len - (w * (h - 1)), 1, GL_RGBA, GL_UNSIGNED_BYTE, + data + w * (h - 1)); + } + + *px = x / at->item_w; + *py = y / at->item_h_q; +} diff --git a/vcl/glyphy/demo/demo-buffer.cc b/vcl/glyphy/demo/demo-buffer.cc new file mode 100644 index 000000000000..8ce5b34fcd78 --- /dev/null +++ b/vcl/glyphy/demo/demo-buffer.cc @@ -0,0 +1,191 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-buffer.h" + +struct demo_buffer_t { + unsigned int refcount; + + glyphy_point_t cursor; + std::vector<glyph_vertex_t> *vertices; + glyphy_extents_t ink_extents; + glyphy_extents_t logical_extents; + bool dirty; + GLuint buf_name; +}; + +demo_buffer_t * +demo_buffer_create (void) +{ + demo_buffer_t *buffer = (demo_buffer_t *) calloc (1, sizeof (demo_buffer_t)); + buffer->refcount = 1; + + buffer->vertices = new std::vector<glyph_vertex_t>; + glGenBuffers (1, &buffer->buf_name); + + demo_buffer_clear (buffer); + + return buffer; +} + +demo_buffer_t * +demo_buffer_reference (demo_buffer_t *buffer) +{ + if (buffer) buffer->refcount++; + return buffer; +} + +void +demo_buffer_destroy (demo_buffer_t *buffer) +{ + if (!buffer || --buffer->refcount) + return; + + glDeleteBuffers (1, &buffer->buf_name); + delete buffer->vertices; + free (buffer); +} + + +void +demo_buffer_clear (demo_buffer_t *buffer) +{ + buffer->vertices->clear (); + glyphy_extents_clear (&buffer->ink_extents); + glyphy_extents_clear (&buffer->logical_extents); + buffer->dirty = true; +} + +void +demo_buffer_extents (demo_buffer_t *buffer, + glyphy_extents_t *ink_extents, + glyphy_extents_t *logical_extents) +{ + if (ink_extents) + *ink_extents = buffer->ink_extents; + if (logical_extents) + *logical_extents = buffer->logical_extents; +} + +void +demo_buffer_move_to (demo_buffer_t *buffer, + const glyphy_point_t *p) +{ + buffer->cursor = *p; +} + +void +demo_buffer_current_point (demo_buffer_t *buffer, + glyphy_point_t *p) +{ + *p = buffer->cursor; +} + +void +demo_buffer_add_text (demo_buffer_t *buffer, + const char *utf8, + demo_font_t *font, + double font_size) +{ +#ifndef _WIN32 + FT_Face face = demo_font_get_face (font); +#else + HDC hdc = demo_font_get_face (font); +#endif + glyphy_point_t top_left = buffer->cursor; + buffer->cursor.y += font_size /* * font->ascent */; + unsigned int unicode; + for (const unsigned char *p = (const unsigned char *) utf8; *p; p++) { + if (*p < 128) { + unicode = *p; + } else { + unsigned int j; + if (*p < 0xE0) { + unicode = *p & ~0xE0; + j = 1; + } else if (*p < 0xF0) { + unicode = *p & ~0xF0; + j = 2; + } else { + unicode = *p & ~0xF8; + j = 3; + continue; + } + p++; + for (; j && *p; j--, p++) + unicode = (unicode << 6) | (*p & ~0xC0); + p--; + } + + if (unicode == '\n') { + buffer->cursor.y += font_size; + buffer->cursor.x = top_left.x; + continue; + } + +#ifndef _WIN32 + unsigned int glyph_index = FT_Get_Char_Index (face, unicode); +#else + wchar_t wc = unicode; /* FIXME: What about non-BMP chars? */ + WORD glyph_index; + if (GetGlyphIndicesW (hdc, &wc, 1, &glyph_index, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) + die ("GetGlyphIndicesW failed"); +#endif + glyph_info_t gi; + demo_font_lookup_glyph (font, glyph_index, &gi); + + /* Update ink extents */ + glyphy_extents_t ink_extents; + demo_shader_add_glyph_vertices (buffer->cursor, font_size, &gi, buffer->vertices, &ink_extents); + glyphy_extents_extend (&buffer->ink_extents, &ink_extents); + + /* Update logical extents */ + glyphy_point_t corner; + corner.x = buffer->cursor.x; + corner.y = buffer->cursor.y - font_size; + glyphy_extents_add (&buffer->logical_extents, &corner); + corner.x = buffer->cursor.x + font_size * gi.advance; + corner.y = buffer->cursor.y; + glyphy_extents_add (&buffer->logical_extents, &corner); + + buffer->cursor.x += font_size * gi.advance; + } + + buffer->dirty = true; +} + +void +demo_buffer_draw (demo_buffer_t *buffer) +{ + GLint program; + glGetIntegerv (GL_CURRENT_PROGRAM, &program); + GLuint a_glyph_vertex_loc = glGetAttribLocation (program, "a_glyph_vertex"); + glBindBuffer (GL_ARRAY_BUFFER, buffer->buf_name); + if (buffer->dirty) { + glBufferData (GL_ARRAY_BUFFER, sizeof (glyph_vertex_t) * buffer->vertices->size (), (const char *) &(*buffer->vertices)[0], GL_STATIC_DRAW); + buffer->dirty = false; + } + glEnableVertexAttribArray (a_glyph_vertex_loc); + glVertexAttribPointer (a_glyph_vertex_loc, 4, GL_FLOAT, GL_FALSE, sizeof (glyph_vertex_t), 0); + glDrawArrays (GL_TRIANGLES, 0, buffer->vertices->size ()); + glDisableVertexAttribArray (a_glyph_vertex_loc); +} diff --git a/vcl/glyphy/demo/demo-font.cc b/vcl/glyphy/demo/demo-font.cc new file mode 100644 index 000000000000..c28778e899c3 --- /dev/null +++ b/vcl/glyphy/demo/demo-font.cc @@ -0,0 +1,333 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-font.h" + +#ifndef _WIN32 +#include <glyphy-freetype.h> +#endif + +#ifdef _WIN32 +#include <glyphy-windows.h> +#endif + +#include <map> +#include <vector> + +typedef std::map<unsigned int, glyph_info_t> glyph_cache_t; + +struct demo_font_t { + unsigned int refcount; + +#ifndef _WIN32 + FT_Face face; +#endif + +#ifdef _WIN32 + HDC face; /* A memory DC that has the font instance selected into it */ +#endif + + glyph_cache_t *glyph_cache; + demo_atlas_t *atlas; + glyphy_arc_accumulator_t *acc; + + /* stats */ + unsigned int num_glyphs; + double sum_error; + unsigned int sum_endpoints; + double sum_fetch; + unsigned int sum_bytes; +}; + +demo_font_t * +demo_font_create ( +#ifndef _WIN32 + FT_Face face, +#endif +#ifdef _WIN32 + HDC face, +#endif + demo_atlas_t *atlas) +{ + demo_font_t *font = (demo_font_t *) calloc (1, sizeof (demo_font_t)); + font->refcount = 1; + + font->face = face; + font->glyph_cache = new glyph_cache_t (); + font->atlas = demo_atlas_reference (atlas); + font->acc = glyphy_arc_accumulator_create (); + + font->num_glyphs = 0; + font->sum_error = 0; + font->sum_endpoints = 0; + font->sum_fetch = 0; + font->sum_bytes = 0; + + return font; +} + +demo_font_t * +demo_font_reference (demo_font_t *font) +{ + if (font) font->refcount++; + return font; +} + +void +demo_font_destroy (demo_font_t *font) +{ + if (!font || --font->refcount) + return; + + glyphy_arc_accumulator_destroy (font->acc); + demo_atlas_destroy (font->atlas); + delete font->glyph_cache; + free (font); +} + + +#ifndef _WIN32 +FT_Face +#endif +#ifdef _WIN32 +HDC +#endif +demo_font_get_face (demo_font_t *font) +{ + return font->face; +} + +demo_atlas_t * +demo_font_get_atlas (demo_font_t *font) +{ + return font->atlas; +} + + +static glyphy_bool_t +accumulate_endpoint (glyphy_arc_endpoint_t *endpoint, + std::vector<glyphy_arc_endpoint_t> *endpoints) +{ + endpoints->push_back (*endpoint); + return true; +} + +static void +encode_glyph (demo_font_t *font, + unsigned int glyph_index, + double tolerance_per_em, + glyphy_rgba_t *buffer, + unsigned int buffer_len, + unsigned int *output_len, + unsigned int *nominal_width, + unsigned int *nominal_height, + glyphy_extents_t *extents, + double *advance) +{ +/* Used for testing only */ +#define SCALE (1. * (1 << 0)) + +#ifndef _WIN32 + FT_Face face = font->face; + if (FT_Err_Ok != FT_Load_Glyph (face, + glyph_index, + FT_LOAD_NO_BITMAP | + FT_LOAD_NO_HINTING | + FT_LOAD_NO_AUTOHINT | + FT_LOAD_NO_SCALE | + FT_LOAD_LINEAR_DESIGN | + FT_LOAD_IGNORE_TRANSFORM)) + die ("Failed loading FreeType glyph"); + + if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) + die ("FreeType loaded glyph format is not outline"); + + unsigned int upem = face->units_per_EM; + double tolerance = upem * tolerance_per_em; /* in font design units */ + double faraway = double (upem) / (MIN_FONT_SIZE * M_SQRT2); + std::vector<glyphy_arc_endpoint_t> endpoints; + + glyphy_arc_accumulator_reset (font->acc); + glyphy_arc_accumulator_set_tolerance (font->acc, tolerance); + glyphy_arc_accumulator_set_callback (font->acc, + (glyphy_arc_endpoint_accumulator_callback_t) accumulate_endpoint, + &endpoints); + + if (FT_Err_Ok != glyphy_freetype(outline_decompose) (&face->glyph->outline, font->acc)) + die ("Failed converting glyph outline to arcs"); +#endif + +#ifdef _WIN32 + HDC hdc = font->face; + + GLYPHMETRICS glyph_metrics; + MAT2 matrix; + + matrix.eM11.value = 1; + matrix.eM11.fract = 0; + matrix.eM12.value = 0; + matrix.eM12.fract = 0; + matrix.eM21.value = 0; + matrix.eM21.fract = 0; + matrix.eM22.value = 1; + matrix.eM22.fract = 0; + + DWORD size = GetGlyphOutlineW (hdc, glyph_index, GGO_NATIVE|GGO_GLYPH_INDEX, &glyph_metrics, 0, NULL, &matrix); + if (size == GDI_ERROR) + die ("GetGlyphOutlineW failed"); + std::vector<char> buf(size); + size = GetGlyphOutlineW (hdc, glyph_index, GGO_NATIVE|GGO_GLYPH_INDEX, &glyph_metrics, size, buf.data(), &matrix); + if (size == GDI_ERROR) + die ("GetGlyphOutlineW failed"); + + size = GetGlyphOutlineW (hdc, glyph_index, GGO_METRICS|GGO_GLYPH_INDEX, &glyph_metrics, 0, NULL, &matrix); + if (size == GDI_ERROR) + die ("GetGlyphOutlineW failed"); + + OUTLINETEXTMETRICW outline_text_metric; + if (!GetOutlineTextMetricsW (hdc, sizeof (OUTLINETEXTMETRICW), &outline_text_metric)) + die ("GetOutlineTextMetricsW failed"); + + unsigned int upem = outline_text_metric.otmEMSquare; + double tolerance = upem * tolerance_per_em; /* in font design units */ + double faraway = double (upem) / (MIN_FONT_SIZE * M_SQRT2); + std::vector<glyphy_arc_endpoint_t> endpoints; + + glyphy_arc_accumulator_reset (font->acc); + glyphy_arc_accumulator_set_tolerance (font->acc, tolerance); + glyphy_arc_accumulator_set_callback (font->acc, + (glyphy_arc_endpoint_accumulator_callback_t) accumulate_endpoint, + &endpoints); + + if (0 != glyphy_windows(outline_decompose) ((TTPOLYGONHEADER *) buf.data(), buf.size(), font->acc)) + die ("Failed converting glyph outline to arcs"); +#endif + + assert (glyphy_arc_accumulator_get_error (font->acc) <= tolerance); + + if (endpoints.size ()) + { +#if 0 + /* Technically speaking, we want the following code, + * however, crappy fonts have crappy flags. So we just + * fixup unconditionally... */ + if (face->glyph->outline.flags & FT_OUTLINE_EVEN_ODD_FILL) + glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false); + else if (face->glyph->outline.flags & FT_OUTLINE_REVERSE_FILL) + glyphy_outline_reverse (&endpoints[0], endpoints.size ()); +#else + glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false); +#endif + } + + if (SCALE != 1.) + for (unsigned int i = 0; i < endpoints.size (); i++) + { + endpoints[i].p.x /= SCALE; + endpoints[i].p.y /= SCALE; + } + + double avg_fetch_achieved; + if (!glyphy_arc_list_encode_blob (endpoints.size () ? &endpoints[0] : NULL, endpoints.size (), + buffer, + buffer_len, + faraway / SCALE, + 4, /* UNUSED */ + &avg_fetch_achieved, + output_len, + nominal_width, + nominal_height, + extents)) + die ("Failed encoding arcs"); + + glyphy_extents_scale (extents, 1. / upem, 1. / upem); + glyphy_extents_scale (extents, SCALE, SCALE); + +#ifndef _WIN32 + *advance = face->glyph->metrics.horiAdvance / (double) upem; +#endif + +#ifdef _WIN32 + *advance = glyph_metrics.gmCellIncX / (double) upem; /* ??? */ +#endif + + if (0) + LOGI ("gid%3u: endpoints%3d; err%3g%%; tex fetch%4.1f; mem%4.1fkb\n", + glyph_index, + (unsigned int) glyphy_arc_accumulator_get_num_endpoints (font->acc), + round (100 * glyphy_arc_accumulator_get_error (font->acc) / tolerance), + avg_fetch_achieved, + (*output_len * sizeof (glyphy_rgba_t)) / 1024.); + + font->num_glyphs++; + font->sum_error += glyphy_arc_accumulator_get_error (font->acc) / tolerance; + font->sum_endpoints += glyphy_arc_accumulator_get_num_endpoints (font->acc); + font->sum_fetch += avg_fetch_achieved; + font->sum_bytes += (*output_len * sizeof (glyphy_rgba_t)); +} + +static void +_demo_font_upload_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info) +{ + glyphy_rgba_t buffer[4096 * 16]; + unsigned int output_len; + + encode_glyph (font, + glyph_index, + TOLERANCE, + buffer, ARRAY_LEN (buffer), + &output_len, + &glyph_info->nominal_w, + &glyph_info->nominal_h, + &glyph_info->extents, + &glyph_info->advance); + + glyph_info->is_empty = glyphy_extents_is_empty (&glyph_info->extents); + if (!glyph_info->is_empty) + demo_atlas_alloc (font->atlas, buffer, output_len, + &glyph_info->atlas_x, &glyph_info->atlas_y); +} + +void +demo_font_lookup_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info) +{ + if (font->glyph_cache->find (glyph_index) == font->glyph_cache->end ()) { + _demo_font_upload_glyph (font, glyph_index, glyph_info); + (*font->glyph_cache)[glyph_index] = *glyph_info; + } else + *glyph_info = (*font->glyph_cache)[glyph_index]; +} + +void +demo_font_print_stats (demo_font_t *font) +{ + LOGI ("%3d glyphs; avg num endpoints%6.2f; avg error%5.1f%%; avg tex fetch%5.2f; avg %5.2fkb per glyph\n", + font->num_glyphs, + (double) font->sum_endpoints / font->num_glyphs, + 100. * font->sum_error / font->num_glyphs, + font->sum_fetch / font->num_glyphs, + font->sum_bytes / 1024. / font->num_glyphs); +} diff --git a/vcl/glyphy/demo/demo-shader.cc b/vcl/glyphy/demo/demo-shader.cc new file mode 100644 index 000000000000..9b8212333175 --- /dev/null +++ b/vcl/glyphy/demo/demo-shader.cc @@ -0,0 +1,212 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-shader.h" + +#include "demo-atlas-glsl.h" +#include "demo-vshader-glsl.h" +#include "demo-fshader-glsl.h" + + +static unsigned int +glyph_encode (unsigned int atlas_x , /* 7 bits */ + unsigned int atlas_y, /* 7 bits */ + unsigned int corner_x, /* 1 bit */ + unsigned int corner_y, /* 1 bit */ + unsigned int nominal_w, /* 6 bits */ + unsigned int nominal_h /* 6 bits */) +{ + assert (0 == (atlas_x & ~0x7F)); + assert (0 == (atlas_y & ~0x7F)); + assert (0 == (corner_x & ~1)); + assert (0 == (corner_y & ~1)); + assert (0 == (nominal_w & ~0x3F)); + assert (0 == (nominal_h & ~0x3F)); + + unsigned int x = (((atlas_x << 6) | nominal_w) << 1) | corner_x; + unsigned int y = (((atlas_y << 6) | nominal_h) << 1) | corner_y; + + return (x << 16) | y; +} + +static void +glyph_vertex_encode (double x, double y, + unsigned int corner_x, unsigned int corner_y, + const glyph_info_t *gi, + glyph_vertex_t *v) +{ + unsigned int encoded = glyph_encode (gi->atlas_x, gi->atlas_y, + corner_x, corner_y, + gi->nominal_w, gi->nominal_h); + v->x = x; + v->y = y; + v->g16hi = encoded >> 16; + v->g16lo = encoded & 0xFFFF; +} + +void +demo_shader_add_glyph_vertices (const glyphy_point_t &p, + double font_size, + glyph_info_t *gi, + std::vector<glyph_vertex_t> *vertices, + glyphy_extents_t *extents) +{ + if (gi->is_empty) + return; + + glyph_vertex_t v[4]; + +#define ENCODE_CORNER(_cx, _cy) \ + do { \ + double _vx = p.x + font_size * ((1-_cx) * gi->extents.min_x + _cx * gi->extents.max_x); \ + double _vy = p.y - font_size * ((1-_cy) * gi->extents.min_y + _cy * gi->extents.max_y); \ + glyph_vertex_encode (_vx, _vy, _cx, _cy, gi, &v[_cx * 2 + _cy]); \ + } while (0) + ENCODE_CORNER (0, 0); + ENCODE_CORNER (0, 1); + ENCODE_CORNER (1, 0); + ENCODE_CORNER (1, 1); +#undef ENCODE_CORNER + + vertices->push_back (v[0]); + vertices->push_back (v[1]); + vertices->push_back (v[2]); + + vertices->push_back (v[1]); + vertices->push_back (v[2]); + vertices->push_back (v[3]); + + if (extents) { + glyphy_extents_clear (extents); + for (unsigned int i = 0; i < 4; i++) { + glyphy_point_t p = {v[i].x, v[i].y}; + glyphy_extents_add (extents, &p); + } + } +} + + + + +static GLuint +compile_shader (GLenum type, + GLsizei count, + const GLchar** sources) +{ + TRACE(); + + GLuint shader; + GLint compiled; + + if (!(shader = glCreateShader (type))) + return shader; + + glShaderSource (shader, count, sources, 0); + glCompileShader (shader); + + glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint info_len = 0; + LOGW ("%s shader failed to compile\n", + type == GL_VERTEX_SHADER ? "Vertex" : "Fragment"); + glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &info_len); + + if (info_len > 0) { + char *info_log = (char*) malloc (info_len); + glGetShaderInfoLog (shader, info_len, NULL, info_log); + + LOGW ("%s\n", info_log); + free (info_log); + } + + abort (); + } + + return shader; +} + +static GLuint +link_program (GLuint vshader, + GLuint fshader) +{ + TRACE(); + + GLuint program; + GLint linked; + + program = glCreateProgram (); + glAttachShader (program, vshader); + glAttachShader (program, fshader); + glLinkProgram (program); + glDeleteShader (vshader); + glDeleteShader (fshader); + + glGetProgramiv (program, GL_LINK_STATUS, &linked); + if (!linked) { + GLint info_len = 0; + LOGW ("Program failed to link\n"); + glGetProgramiv (program, GL_INFO_LOG_LENGTH, &info_len); + + if (info_len > 0) { + char *info_log = (char*) malloc (info_len); + glGetProgramInfoLog (program, info_len, NULL, info_log); + + LOGW ("%s\n", info_log); + free (info_log); + } + + abort (); + } + + return program; +} + +#ifdef GL_ES_VERSION_2_0 +# define GLSL_HEADER_STRING \ + "#extension GL_OES_standard_derivatives : enable\n" \ + "precision highp float;\n" \ + "precision highp int;\n" +#else +# define GLSL_HEADER_STRING \ + "#version 110\n" +#endif + +GLuint +demo_shader_create_program (void) +{ + TRACE(); + + GLuint vshader, fshader, program; + const GLchar *vshader_sources[] = {GLSL_HEADER_STRING, + demo_vshader_glsl}; + vshader = compile_shader (GL_VERTEX_SHADER, ARRAY_LEN (vshader_sources), vshader_sources); + const GLchar *fshader_sources[] = {GLSL_HEADER_STRING, + demo_atlas_glsl, + glyphy_common_shader_source (), + "#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n", + glyphy_sdf_shader_source (), + demo_fshader_glsl}; + fshader = compile_shader (GL_FRAGMENT_SHADER, ARRAY_LEN (fshader_sources), fshader_sources); + + program = link_program (vshader, fshader); + return program; +} diff --git a/vcl/glyphy/demo/matrix4x4.c b/vcl/glyphy/demo/matrix4x4.c new file mode 100644 index 000000000000..f103589e6593 --- /dev/null +++ b/vcl/glyphy/demo/matrix4x4.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2009, Mozilla Corp + * Copyright (c) 2012, Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers + * the following header: + * + * Book: OpenGL(R) ES 2.0 Programming Guide + * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner + * ISBN-10: 0321502795 + * ISBN-13: 9780321502797 + * Publisher: Addison-Wesley Professional + * URLs: http://safari.informit.com/9780321563835 + * http://www.opengles-book.com + */ + +/* + * Ported from JavaScript to C by Behdad Esfahbod, 2012. + * Added MultMatrix. Converting from fixed-function OpenGL matrix + * operations to these functions should be as simple as renaming the + * 'gl' prefix to 'm4' and adding the matrix argument to the call. + * + * The C version lives at http://code.google.com/p/matrix4x4-c/ + */ + +#include "matrix4x4.h" +#include <math.h> + +/* + * A simple 4x4 matrix utility implementation + */ + + +float * +m4LoadIdentity (float *mat) { + unsigned int i; + for (i = 0; i < 16; i++) + mat[i] = 0; + mat[0*4+0] = 1.0; + mat[1*4+1] = 1.0; + mat[2*4+2] = 1.0; + mat[3*4+3] = 1.0; + return mat; +} + +/* Copies other matrix into mat */ +float * +m4Copy (float *mat, const float *other) { + unsigned int i; + for (i = 0; i < 16; i++) { + mat[i] = other[i]; + } + return mat; +} + +float * +m4Multiply (float *mat, const float *right) { + float tmp[16]; + unsigned int i; + + for (i = 0; i < 4; i++) { + tmp[i*4+0] = + (mat[i*4+0] * right[0*4+0]) + + (mat[i*4+1] * right[1*4+0]) + + (mat[i*4+2] * right[2*4+0]) + + (mat[i*4+3] * right[3*4+0]) ; + + tmp[i*4+1] = + (mat[i*4+0] * right[0*4+1]) + + (mat[i*4+1] * right[1*4+1]) + + (mat[i*4+2] * right[2*4+1]) + + (mat[i*4+3] * right[3*4+1]) ; + + tmp[i*4+2] = + (mat[i*4+0] * right[0*4+2]) + + (mat[i*4+1] * right[1*4+2]) + + (mat[i*4+2] * right[2*4+2]) + + (mat[i*4+3] * right[3*4+2]) ; + + tmp[i*4+3] = + (mat[i*4+0] * right[0*4+3]) + + (mat[i*4+1] * right[1*4+3]) + + (mat[i*4+2] * right[2*4+3]) + + (mat[i*4+3] * right[3*4+3]) ; + } + + return m4Copy (mat, tmp); +} + +float +m4Get (float *mat, unsigned int row, unsigned int col) { + return mat[4*row+col]; +} + +float * +m4MultMatrix (float *mat, const float *left) { + float tmp[16]; + return m4Copy (mat, m4Multiply (m4Copy (tmp, left), mat)); +} + +float * +m4Scale (float *mat, float sx, float sy, float sz) { + mat[0*4+0] *= sx; + mat[0*4+1] *= sx; + mat[0*4+2] *= sx; + mat[0*4+3] *= sx; + + mat[1*4+0] *= sy; + mat[1*4+1] *= sy; + mat[1*4+2] *= sy; + mat[1*4+3] *= sy; + + mat[2*4+0] *= sz; + mat[2*4+1] *= sz; + mat[2*4+2] *= sz; + mat[2*4+3] *= sz; + + return mat; +} + +float * +m4Translate (float *mat, float tx, float ty, float tz) { + mat[3*4+0] += mat[0*4+0] * tx + mat[1*4+0] * ty + mat[2*4+0] * tz; + mat[3*4+1] += mat[0*4+1] * tx + mat[1*4+1] * ty + mat[2*4+1] * tz; + mat[3*4+2] += mat[0*4+2] * tx + mat[1*4+2] * ty + mat[2*4+2] * tz; + mat[3*4+3] += mat[0*4+3] * tx + mat[1*4+3] * ty + mat[2*4+3] * tz; + + return mat; +} + +float * +m4Rotate (float *mat, float angle, float x, float y, float z) { + float mag = sqrt(x*x + y*y + z*z); + float sinAngle = sin(angle * M_PI / 180.0); + float cosAngle = cos(angle * M_PI / 180.0); + + float xx, yy, zz, xy, yz, zx, xs, ys, zs; + float oneMinusCos; + + float rotMat[16]; + + if (mag <= 0) + return mat; + + m4LoadIdentity (rotMat); + + x /= mag; + y /= mag; + z /= mag; + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * sinAngle; + ys = y * sinAngle; + zs = z * sinAngle; + oneMinusCos = 1.0 - cosAngle; + + rotMat[0*4+0] = (oneMinusCos * xx) + cosAngle; + rotMat[0*4+1] = (oneMinusCos * xy) - zs; + rotMat[0*4+2] = (oneMinusCos * zx) + ys; + rotMat[0*4+3] = 0.0; + + rotMat[1*4+0] = (oneMinusCos * xy) + zs; + rotMat[1*4+1] = (oneMinusCos * yy) + cosAngle; + rotMat[1*4+2] = (oneMinusCos * yz) - xs; + rotMat[1*4+3] = 0.0; + + rotMat[2*4+0] = (oneMinusCos * zx) - ys; + rotMat[2*4+1] = (oneMinusCos * yz) + xs; + rotMat[2*4+2] = (oneMinusCos * zz) + cosAngle; + rotMat[2*4+3] = 0.0; + + rotMat[3*4+0] = 0.0; + rotMat[3*4+1] = 0.0; + rotMat[3*4+2] = 0.0; + rotMat[3*4+3] = 1.0; + + return m4Copy (mat, m4Multiply (rotMat, mat)); +} + +float * +m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) { + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + + float frust[16]; + + if ( (nearZ <= 0.0) || (farZ <= 0.0) || + (deltaX <= 0.0) || (deltaY <= 0.0) || (deltaZ <= 0.0) ) + return mat; + + m4LoadIdentity (frust); + + frust[0*4+0] = 2.0 * nearZ / deltaX; + frust[0*4+1] = frust[0*4+2] = frust[0*4+3] = 0.0; + + frust[1*4+1] = 2.0 * nearZ / deltaY; + frust[1*4+0] = frust[1*4+2] = frust[1*4+3] = 0.0; + + frust[2*4+0] = (right + left) / deltaX; + frust[2*4+1] = (top + bottom) / deltaY; + frust[2*4+2] = -(nearZ + farZ) / deltaZ; + frust[2*4+3] = -1.0; + + frust[3*4+2] = -2.0 * nearZ * farZ / deltaZ; + frust[3*4+0] = frust[3*4+1] = frust[3*4+3] = 0.0; + + return m4Copy (mat, m4Multiply (frust, mat)); +} + +float * +m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ) { + float frustumH = tan(fovy / 360.0 * M_PI) * nearZ; + float frustumW = frustumH * aspect; + + return m4Frustum(mat, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ); +} + +float * +m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) { + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + + float ortho[16]; + + if ( (deltaX == 0.0) || (deltaY == 0.0) || (deltaZ == 0.0) ) + return mat; + + m4LoadIdentity (ortho); + + ortho[0*4+0] = 2.0 / deltaX; + ortho[3*4+0] = -(right + left) / deltaX; + ortho[1*4+1] = 2.0 / deltaY; + ortho[3*4+1] = -(top + bottom) / deltaY; + ortho[2*4+2] = -2.0 / deltaZ; + ortho[3*4+2] = -(nearZ + farZ) / deltaZ; + + return m4Copy (mat, m4Multiply (ortho, mat)); +} + +/* In-place inversion */ +float * +m4Invert (float *mat) { + float tmp_0 = m4Get(mat,2,2) * m4Get(mat,3,3); + float tmp_1 = m4Get(mat,3,2) * m4Get(mat,2,3); + float tmp_2 = m4Get(mat,1,2) * m4Get(mat,3,3); + float tmp_3 = m4Get(mat,3,2) * m4Get(mat,1,3); + float tmp_4 = m4Get(mat,1,2) * m4Get(mat,2,3); + float tmp_5 = m4Get(mat,2,2) * m4Get(mat,1,3); + float tmp_6 = m4Get(mat,0,2) * m4Get(mat,3,3); + float tmp_7 = m4Get(mat,3,2) * m4Get(mat,0,3); + float tmp_8 = m4Get(mat,0,2) * m4Get(mat,2,3); + float tmp_9 = m4Get(mat,2,2) * m4Get(mat,0,3); + float tmp_10 = m4Get(mat,0,2) * m4Get(mat,1,3); + float tmp_11 = m4Get(mat,1,2) * m4Get(mat,0,3); + float tmp_12 = m4Get(mat,2,0) * m4Get(mat,3,1); + float tmp_13 = m4Get(mat,3,0) * m4Get(mat,2,1); + float tmp_14 = m4Get(mat,1,0) * m4Get(mat,3,1); + float tmp_15 = m4Get(mat,3,0) * m4Get(mat,1,1); + float tmp_16 = m4Get(mat,1,0) * m4Get(mat,2,1); + float tmp_17 = m4Get(mat,2,0) * m4Get(mat,1,1); + float tmp_18 = m4Get(mat,0,0) * m4Get(mat,3,1); + float tmp_19 = m4Get(mat,3,0) * m4Get(mat,0,1); + float tmp_20 = m4Get(mat,0,0) * m4Get(mat,2,1); + float tmp_21 = m4Get(mat,2,0) * m4Get(mat,0,1); + float tmp_22 = m4Get(mat,0,0) * m4Get(mat,1,1); + float tmp_23 = m4Get(mat,1,0) * m4Get(mat,0,1); + + float t0 = ((tmp_0 * m4Get(mat,1,1) + tmp_3 * m4Get(mat,2,1) + tmp_4 * m4Get(mat,3,1)) - + (tmp_1 * m4Get(mat,1,1) + tmp_2 * m4Get(mat,2,1) + tmp_5 * m4Get(mat,3,1))); + float t1 = ((tmp_1 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,2,1) + tmp_9 * m4Get(mat,3,1)) - + (tmp_0 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,2,1) + tmp_8 * m4Get(mat,3,1))); + float t2 = ((tmp_2 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,3,1)) - + (tmp_3 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,3,1))); + float t3 = ((tmp_5 * m4Get(mat,0,1) + tmp_8 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,2,1)) - + (tmp_4 * m4Get(mat,0,1) + tmp_9 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,2,1))); + + float d = 1.0 / (m4Get(mat,0,0) * t0 + m4Get(mat,1,0) * t1 + m4Get(mat,2,0) * t2 + m4Get(mat,3,0) * t3); + + float out_00 = d * t0; + float out_01 = d * t1; + float out_02 = d * t2; + float out_03 = d * t3; + + float out_10 = d * ((tmp_1 * m4Get(mat,1,0) + tmp_2 * m4Get(mat,2,0) + tmp_5 * m4Get(mat,3,0)) - + (tmp_0 * m4Get(mat,1,0) + tmp_3 * m4Get(mat,2,0) + tmp_4 * m4Get(mat,3,0))); + float out_11 = d * ((tmp_0 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,2,0) + tmp_8 * m4Get(mat,3,0)) - + (tmp_1 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,2,0) + tmp_9 * m4Get(mat,3,0))); + float out_12 = d * ((tmp_3 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,3,0)) - + (tmp_2 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,3,0))); + float out_13 = d * ((tmp_4 * m4Get(mat,0,0) + tmp_9 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,2,0)) - + (tmp_5 * m4Get(mat,0,0) + tmp_8 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,2,0))); + + float out_20 = d * ((tmp_12 * m4Get(mat,1,3) + tmp_15 * m4Get(mat,2,3) + tmp_16 * m4Get(mat,3,3)) - + (tmp_13 * m4Get(mat,1,3) + tmp_14 * m4Get(mat,2,3) + tmp_17 * m4Get(mat,3,3))); + float out_21 = d * ((tmp_13 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,2,3) + tmp_21 * m4Get(mat,3,3)) - + (tmp_12 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,2,3) + tmp_20 * m4Get(mat,3,3))); + float out_22 = d * ((tmp_14 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,3,3)) - + (tmp_15 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,3,3))); + float out_23 = d * ((tmp_17 * m4Get(mat,0,3) + tmp_20 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,2,3)) - + (tmp_16 * m4Get(mat,0,3) + tmp_21 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,2,3))); + + float out_30 = d * ((tmp_14 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,1,2)) - + (tmp_16 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,1,2) + tmp_15 * m4Get(mat,2,2))); + float out_31 = d * ((tmp_20 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,2,2)) - + (tmp_18 * m4Get(mat,2,2) + tmp_21 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,0,2))); + float out_32 = d * ((tmp_18 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,3,2) + tmp_15 * m4Get(mat,0,2)) - + (tmp_22 * m4Get(mat,3,2) + tmp_14 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,1,2))); + float out_33 = d * ((tmp_22 * m4Get(mat,2,2) + tmp_16 * m4Get(mat,0,2) + tmp_21 * m4Get(mat,1,2)) - + (tmp_20 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,0,2))); + + mat[0*4+0] = out_00; + mat[0*4+1] = out_01; + mat[0*4+2] = out_02; + mat[0*4+3] = out_03; + mat[1*4+0] = out_10; + mat[1*4+1] = out_11; + mat[1*4+2] = out_12; + mat[1*4+3] = out_13; + mat[2*4+0] = out_20; + mat[2*4+1] = out_21; + mat[2*4+2] = out_22; + mat[2*4+3] = out_23; + mat[3*4+0] = out_30; + mat[3*4+1] = out_31; + mat[3*4+2] = out_32; + mat[3*4+3] = out_33; + return mat; +} + +/* Puts the inverse of other matrix into mat */ +float * +m4Inverse (float *mat, const float *other) { + m4Copy (mat, other); + m4Invert (mat); + return mat; +} + +/* In-place transpose */ +float * +m4Transpose (float *mat) { + float tmp = mat[0*4+1]; + mat[0*4+1] = mat[1*4+0]; + mat[1*4+0] = tmp; + + tmp = mat[0*4+2]; + mat[0*4+2] = mat[2*4+0]; + mat[2*4+0] = tmp; + + tmp = mat[0*4+3]; + mat[0*4+3] = mat[3*4+0]; + mat[3*4+0] = tmp; + + tmp = mat[1*4+2]; + mat[1*4+2] = mat[2*4+1]; + mat[2*4+1] = tmp; + + tmp = mat[1*4+3]; + mat[1*4+3] = mat[3*4+1]; + mat[3*4+1] = tmp; + + tmp = mat[2*4+3]; + mat[2*4+3] = mat[3*4+2]; + mat[3*4+2] = tmp; + + return mat; +} + +float * +m4ApplyToVect (float *mat, float *vec) +{ + float tmp[4] = {vec[0], vec[1], vec[2], vec[3]}; + + vec[0] = mat[0]*tmp[0] + mat[4]*tmp[1] + mat[8]*tmp[2] + mat[12]*tmp[3]; + vec[1] = mat[1]*tmp[0] + mat[5]*tmp[1] + mat[9]*tmp[2] + mat[13]*tmp[3]; + vec[2] = mat[2]*tmp[0] + mat[6]*tmp[1] + mat[10]*tmp[2] + mat[14]*tmp[3]; + vec[3] = mat[3]*tmp[0] + mat[7]*tmp[1] + mat[11]*tmp[2] + mat[15]*tmp[3]; + + return vec; +} + +#ifdef TEST + +#include <stdio.h> + +static void setvec (float *vec, float x, float y, float z, float w) +{ + vec[0] = x; + vec[1] = y; + vec[2] = z; + vec[3] = w; +} + +static void printmat (float *mat) +{ + printf("(%f,%f,%f,%f,\n", mat[0], mat[1], mat[2], mat[3]); + printf(" %f,%f,%f,%f,\n", mat[4], mat[5], mat[6], mat[7]); + printf(" %f,%f,%f,%f,\n", mat[8], mat[9], mat[10], mat[11]); + printf(" %f,%f,%f,%f)\n", mat[12], mat[13], mat[14], mat[15]); +} + +static void printvec (float *vec) +{ + printf("(%f,%f,%f,%f)\n", vec[0], vec[1], vec[2], vec[3]); +} + +int main(int argc, char **argv) +{ + float mat[16]; + float vec[4]; + + setvec (vec, 1, 2, 3, 1); + printf ("vec:\n"); + printvec (vec); + + m4LoadIdentity (mat); + printf ("Identity matrix:\n"); + printmat (mat); + + m4Scale (mat, 2, 2, 2); + printf ("Scale by 2:\n"); + printmat (mat); + + m4LoadIdentity (mat); + m4Translate (mat, 2, 3, 0); + printf ("Translate by (2,3,0):\n"); + printmat (mat); + + printf ("Apply that to vec:\n"); + m4ApplyToVect (mat, vec); + printvec (vec); + + m4LoadIdentity (mat); + m4Scale (mat, 2, 2, 2); + m4ApplyToVect (mat, vec); + printf ("Scale then by 2:\n"); + printvec (vec); + + setvec (vec, 1, 2, 3, 1); + m4LoadIdentity (mat); + m4Scale (mat, 2, 2, 2); + m4Translate (mat, 2, 3, 0); + m4ApplyToVect (mat, vec); + printf ("Both in one step:\n"); + printvec (vec); + + return 0; +} + +#endif diff --git a/vcl/inc/glyphy/demo.hxx b/vcl/inc/glyphy/demo.hxx new file mode 100644 index 000000000000..2323186764cf --- /dev/null +++ b/vcl/inc/glyphy/demo.hxx @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_GLYPHY_DEMO_HXX +#define INCLUDED_VCL_INC_GLYPHY_DEMO_HXX + +namespace GLyphyDemo { +#include "demo-atlas.h" +#include "demo-buffer.h" +#include "demo-font.h" +#include "demo-shader.h" +#include "matrix4x4.h" +} + +#endif // INCLUDED_VCL_INC_GLYPHY_DEMO_HXX diff --git a/vcl/inc/glyphy/demo/demo-atlas-glsl.h b/vcl/inc/glyphy/demo/demo-atlas-glsl.h new file mode 100644 index 000000000000..9b93c2ab129f --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-atlas-glsl.h @@ -0,0 +1,18 @@ +static const char *demo_atlas_glsl = +"uniform sampler2D u_atlas_tex;\n" +"uniform ivec4 u_atlas_info;\n" +"\n" +"#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos\n" +"#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos\n" +"#define GLYPHY_DEMO_EXTRA_ARGS , u_atlas_tex, u_atlas_info, gi.atlas_pos\n" +"\n" +"vec4\n" +"glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)\n" +"{\n" +" ivec2 item_geom = _atlas_info.zw;\n" +" vec2 pos = (vec2 (_atlas_pos.xy * item_geom +\n" +" ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +\n" +" + vec2 (.5, .5)) / vec2(_atlas_info.xy);\n" +" return texture2D (_tex, pos);\n" +"}\n" +; diff --git a/vcl/inc/glyphy/demo/demo-atlas.h b/vcl/inc/glyphy/demo/demo-atlas.h new file mode 100644 index 000000000000..729403f472fa --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-atlas.h @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju + */ + +#ifndef DEMO_ATLAS_H +#define DEMO_ATLAS_H + +#include "demo-common.h" + + +typedef struct demo_atlas_t demo_atlas_t; + +demo_atlas_t * +demo_atlas_create (unsigned int w, + unsigned int h, + unsigned int item_w, + unsigned int item_h_quantum); + +demo_atlas_t * +demo_atlas_reference (demo_atlas_t *at); + +void +demo_atlas_destroy (demo_atlas_t *at); + + +void +demo_atlas_alloc (demo_atlas_t *at, + glyphy_rgba_t *data, + unsigned int len, + unsigned int *px, + unsigned int *py); + +void +demo_atlas_bind_texture (demo_atlas_t *at); + +void +demo_atlas_set_uniforms (demo_atlas_t *at); + + +#endif /* DEMO_ATLAS_H */ diff --git a/vcl/inc/glyphy/demo/demo-buffer.h b/vcl/inc/glyphy/demo/demo-buffer.h new file mode 100644 index 000000000000..2948a7ff0a04 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-buffer.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_BUFFER_H +#define DEMO_BUFFER_H + +#include "demo-common.h" +#include "demo-font.h" +#include "demo-shader.h" + +typedef struct demo_buffer_t demo_buffer_t; + +demo_buffer_t * +demo_buffer_create (void); + +demo_buffer_t * +demo_buffer_reference (demo_buffer_t *buffer); + +void +demo_buffer_destroy (demo_buffer_t *buffer); + + +void +demo_buffer_clear (demo_buffer_t *buffer); + +void +demo_buffer_extents (demo_buffer_t *buffer, + glyphy_extents_t *ink_extents, + glyphy_extents_t *logical_extents); + +void +demo_buffer_move_to (demo_buffer_t *buffer, + const glyphy_point_t *p); + +void +demo_buffer_current_point (demo_buffer_t *buffer, + glyphy_point_t *p); + +void +demo_buffer_add_text (demo_buffer_t *buffer, + const char *utf8, + demo_font_t *font, + double font_size); + +void +demo_buffer_draw (demo_buffer_t *buffer); + + +#endif /* DEMO_BUFFER_H */ diff --git a/vcl/inc/glyphy/demo/demo-common.h b/vcl/inc/glyphy/demo/demo-common.h new file mode 100644 index 000000000000..380942f82297 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-common.h @@ -0,0 +1,186 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju + */ + +#ifndef DEMO_COMMON_H +#define DEMO_COMMON_H + +#include <glyphy.h> + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> + +#include <algorithm> +#include <vector> + +/* Tailor config for various platforms. */ + +#ifdef EMSCRIPTEN +/* https://github.com/kripken/emscripten/issues/340 */ +# undef HAVE_GLEW + /* WebGL shaders are ES2 */ +# define GL_ES_VERSION_2_0 1 +#endif + +#if defined(__ANDROID__) +# define HAVE_GLES2 1 +# define HAVE_GLUT 1 +#endif + +#ifdef _WIN32 +# define HAVE_GL 1 +# define HAVE_GLEW 1 +#endif + +/* Get Glew out of the way. */ +#ifdef HAVE_GLEW +# include <GL/glew.h> +#else +# define GLEW_OK 0 + static inline int glewInit (void) { return GLEW_OK; } + static inline int glewIsSupported (const char *s) + { return 0 == strcmp ("GL_VERSION_2_0", s); } +#endif /* HAVE_GLEW */ + +/* WTF this block?! */ +#if defined(HAVE_GLES2) +# include <GLES2/gl2.h> +#elif defined(HAVE_GL) +# ifndef HAVE_GLEW +# define GL_GLEXT_PROTOTYPES 1 +# if defined(__APPLE__) +# include <OpenGL/gl.h> +# else +# include <GL/gl.h> +# endif +# endif +# if defined(__APPLE__) +# include <OpenGL/OpenGL.h> +# else +# ifdef HAVE_GLEW +# ifdef _WIN32 +# include <GL/wglew.h> +# else +# include <GL/glxew.h> +# endif +# endif +# endif +#endif /* HAVE_GL */ + +/* Finally, Glut. */ +#ifdef HAVE_GLUT +# if defined(__APPLE__) +# include <GLUT/glut.h> +# else +# include <GL/glut.h> +# endif +#endif + + + + +/* Logging. */ +#ifdef __ANDROID__ +# include <android/log.h> +# define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "glyphy-demo", __VA_ARGS__)) +# define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "glyphy-demo", __VA_ARGS__)) +# define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "glyphy-demo", __VA_ARGS__)) +#else /* !__ANDROID__ */ +#if 0 +# define LOGI(...) ((void) fprintf (stderr, __VA_ARGS__)) +# define LOGW(...) ((void) fprintf (stderr, __VA_ARGS__)) +# define LOGE(...) ((void) fprintf (stderr, __VA_ARGS__), abort ()) +#else +# define LOGI(...) do { } while(false) +# define LOGW(...) do { } while(false) +# define LOGE(...) do { } while(false) +#endif +#endif + + + +#define STRINGIZE1(Src) #Src +#define STRINGIZE(Src) STRINGIZE1(Src) + +#define ARRAY_LEN(Array) (sizeof (Array) / sizeof (*Array)) + + +#define MIN_FONT_SIZE 10 +#define TOLERANCE (1./2048) + + +#define gl(name) \ + for (GLint __ee, __ii = 0; \ + __ii < 1; \ + (__ii++, \ + (__ee = glGetError()) && \ + (reportGLerror (__ee, #name, __LINE__, __FILE__), 0))) \ + gl##name + + +static inline void +reportGLerror(GLint e, const char *api, int line, const char *file) +{ + fflush(stdout); + fprintf(stderr, "\nwglGetCurrentDC=%p wglGetCurrentContext=%p\n", wglGetCurrentDC(), wglGetCurrentContext()); + fprintf (stderr, "gl%s failed with error %04X on %s:%d\n", api, e, file, line); + fflush (stderr); + exit (1); +} + +static inline void +die (const char *msg) +{ + fprintf (stderr, "%s\n", msg); + exit (1); +} + +template <typename T> +T clamp (T v, T m, T M) +{ + return v < m ? m : v > M ? M : v; +} + + +#if defined(_MSC_VER) +#define DEMO_FUNC __FUNCSIG__ +#else +#define DEMO_FUNC __func__ +#endif + +struct auto_trace_t +{ + auto_trace_t (const char *func_) : func (func_) + { printf ("Enter: %s\n", func); } + + ~auto_trace_t (void) + { printf ("Leave: %s\n", func); } + + private: + const char * const func; +}; + +#if 0 +#define TRACE() auto_trace_t trace(DEMO_FUNC) +#else +#define TRACE() do { } while(false) +#endif + +#endif /* DEMO_COMMON_H */ diff --git a/vcl/inc/glyphy/demo/demo-font.h b/vcl/inc/glyphy/demo/demo-font.h new file mode 100644 index 000000000000..d4e75ff3f2d6 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-font.h @@ -0,0 +1,88 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_FONT_H +#define DEMO_FONT_H + +#include "demo-common.h" +#include "demo-atlas.h" + +#ifndef _WIN32 +#include <ft2build.h> +#include FT_FREETYPE_H +#endif + +#ifdef _WIN32 +#include <windows.h> +#define DEFAULT_FONT "Calibri" +#undef near +#undef far +#endif + +typedef struct { + glyphy_extents_t extents; + double advance; + glyphy_bool_t is_empty; /* has no outline; eg. space; don't draw it */ + unsigned int nominal_w; + unsigned int nominal_h; + unsigned int atlas_x; + unsigned int atlas_y; +} glyph_info_t; + + +typedef struct demo_font_t demo_font_t; + +demo_font_t * +demo_font_create ( +#ifndef _WIN32 + FT_Face face, +#endif +#ifdef _WIN32 + HDC hdc, +#endif + demo_atlas_t *atlas); + +demo_font_t * +demo_font_reference (demo_font_t *font); + +void +demo_font_destroy (demo_font_t *font); + + +#ifndef _WIN32 +FT_Face +#endif +#ifdef _WIN32 +HDC +#endif +demo_font_get_face (demo_font_t *font); + +demo_atlas_t * +demo_font_get_atlas (demo_font_t *font); + + +void +demo_font_lookup_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info); + +void +demo_font_print_stats (demo_font_t *font); + + +#endif /* DEMO_FONT_H */ diff --git a/vcl/inc/glyphy/demo/demo-fshader-glsl.h b/vcl/inc/glyphy/demo/demo-fshader-glsl.h new file mode 100644 index 000000000000..d80a6cc82b26 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-fshader-glsl.h @@ -0,0 +1,88 @@ +static const char *demo_fshader_glsl = +"uniform float u_contrast;\n" +"uniform float u_gamma_adjust;\n" +"uniform float u_outline_thickness;\n" +"uniform bool u_outline;\n" +"uniform float u_boldness;\n" +"uniform bool u_debug;\n" +"\n" +"varying vec4 v_glyph;\n" +"\n" +"\n" +"#define SQRT2_2 0.70710678118654757 /* 1 / sqrt(2.) */\n" +"#define SQRT2 1.4142135623730951\n" +"\n" +"struct glyph_info_t {\n" +" ivec2 nominal_size;\n" +" ivec2 atlas_pos;\n" +"};\n" +"\n" +"glyph_info_t\n" +"glyph_info_decode (vec4 v)\n" +"{\n" +" glyph_info_t gi;\n" +" gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;\n" +" gi.atlas_pos = ivec2 (v_glyph.zw) / 256;\n" +" return gi;\n" +"}\n" +"\n" +"\n" +"float\n" +"antialias (float d)\n" +"{\n" +" return smoothstep (-.75, +.75, d);\n" +"}\n" +"\n" +"vec4\n" +"source_over (const vec4 src, const vec4 dst)\n" +"{\n" +" // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcover\n" +" float alpha = src.a + (dst.a * (1. - src.a));\n" +" return vec4 (((src.rgb * src.a) + (dst.rgb * dst.a * (1. - src.a))) / alpha, alpha);\n" +"}\n" +"\n" +"void\n" +"main()\n" +"{\n" +" vec2 p = v_glyph.xy;\n" +" glyph_info_t gi = glyph_info_decode (v_glyph);\n" +"\n" +" /* isotropic antialiasing */\n" +" vec2 dpdx = dFdx (p);\n" +" vec2 dpdy = dFdy (p);\n" +" float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;\n" +"\n" +" vec4 color = vec4 (0,0,0,1);\n" +"\n" +" float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n" +" float sdist = gsdist / m * u_contrast;\n" +"\n" +" if (!u_debug) {\n" +" sdist -= u_boldness * 10.;\n" +" if (u_outline)\n" +" sdist = abs (sdist) - u_outline_thickness * .5;\n" +" if (sdist > 1.)\n" +" discard;\n" +" float alpha = antialias (-sdist);\n" +" if (u_gamma_adjust != 1.)\n" +" alpha = pow (alpha, 1./u_gamma_adjust);\n" +" color = vec4 (color.rgb,color.a * alpha);\n" +" } else {\n" +" float gudist = abs (gsdist);\n" +" float debug_color = 0.4;\n" +" // Color the distance field red inside and green outside\n" +" if (!glyphy_isinf (gudist))\n" +" color = source_over (vec4 (debug_color * smoothstep (1., -1., sdist), debug_color * smoothstep (-1., 1., sdist), 0, 1. - gudist), color);\n" +"\n" +" glyphy_arc_list_t arc_list = glyphy_arc_list (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n" +" // Color the number of endpoints per cell blue\n" +" color = source_over (vec4 (0, 0, debug_color, float(arc_list.num_endpoints) / float(GLYPHY_MAX_NUM_ENDPOINTS)), color);\n" +"\n" +" float pdist = glyphy_point_dist (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n" +" // Color points yellow\n" +" color = source_over (vec4 (1, 1, 0, smoothstep (.06, .05, pdist)), color);\n" +" }\n" +"\n" +" gl_FragColor = color;\n" +"}\n" +; diff --git a/vcl/inc/glyphy/demo/demo-shader.h b/vcl/inc/glyphy/demo/demo-shader.h new file mode 100644 index 000000000000..dfa548091039 --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-shader.h @@ -0,0 +1,47 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_SHADERS_H +#define DEMO_SHADERS_H + +#include "demo-common.h" +#include "demo-font.h" + + +struct glyph_vertex_t { + /* Position */ + GLfloat x; + GLfloat y; + /* Glyph info */ + GLfloat g16hi; + GLfloat g16lo; +}; + +void +demo_shader_add_glyph_vertices (const glyphy_point_t &p, + double font_size, + glyph_info_t *gi, + std::vector<glyph_vertex_t> *vertices, + glyphy_extents_t *extents); + + +GLuint +demo_shader_create_program (void); + + +#endif /* DEMO_SHADERS_H */ diff --git a/vcl/inc/glyphy/demo/demo-vshader-glsl.h b/vcl/inc/glyphy/demo/demo-vshader-glsl.h new file mode 100644 index 000000000000..c952ab719b2c --- /dev/null +++ b/vcl/inc/glyphy/demo/demo-vshader-glsl.h @@ -0,0 +1,24 @@ +static const char *demo_vshader_glsl = +"uniform mat4 u_matViewProjection;\n" +"\n" +"attribute vec4 a_glyph_vertex;\n" +"\n" +"varying vec4 v_glyph;\n" +"\n" +"vec4\n" +"glyph_vertex_transcode (vec2 v)\n" +"{\n" +" ivec2 g = ivec2 (v);\n" +" ivec2 corner = ivec2 (mod (v, 2.));\n" +" g /= 2;\n" +" ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));\n" +" return vec4 (corner * nominal_size, g * 4);\n" +"}\n" +"\n" +"void\n" +"main()\n" +"{\n" +" gl_Position = u_matViewProjection * vec4 (a_glyph_vertex.xy, 0, 1);\n" +" v_glyph = glyph_vertex_transcode (a_glyph_vertex.zw);\n" +"}\n" +; diff --git a/vcl/inc/glyphy/demo/matrix4x4.h b/vcl/inc/glyphy/demo/matrix4x4.h new file mode 100644 index 000000000000..2169561007e3 --- /dev/null +++ b/vcl/inc/glyphy/demo/matrix4x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2009, Mozilla Corp + * Copyright (c) 2012, Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers + * the following header: + * + * Book: OpenGL(R) ES 2.0 Programming Guide + * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner + * ISBN-10: 0321502795 + * ISBN-13: 9780321502797 + * Publisher: Addison-Wesley Professional + * URLs: http://safari.informit.com/9780321563835 + * http://www.opengles-book.com + */ + +/* + * Ported from JavaScript to C by Behdad Esfahbod, 2012. + * Added MultMatrix. Converting from fixed-function OpenGL matrix + * operations to these functions should be as simple as renaming the + * 'gl' prefix to 'm4' and adding the matrix argument to the call. + * + * The C version lives at http://code.google.com/p/matrix4x4-c/ + */ + +/* + * A simple 4x4 matrix utility implementation + */ + +#ifndef MATRIX4x4_H +#define MATRIX4x4_H + +/* Copies other matrix into mat */ +float * +m4Copy (float *mat, const float *other); + +float * +m4Multiply (float *mat, const float *right); + +float * +m4MultMatrix (float *mat, const float *left); + +float +m4Get (float *mat, unsigned int row, unsigned int col); + +float * +m4Scale (float *mat, float sx, float sy, float sz); + +float * +m4Translate (float *mat, float tx, float ty, float tz); + +float * +m4Rotate (float *mat, float angle, float x, float y, float z); + +float * +m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ); + +float * +m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ); + +float * +m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ); + +/* In-place inversion */ +float * +m4Invert (float *mat); + +/* Puts the inverse of other matrix into mat */ +float * +m4Inverse (float *mat, const float *other); + +/* In-place transpose */ +float * +m4Transpose (float *mat); + +float * +m4LoadIdentity (float *mat); + +float * +m4ApplyToVect (float *mat, float *vec); + +#endif diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 2409d4b36303..5ae2ce4b4722 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -33,6 +33,7 @@ #include "sft.hxx" #include "sallayout.hxx" +#include "glyphy/demo.hxx" #include <cstdio> #include <cstdlib> @@ -46,8 +47,6 @@ #include <unordered_map> -typedef std::unordered_map<int,int> IntMap; - // Graphite headers #include <config_graphite.h> #if ENABLE_GRAPHITE @@ -67,33 +66,13 @@ const int GLYPH_SPACE_RATIO = 8; const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2; } -struct OpenGLGlyphCacheChunk -{ - WORD mnFirstGlyph; - int mnGlyphCount; - std::vector<Rectangle> maLocation; - std::shared_ptr<OpenGLTexture> mpTexture; - int mnAscent; - int mnHeight; - bool mbVertical; - - int getExtraSpace() const - { - return std::max(mnHeight / GLYPH_SPACE_RATIO, 4); - } - - int getExtraOffset() const - { - return std::max(mnHeight / GLYPH_OFFSET_RATIO, 2); - } -}; - // win32 specific physical font instance class ImplWinFontEntry : public ImplFontEntry { public: explicit ImplWinFontEntry( FontSelectPattern& ); virtual ~ImplWinFontEntry(); + void setupGLyphy(HDC hDC); private: // TODO: also add HFONT??? Watch out for issues with too many active fonts... @@ -103,162 +82,31 @@ public: { return maScriptCache; } private: mutable SCRIPT_CACHE maScriptCache; - std::vector<OpenGLGlyphCacheChunk> maOpenGLGlyphCache; public: - int GetCachedGlyphWidth( int nCharCode ) const; - void CacheGlyphWidth( int nCharCode, int nCharWidth ); - bool InitKashidaHandling( HDC ); int GetMinKashidaWidth() const { return mnMinKashidaWidth; } int GetMinKashidaGlyph() const { return mnMinKashidaGlyph; } + static GLuint mnGLyphyProgram; + GLyphyDemo::demo_atlas_t* mpGLyphyAtlas; + GLyphyDemo::demo_font_t* mpGLyphyFont; + private: - IntMap maWidthMap; mutable int mnMinKashidaWidth; mutable int mnMinKashidaGlyph; - -public: - bool GlyphIsCached(int nGlyphIndex) const; - bool AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics); - const OpenGLGlyphCacheChunk& GetCachedGlyphChunkFor(int nGlyphIndex) const; + bool mbGLyphySetupCalled; }; -#ifdef SAL_LOG_INFO - -namespace { - -char ColorFor(COLORREF aColor) -{ - if (aColor == RGB(0xFF, 0xFF, 0xFF)) - return ' '; - else if (aColor == RGB(0x00, 0x00, 0x00)) - return 'X'; - - return '0' + (10*(GetRValue(aColor) + GetGValue(aColor) + GetBValue(aColor))) / (0xFF*3); -} - -void DumpGlyphBitmap(HDC hDC) -{ - HBITMAP hBitmap = static_cast<HBITMAP>(GetCurrentObject(hDC, OBJ_BITMAP)); - if (hBitmap == NULL) - { - SAL_WARN("vcl.gdi", "GetCurrentObject failed: " << WindowsErrorString(GetLastError())); - return; - } - - BITMAP aBitmap; - if (!GetObjectW(hBitmap, sizeof(aBitmap), &aBitmap)) - { - SAL_WARN("vcl.gdi", "GetObjectW failed: " << WindowsErrorString(GetLastError())); - return; - } - - SAL_INFO("vcl.gdi.opengl", "Bitmap " << hBitmap << ": " << aBitmap.bmWidth << "x" << aBitmap.bmHeight << ":"); - - std::ostringstream sLine("\n"); - for (long y = 0; y < aBitmap.bmHeight; y++) - { - for (long x = 0; x < std::min(75l, aBitmap.bmWidth); x++) - sLine << ColorFor(GetPixel(hDC, x, y)); - if (y < aBitmap.bmHeight - 1) - sLine << "\n"; - } - SAL_INFO("vcl.gdi.opengl", sLine.str()); -} - -} // anonymous namespace - -#endif // SAL_LOG_INFO - -template< typename charT, typename traits > -inline std::basic_ostream<charT, traits> & operator <<( - std::basic_ostream<charT, traits> & stream, const std::vector<OpenGLGlyphCacheChunk>& rCache ) -{ - stream << "{"; - for (auto i = rCache.cbegin(); i != rCache.cend(); ++i) - { - stream << "[" << i->mnFirstGlyph; - if (i->mnGlyphCount > 1) - stream << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1); - stream << "]"; - if (i+1 != rCache.cend()) - { - stream << ","; - assert(i->mnFirstGlyph + i->mnGlyphCount <= (i+1)->mnFirstGlyph); - } - } - - return stream << "}"; -} - -inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth ) -{ - maWidthMap[ nCharCode ] = nCharWidth; -} - -inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const -{ - IntMap::const_iterator it = maWidthMap.find( nCharCode ); - if( it == maWidthMap.end() ) - return -1; - return it->second; -} - -bool ImplWinFontEntry::GlyphIsCached(int nGlyphIndex) const -{ - if (nGlyphIndex == DROPPED_OUTGLYPH) - return true; - - for (size_t i = 0; i < maOpenGLGlyphCache.size(); i++) - if (nGlyphIndex >= maOpenGLGlyphCache[i].mnFirstGlyph && - nGlyphIndex < maOpenGLGlyphCache[i].mnFirstGlyph + maOpenGLGlyphCache[i].mnGlyphCount) - return true; +GLuint ImplWinFontEntry::mnGLyphyProgram = 0; - return false; -} +#if 0 -bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics) +bool ImplWinFontEntry::AddGlyphToCache(WORD nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics) { - const int DEFAULT_CHUNK_SIZE = 20; - if (nGlyphIndex == DROPPED_OUTGLYPH) return true; - SAL_INFO("vcl.gdi.opengl", "this=" << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache); - - auto n = maOpenGLGlyphCache.begin(); - while (n != maOpenGLGlyphCache.end() && - nGlyphIndex > n->mnFirstGlyph) - ++n; - assert(n == maOpenGLGlyphCache.end() || nGlyphIndex < n->mnFirstGlyph); - - int nCount = DEFAULT_CHUNK_SIZE; - if (n != maOpenGLGlyphCache.end() && nGlyphIndex + nCount >= n->mnFirstGlyph) - nCount = n->mnFirstGlyph - nGlyphIndex; - - if (nCount < DEFAULT_CHUNK_SIZE) - { - if (n == maOpenGLGlyphCache.begin()) - { - nGlyphIndex = std::max(0, n->mnFirstGlyph - DEFAULT_CHUNK_SIZE); - } - else - { - nGlyphIndex = std::max(n[-1].mnFirstGlyph + n[-1].mnGlyphCount, - n->mnFirstGlyph - DEFAULT_CHUNK_SIZE); - } - nCount = n->mnFirstGlyph - nGlyphIndex; - } - - OpenGLGlyphCacheChunk aChunk; - aChunk.mnFirstGlyph = nGlyphIndex; - aChunk.mnGlyphCount = nCount; - - std::vector<WORD> aGlyphIndices(nCount); - for (int i = 0; i < nCount; i++) - aGlyphIndices[i] = nGlyphIndex + i; - HDC hDC = CreateCompatibleDC(rLayout.mhDC); if (hDC == NULL) { @@ -275,7 +123,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou SIZE aSize; - if (!GetTextExtentExPointI(hDC, aGlyphIndices.data(), nCount, 0, NULL, NULL, &aSize)) + if (!GetTextExtentExPointI(hDC, &nGlyphIndex, 1, 0, NULL, NULL, &aSize)) { SAL_WARN("vcl.gdi", "GetTextExtentExPointI failed: " << WindowsErrorString(GetLastError())); SelectObject(hDC, hOrigFont); @@ -283,8 +131,8 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou return false; } - std::vector<ABC> aABC(nCount); - if (!GetCharABCWidthsI(hDC, 0, nCount, aGlyphIndices.data(), aABC.data())) + ABC aABC; + if (!GetCharABCWidthsI(hDC, 0, 1, &nGlyphIndex, &aABC)) { SAL_WARN("vcl.gdi", "GetCharABCWidthsI failed: " << WindowsErrorString(GetLastError())); SelectObject(hDC, hOrigFont); @@ -292,10 +140,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou return false; } - std::ostringstream sLine; - for (int i = 0; i < nCount; i++) - sLine << aABC[i].abcA << ":" << aABC[i].abcB << ":" << aABC[i].abcC << " "; - SAL_INFO("vcl.gdi.opengl", "ABC widths: " << sLine.str()); + SAL_INFO("vcl.gdi.opengl", "ABC width: " << aABC.abcA << ":" << aABC.abcB << ":" << aABC.abcC); TEXTMETRICW aTextMetric; if (!GetTextMetricsW(hDC, &aTextMetric)) @@ -305,25 +150,6 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou DeleteDC(hDC); return false; } - aChunk.mnAscent = aTextMetric.tmAscent; - aChunk.mnHeight = aTextMetric.tmHeight; - - // Try hard to avoid overlap as we want to be able to use - // individual rectangles for each glyph. The ABC widths don't - // take anti-aliasing into consideration. Let's hope that leaving - // "extra" space inbetween glyphs will help. - std::vector<int> aDX(nCount); - int totWidth = 0; - for (int i = 0; i < nCount; i++) - { - aDX[i] = aABC[i].abcB + std::abs(aABC[i].abcC); - if (i == 0) - aDX[0] += std::abs(aABC[0].abcA); - if (i < nCount-1) - aDX[i] += std::abs(aABC[i+1].abcA); - aDX[i] += aChunk.getExtraSpace(); - totWidth += aDX[i]; - } LOGFONTW aLogfont; if (!GetObjectW(rLayout.mhFont, sizeof(aLogfont), &aLogfont)) @@ -349,120 +175,73 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou " Orientation=" << aLogfont.lfOrientation << " Ascent=" << aTextMetric.tmAscent << " InternalLeading=" << aTextMetric.tmInternalLeading << - " Size=(" << aSize.cx << "," << aSize.cy << ") totWidth=" << totWidth); + " Size=(" << aSize.cx << "," << aSize.cy << ")"); if (SelectObject(hDC, hOrigFont) == NULL) SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); if (!DeleteDC(hDC)) SAL_WARN("vcl.gdi", "DeleteDC failed: " << WindowsErrorString(GetLastError())); - // Leave extra space also at top and bottom - int nBitmapWidth, nBitmapHeight; - if (sFaceName[0] == '@') - { - nBitmapWidth = aSize.cy + aChunk.getExtraSpace(); - nBitmapHeight = totWidth; - aChunk.mbVertical = true; - } - else - { - nBitmapWidth = totWidth; - nBitmapHeight = aSize.cy + aChunk.getExtraSpace(); - aChunk.mbVertical = false; - } + // FIXME HERE, in case this code snipet actually is needed any more? - if (aChunk.mbVertical && aLogfont.lfEscapement != 2700) - return false; + return true; +} - OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight); +#endif - HFONT hNonAntialiasedFont = NULL; +void ImplWinFontEntry::setupGLyphy(HDC hDC) +{ + if (mbGLyphySetupCalled) + return; -#ifdef DBG_UTIL - static bool bNoAntialias = (std::getenv("VCL_GLYPH_CACHING_HACK_NO_ANTIALIAS") != NULL); - if (bNoAntialias) - { - aLogfont.lfQuality = NONANTIALIASED_QUALITY; - hNonAntialiasedFont = CreateFontIndirectW(&aLogfont); - if (hNonAntialiasedFont == NULL) - { - SAL_WARN("vcl.gdi", "CreateFontIndirect failed: " << WindowsErrorString(GetLastError())); - return false; - } - } -#endif + mbGLyphySetupCalled = true; - hOrigFont = SelectFont(aDC.getCompatibleHDC(), hNonAntialiasedFont != NULL ? hNonAntialiasedFont : rLayout.mhFont); - if (hOrigFont == NULL) + // First get the OUTLINETEXTMETRIC to find the font's em unit. Then, to get an unmodified (not + // grid-fitted) glyph outline, create the font anew at that size. That is as the doc for + // GetGlyphOutline() suggests. + OUTLINETEXTMETRICW aOutlineTextMetric; + if (!GetOutlineTextMetricsW (hDC, sizeof (OUTLINETEXTMETRICW), &aOutlineTextMetric)) { - SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); - return false; + SAL_WARN("vcl.gdi.opengl", "GetOutlineTextMetricsW failed: " << WindowsErrorString(GetLastError())); + return; } - SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0)); - SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255)); - - aDC.fill(MAKE_SALCOLOR(0xff, 0xff, 0xff)); + HFONT hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT); + LOGFONTW aLogFont; + GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont); - int nY = aChunk.getExtraOffset(); - int nX = nY; - if (aChunk.mbVertical) - nX += aDX[0]; - if (!ExtTextOutW(aDC.getCompatibleHDC(), nX, nY, ETO_GLYPH_INDEX, NULL, aGlyphIndices.data(), nCount, aDX.data())) + HDC hNewDC = GetDC(NULL); + if (hNewDC == NULL) { - SAL_WARN("vcl.gdi", "ExtTextOutW failed: " << WindowsErrorString(GetLastError())); - SelectFont(aDC.getCompatibleHDC(), hOrigFont); - if (hNonAntialiasedFont != NULL) - DeleteObject(hNonAntialiasedFont); - return false; + SAL_WARN("vcl.gdi.opengl", "GetDC failed: " << WindowsErrorString(GetLastError())); + return; } - aChunk.maLocation.resize(nCount); - UINT nPos = 0; - for (int i = 0; i < nCount; i++) + hNewDC = CreateCompatibleDC(hNewDC); + if (hNewDC == NULL) { - if (aChunk.mbVertical) - { - aChunk.maLocation[i].Left() = 0; - aChunk.maLocation[i].Right() = nBitmapWidth; - aChunk.maLocation[i].Top() = nPos; - aChunk.maLocation[i].Bottom() = nPos + aDX[i]; - nPos = aChunk.maLocation[i].Bottom(); - } - else - { - aChunk.maLocation[i].Left() = nPos; - aChunk.maLocation[i].Right() = nPos + aDX[i]; - nPos = aChunk.maLocation[i].Right(); - aChunk.maLocation[i].Top() = 0; - aChunk.maLocation[i].Bottom() = aSize.cy + aChunk.getExtraSpace(); - } + SAL_WARN("vcl.gdi.opengl", "CreateCompatibleDC failed: " << WindowsErrorString(GetLastError())); + return; } - aChunk.mpTexture = std::unique_ptr<OpenGLTexture>(aDC.getTexture()); - - maOpenGLGlyphCache.insert(n, aChunk); - - SelectFont(aDC.getCompatibleHDC(), hOrigFont); - if (hNonAntialiasedFont != NULL) - DeleteObject(hNonAntialiasedFont); - -#ifdef SAL_LOG_INFO - SAL_INFO("vcl.gdi.opengl", "this=" << this << " now: " << maOpenGLGlyphCache); - DumpGlyphBitmap(aDC.getCompatibleHDC()); -#endif + aLogFont.lfHeight = aOutlineTextMetric.otmEMSquare; + hFont = CreateFontIndirectW(&aLogFont); + if (hFont == NULL) + { + SAL_WARN("vcl.gdi.opengl", "CreateFontIndirectW failed: " << WindowsErrorString(GetLastError())); + return; + } + if (SelectObject(hNewDC, hFont) == NULL) + { + SAL_WARN("vcl.gdi.opengl", "SelectObject failed: " << WindowsErrorString(GetLastError())); + return; + } - return true; -} + if (mnGLyphyProgram == 0) + mnGLyphyProgram = GLyphyDemo::demo_shader_create_program(); -const OpenGLGlyphCacheChunk& ImplWinFontEntry::GetCachedGlyphChunkFor(int nGlyphIndex) const -{ - auto i = maOpenGLGlyphCache.cbegin(); - while (i != maOpenGLGlyphCache.cend() && nGlyphIndex >= i->mnFirstGlyph + i->mnGlyphCount) - ++i; - assert(i != maOpenGLGlyphCache.cend()); - assert(nGlyphIndex >= i->mnFirstGlyph && nGlyphIndex < i->mnFirstGlyph + i->mnGlyphCount); - return *i; + mpGLyphyAtlas = GLyphyDemo::demo_atlas_create(2048, 1024, 64, 8); + mpGLyphyFont = GLyphyDemo::demo_font_create(hNewDC, mpGLyphyAtlas); } WinLayout::WinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE, bool bUseOpenGL) @@ -1765,20 +1544,26 @@ void UniscribeLayout::DrawTextImpl(HDC hDC) const DeleteFont(SelectFont(hDC, hOrigFont)); } -bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const +bool UniscribeLayout::CacheGlyphs(SalGraphics&) const { static bool bDoGlyphCaching = (std::getenv("SAL_DISABLE_GLYPH_CACHING") == NULL); if (!bDoGlyphCaching) return false; + if (!mrWinFontEntry.maMetric.mbTrueTypeFont) + return false; + + mrWinFontEntry.setupGLyphy(mhDC); + for (int i = 0; i < mnGlyphCount; i++) { - if (mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])) + if (mpOutGlyphs[i] == DROPPED_OUTGLYPH) continue; - if (!mrWinFontEntry.AddChunkOfGlyphs(mpOutGlyphs[i], *this, rGraphics)) - return false; + GLyphyDemo::glyph_info_t aGI; + VCL_GL_INFO("vcl.opengl", "Calling demo_font_lookup_glyph"); + GLyphyDemo::demo_font_lookup_glyph( mrWinFontEntry.mpGLyphyFont, mpOutGlyphs[i], &aGI ); } return true; @@ -1787,20 +1572,53 @@ bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const { WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics); - HDC hDC = rWinGraphics.getHDC(); Rectangle aRect; GetBoundRect(rGraphics, aRect); - COLORREF color = GetTextColor(hDC); - SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color)); - WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get()); if (!pImpl) return false; pImpl->PreDraw(); + rGraphics.GetOpenGLContext()->UseNoProgram(); + glUseProgram( mrWinFontEntry.mnGLyphyProgram ); + CHECK_GL_ERROR(); + GLyphyDemo::demo_atlas_set_uniforms( mrWinFontEntry.mpGLyphyAtlas ); + + GLint nLoc; + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_debug" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 0 ); // FIXME: Try to get the "debug" thing displayed first + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_contrast" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 1 ); + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_gamma_adjust" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 1 ); + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_outline" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, false ); + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_outline_thickness" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 1 ); + CHECK_GL_ERROR(); + + nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_boldness" ); + CHECK_GL_ERROR(); + glUniform1f( nLoc, 0 ); + CHECK_GL_ERROR(); + // FIXME: This code snippet is mostly copied from the one in // UniscribeLayout::DrawTextImpl. Should be factored out. int nBaseClusterOffset = 0; @@ -1842,35 +1660,97 @@ bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const // positioning) match. const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances; + double font_size = mrWinFontEntry.maFontSelData.mfExactHeight; // ??? + + // font_size = 1; // ??? + + std::vector<GLyphyDemo::glyph_vertex_t> vertices; for (int i = nMinGlyphPos; i < nEndGlyphPos; i++) { // Ignore dropped glyphs. if (mpOutGlyphs[i] == DROPPED_OUTGLYPH) continue; - assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])); + // Total crack + GLyphyDemo::glyphy_point_t pt; + pt.x = nAdvance + aPos.X() + mpGlyphOffsets[i].du; + pt.y = aPos.Y() + mpGlyphOffsets[i].dv; + GLyphyDemo::glyph_info_t gi; + GLyphyDemo::demo_font_lookup_glyph( mrWinFontEntry.mpGLyphyFont, mpOutGlyphs[i], &gi ); + GLyphyDemo::demo_shader_add_glyph_vertices( pt, font_size, &gi, &vertices, NULL ); - const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(mpOutGlyphs[i]); - const int n = mpOutGlyphs[i] - rChunk.mnFirstGlyph; - - if (rChunk.mbVertical) - { - SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), - rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(), - aPos.X(), nAdvance + aPos.Y(), - rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ??? - pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects); - } - else - { - SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), - rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(), - nAdvance + aPos.X() + mpGlyphOffsets[i].du - rChunk.getExtraOffset(), aPos.Y() + mpGlyphOffsets[i].dv - rChunk.mnAscent - rChunk.getExtraOffset(), - rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ??? - pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects); - } nAdvance += pGlyphWidths[i]; } + + GLfloat mat[16]; + GLyphyDemo::m4LoadIdentity( mat ); + + GLint viewport[4]; + glGetIntegerv( GL_VIEWPORT, viewport ); + CHECK_GL_ERROR(); + + double width = viewport[2]; + double height = viewport[3]; + +#if 0 + // Based on demo_view_apply_transform(). I don't really understand it. + + // No scaling, no translation needed here + + // Perspective (but why would we want that in LO; it's needed in glyphy-demo because there + // you can rotate the "sheet" the text is drawn on) + { + double d = std::max( width, height ); + double near = d / 4; + double far = near + d; + double factor = near / (2 * near + d); + GLyphyDemo::m4Frustum( mat, -width * factor, width * factor, -height * factor, height * factor, near, far ); + GLyphyDemo::m4Translate( mat, 0, 0, -(near + d * 0.5) ); + } + + // No rotation here + + // Fix 'up' + GLyphyDemo::m4Scale( mat, 1, -1, 1 ); + + // Foo + // GLyphyDemo::m4Scale( mat, 0.5, 0.5, 1 ); + + // The "Center buffer" part in demo_view_display() + GLyphyDemo::m4Translate( mat, width/2, height/2, 0 ); + +#else + // Crack that just happens to show something (even if not completely in correct location) in + // some cases, but not all. I don't understand why. + double scale = std::max( 2/width, 2/height ); + GLyphyDemo::m4Scale( mat, scale, -scale, 1); + GLyphyDemo::m4Translate( mat, -width/2, -height/2, 0 ); +#endif + + GLuint u_matViewProjection_loc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_matViewProjection" ); + CHECK_GL_ERROR(); + glUniformMatrix4fv( u_matViewProjection_loc, 1, GL_FALSE, mat ); + CHECK_GL_ERROR(); + + GLuint a_glyph_vertex_loc = glGetAttribLocation( mrWinFontEntry.mnGLyphyProgram, "a_glyph_vertex" ); + GLuint buf_name; + glGenBuffers( 1, &buf_name ); + CHECK_GL_ERROR(); + glBindBuffer( GL_ARRAY_BUFFER, buf_name ); + CHECK_GL_ERROR(); + + glBufferData( GL_ARRAY_BUFFER, sizeof(GLyphyDemo::glyph_vertex_t) * vertices.size(), (const char *) &vertices[0], GL_STATIC_DRAW ); + CHECK_GL_ERROR(); + glEnableVertexAttribArray( a_glyph_vertex_loc ); + CHECK_GL_ERROR(); + glVertexAttribPointer( a_glyph_vertex_loc, 4, GL_FLOAT, GL_FALSE, sizeof(GLyphyDemo::glyph_vertex_t), 0 ); + CHECK_GL_ERROR(); + glDrawArrays( GL_TRIANGLES, 0, vertices.size() ); + CHECK_GL_ERROR(); + glDisableVertexAttribArray( a_glyph_vertex_loc ); + CHECK_GL_ERROR(); + glDeleteBuffers( 1, &buf_name ); + CHECK_GL_ERROR(); } pImpl->PostDraw(); @@ -2625,11 +2505,14 @@ int WinSalGraphics::GetMinKashidaWidth() ImplWinFontEntry::ImplWinFontEntry( FontSelectPattern& rFSD ) : ImplFontEntry( rFSD ) -, maWidthMap( 512 ) +, mpGLyphyAtlas( nullptr ) +, mpGLyphyFont( nullptr ) , mnMinKashidaWidth( -1 ) , mnMinKashidaGlyph( -1 ) { maScriptCache = NULL; + mpGLyphyFont = NULL; + mbGLyphySetupCalled = false; } ImplWinFontEntry::~ImplWinFontEntry() |