citrun

watch C/C++ source code execute
Log | Files | Refs | LICENSE

commit f53a4f16ac181ce8a7f2ab532be501a94522dfea
parent 53502e5e5763822f98bed21ae35ef762d3d0346a
Author: Kyle Milz <kyle@getaddrinfo.net>
Date:   Sat, 19 Mar 2016 16:59:03 -0600

viewer: port over glyphy demo code

Diffstat:
Mviewer/Makefile | 4+++-
Mviewer/af_unix.cxx | 4++--
Aviewer/demo-atlas-glsl.h | 18++++++++++++++++++
Aviewer/demo-atlas.cxx | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-atlas.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-buffer.cxx | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-buffer.h | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-common.h | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-font.cxx | 257+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-font.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-fshader-glsl.h | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-glstate.cxx | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-glstate.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-shader.cxx | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-shader.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-view.cxx | 656+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-view.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/demo-vshader-glsl.h | 24++++++++++++++++++++++++
Aviewer/matrix4x4.c | 398+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/matrix4x4.h | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mviewer/text.cxx | 25+------------------------
Mviewer/text.h | 3---
Aviewer/trackball.c | 337+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aviewer/trackball.h | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mviewer/viewer.cxx | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
25 files changed, 3220 insertions(+), 56 deletions(-)

diff --git a/viewer/Makefile b/viewer/Makefile @@ -1,5 +1,7 @@ PROG = scv_viewer -SRCS = viewer.cxx text.cxx af_unix.cxx +SRCS = viewer.cxx text.cxx af_unix.cxx demo-atlas.cxx demo-buffer.cxx +SRCS += demo-font.cxx demo-glstate.cxx demo-shader.cxx demo-view.cxx trackball.c +SRCS += matrix4x4.c CXXFLAGS += -std=c++11 CXXFLAGS += `pkg-config gl glew ftgl --cflags` diff --git a/viewer/af_unix.cxx b/viewer/af_unix.cxx @@ -21,7 +21,7 @@ af_unix::af_unix(int f) : void af_unix::set_listen() { -#ifdef __APPLE__ +#if defined(__APPLE__) // OS X socket() doesn't take SOCK_NONBLOCK if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); @@ -29,7 +29,7 @@ af_unix::set_listen() int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) err(1, "fcntl(F_GETFL)"); - fcntl(fd, F_SETFL, flags & O_NONBLOCK); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); if (flags < 0) err(1, "fcntl(F_SETFL)"); #else diff --git a/viewer/demo-atlas-glsl.h b/viewer/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/viewer/demo-atlas.cxx b/viewer/demo-atlas.cxx @@ -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/viewer/demo-atlas.h b/viewer/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/viewer/demo-buffer.cxx b/viewer/demo-buffer.cxx @@ -0,0 +1,180 @@ +/* + * 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) +{ + FT_Face face = demo_font_get_face (font); + 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; + } + + unsigned int glyph_index = FT_Get_Char_Index (face, unicode); + 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/viewer/demo-buffer.h b/viewer/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/viewer/demo-common.h b/viewer/demo-common.h @@ -0,0 +1,95 @@ +/* + * 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/glyphy.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> + +#include <algorithm> +#include <vector> + +#include <GL/glew.h> +#include <GLES2/gl2.h> +#include <OpenGL/OpenGL.h> + +#if defined(__APPLE__) +# include <GLUT/glut.h> +#else +# include <GL/glut.h> +#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 LOGI(...) ((void) fprintf (stdout, __VA_ARGS__)) +#define LOGW(...) ((void) fprintf (stderr, __VA_ARGS__)) +#define LOGE(...) ((void) fprintf (stderr, __VA_ARGS__), abort ()) + +#define gl(name) \ + for (GLint __ee, __ii = 0; \ + __ii < 1; \ + (__ii++, \ + (__ee = glGetError()) && \ + (fprintf (stderr, "gl" #name " failed with error %04X on line %d\n", __ee, __LINE__), abort (), 0))) \ + gl##name + + +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; +} + +#define DEMO_FUNC __func__ + +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; +}; + +#define TRACE() auto_trace_t trace(DEMO_FUNC) + +#endif /* DEMO_COMMON_H */ diff --git a/viewer/demo-font.cxx b/viewer/demo-font.cxx @@ -0,0 +1,257 @@ +/* + * 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" + +#include "../glyphy/glyphy-freetype.h" + +#include <ext/hash_map> + +using namespace __gnu_cxx; /* This is ridiculous */ + + +typedef hash_map<unsigned int, glyph_info_t> glyph_cache_t; + +struct demo_font_t { + unsigned int refcount; + + FT_Face face; + 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 (FT_Face face, + 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); +} + + +FT_Face +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, + vector<glyphy_arc_endpoint_t> *endpoints) +{ + endpoints->push_back (*endpoint); + return true; +} + +static void +encode_ft_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)) + + 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); + 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"); + + 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); + + *advance = face->glyph->metrics.horiAdvance / (double) upem; + + 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_ft_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/viewer/demo-font.h b/viewer/demo-font.h @@ -0,0 +1,69 @@ +/* + * 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" + +#include <ft2build.h> +#include FT_FREETYPE_H + + +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 (FT_Face face, + demo_atlas_t *atlas); + +demo_font_t * +demo_font_reference (demo_font_t *font); + +void +demo_font_destroy (demo_font_t *font); + + +FT_Face +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/viewer/demo-fshader-glsl.h b/viewer/demo-fshader-glsl.h @@ -0,0 +1,87 @@ +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" +"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" +" color = vec4 (0,0,0,0);\n" +"\n" +" // Color the inside of the glyph a light red\n" +" color += vec4 (.5,0,0,.5) * smoothstep (1., -1., sdist);\n" +"\n" +" float udist = abs (sdist);\n" +" float gudist = abs (gsdist);\n" +" // Color the outline red\n" +" color += vec4 (1,0,0,1) * smoothstep (2., 1., udist);\n" +" // Color the distance field in green\n" +" if (!glyphy_isinf (udist))\n" +" color += vec4(0,.4,0,.4 - (abs(gsdist) / max(float(gi.nominal_size.x), float(gi.nominal_size.y))) * 4.);\n" +"\n" +" float pdist = glyphy_point_dist (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n" +" // Color points green\n" +" color = mix (vec4 (0,1,0,.5), color, smoothstep (.05, .06, pdist));\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 += vec4 (0,0,1,.1) * float(arc_list.num_endpoints) * 32./255.;\n" +" }\n" +"\n" +" gl_FragColor = color;\n" +"}\n" +; diff --git a/viewer/demo-glstate.cxx b/viewer/demo-glstate.cxx @@ -0,0 +1,155 @@ +/* + * 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, Wojciech Baranowski + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-glstate.h" + +struct demo_glstate_t { + unsigned int refcount; + + GLuint program; + demo_atlas_t *atlas; + + /* Uniforms */ + double u_debug; + double u_contrast; + double u_gamma_adjust; + double u_outline; + double u_outline_thickness; + double u_boldness; +}; + +demo_glstate_t * +demo_glstate_create (void) +{ + TRACE(); + + demo_glstate_t *st = (demo_glstate_t *) calloc (1, sizeof (demo_glstate_t)); + st->refcount = 1; + + st->program = demo_shader_create_program (); + st->atlas = demo_atlas_create (2048, 1024, 64, 8); + + st->u_debug = false; + st->u_contrast = 1.0; + st->u_gamma_adjust = 1.0; + st->u_outline = false; + st->u_outline_thickness = 1.0; + st->u_boldness = 0.; + + return st; +} + +demo_glstate_t * +demo_glstate_reference (demo_glstate_t *st) +{ + if (st) st->refcount++; + return st; +} + +void +demo_glstate_destroy (demo_glstate_t *st) +{ + if (!st || --st->refcount) + return; + + demo_atlas_destroy (st->atlas); + glDeleteProgram (st->program); + + free (st); +} + + +static void +set_uniform (GLuint program, const char *name, double *p, double value) +{ + *p = value; + glUniform1f (glGetUniformLocation (program, name), value); + LOGI ("Setting %s to %g\n", name + 2, value); +} + +#define SET_UNIFORM(name, value) set_uniform (st->program, #name, &st->name, value) + +void +demo_glstate_setup (demo_glstate_t *st) +{ + glUseProgram (st->program); + + demo_atlas_set_uniforms (st->atlas); + + SET_UNIFORM (u_debug, st->u_debug); + SET_UNIFORM (u_contrast, st->u_contrast); + SET_UNIFORM (u_gamma_adjust, st->u_gamma_adjust); + SET_UNIFORM (u_outline, st->u_outline); + SET_UNIFORM (u_outline_thickness, st->u_outline_thickness); + SET_UNIFORM (u_boldness, st->u_boldness); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +demo_atlas_t * +demo_glstate_get_atlas (demo_glstate_t *st) +{ + return st->atlas; +} + +void +demo_glstate_scale_gamma_adjust (demo_glstate_t *st, double factor) +{ + SET_UNIFORM (u_gamma_adjust, clamp (st->u_gamma_adjust * factor, .1, 10.)); +} + +void +demo_glstate_scale_contrast (demo_glstate_t *st, double factor) +{ + SET_UNIFORM (u_contrast, clamp (st->u_contrast * factor, .1, 10.)); +} + +void +demo_glstate_toggle_debug (demo_glstate_t *st) +{ + SET_UNIFORM (u_debug, 1 - st->u_debug); +} + +void +demo_glstate_set_matrix (demo_glstate_t *st, float mat[16]) +{ + glUniformMatrix4fv (glGetUniformLocation (st->program, "u_matViewProjection"), 1, GL_FALSE, mat); +} + +void +demo_glstate_toggle_outline (demo_glstate_t *st) +{ + SET_UNIFORM (u_outline, 1 - st->u_outline); +} + +void +demo_glstate_scale_outline_thickness (demo_glstate_t *st, double factor) +{ + SET_UNIFORM (u_outline_thickness, clamp (st->u_outline_thickness * factor, .5, 3.)); +} + +void +demo_glstate_adjust_boldness (demo_glstate_t *st, double adjustment) +{ + SET_UNIFORM (u_boldness, clamp (st->u_boldness + adjustment, -.2, .7)); +} diff --git a/viewer/demo-glstate.h b/viewer/demo-glstate.h @@ -0,0 +1,68 @@ +/* + * 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_GLSTATE_H +#define DEMO_GLSTATE_H + +#include "demo-common.h" +#include "demo-buffer.h" + +#include "demo-atlas.h" +#include "demo-shader.h" + +typedef struct demo_glstate_t demo_glstate_t; + +demo_glstate_t * +demo_glstate_create (void); + +demo_glstate_t * +demo_glstate_reference (demo_glstate_t *st); + +void +demo_glstate_destroy (demo_glstate_t *st); + + +void +demo_glstate_setup (demo_glstate_t *st); + +demo_atlas_t * +demo_glstate_get_atlas (demo_glstate_t *st); + +void +demo_glstate_scale_gamma_adjust (demo_glstate_t *st, double factor); + +void +demo_glstate_scale_contrast (demo_glstate_t *st, double factor); + +void +demo_glstate_toggle_debug (demo_glstate_t *st); + +void +demo_glstate_set_matrix (demo_glstate_t *st, float mat[16]); + +void +demo_glstate_toggle_outline (demo_glstate_t *st); + +void +demo_glstate_scale_outline_thickness (demo_glstate_t *st, double factor); + +void +demo_glstate_adjust_boldness (demo_glstate_t *st, double adjustment); + + +#endif /* DEMO_GLSTATE_H */ diff --git a/viewer/demo-shader.cxx b/viewer/demo-shader.cxx @@ -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/viewer/demo-shader.h b/viewer/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/viewer/demo-view.cxx b/viewer/demo-view.cxx @@ -0,0 +1,656 @@ +/* + * 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, Wojciech Baranowski + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "demo-view.h" + +extern "C" { +#include "trackball.h" +#include "matrix4x4.h" +} + +#include <sys/time.h> + + +struct demo_view_t { + unsigned int refcount; + + demo_glstate_t *st; + + /* Output */ + GLint vsync; + glyphy_bool_t srgb; + glyphy_bool_t fullscreen; + + /* Mouse handling */ + int buttons; + int modifiers; + bool dragged; + bool click_handled; + double beginx, beginy; + double lastx, lasty, lastt; + double dx,dy, dt; + + /* Transformation */ + float quat[4]; + double scale; + glyphy_point_t translate; + double perspective; + + /* Animation */ + float rot_axis[3]; + float rot_speed; + bool animate; + int num_frames; + long fps_start_time; + long last_frame_time; + bool has_fps_timer; + + /* Window geometry just before going fullscreen */ + int x; + int y; + int width; + int height; +}; + +demo_view_t *static_vu; + +demo_view_t * +demo_view_create (demo_glstate_t *st) +{ + TRACE(); + + demo_view_t *vu = (demo_view_t *) calloc (1, sizeof (demo_view_t)); + vu->refcount = 1; + + vu->st = st; + demo_view_reset (vu); + + assert (!static_vu); + static_vu = vu; + + return vu; +} + +demo_view_t * +demo_view_reference (demo_view_t *vu) +{ + if (vu) vu->refcount++; + return vu; +} + +void +demo_view_destroy (demo_view_t *vu) +{ + if (!vu || --vu->refcount) + return; + + assert (static_vu == vu); + static_vu = NULL; + + free (vu); +} + + +#define ANIMATION_SPEED 1. /* Default speed, in radians second. */ +void +demo_view_reset (demo_view_t *vu) +{ + vu->perspective = 4; + vu->scale = 1; + vu->translate.x = vu->translate.y = 0; + trackball (vu->quat , 0.0, 0.0, 0.0, 0.0); + vset (vu->rot_axis, 0., 0., 1.); + vu->rot_speed = ANIMATION_SPEED / 1000.; +} + + +static void +demo_view_scale_gamma_adjust (demo_view_t *vu, double factor) +{ + demo_glstate_scale_gamma_adjust (vu->st, factor); +} + +static void +demo_view_scale_contrast (demo_view_t *vu, double factor) +{ + demo_glstate_scale_contrast (vu->st, factor); +} + +static void +demo_view_scale_perspective (demo_view_t *vu, double factor) +{ + vu->perspective = clamp (vu->perspective * factor, .01, 100.); +} + +static void +demo_view_toggle_outline (demo_view_t *vu) +{ + demo_glstate_toggle_outline (vu->st); +} + +static void +demo_view_scale_outline_thickness (demo_view_t *vu, double factor) +{ + demo_glstate_scale_outline_thickness (vu->st, factor); +} + + +static void +demo_view_adjust_boldness (demo_view_t *vu, double factor) +{ + demo_glstate_adjust_boldness (vu->st, factor); +} + + +static void +demo_view_scale (demo_view_t *vu, double factor) +{ + vu->scale *= factor; +} + +static void +demo_view_translate (demo_view_t *vu, double dx, double dy) +{ + vu->translate.x += dx / vu->scale; + vu->translate.y += dy / vu->scale; +} + +static void +demo_view_apply_transform (demo_view_t *vu, float *mat) +{ + int viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + GLint width = viewport[2]; + GLint height = viewport[3]; + + // View transform + m4Scale (mat, vu->scale, vu->scale, 1); + m4Translate (mat, vu->translate.x, vu->translate.y, 0); + + // Perspective + { + double d = std::max (width, height); + double near = d / vu->perspective; + double far = near + d; + double factor = near / (2 * near + d); + m4Frustum (mat, -width * factor, width * factor, -height * factor, height * factor, near, far); + m4Translate (mat, 0, 0, -(near + d * .5)); + } + + // Rotate + float m[4][4]; + build_rotmatrix (m, vu->quat); + m4MultMatrix(mat, &m[0][0]); + + // Fix 'up' + m4Scale (mat, 1, -1, 1); +} + + +/* return current time in milli-seconds */ +static long +current_time (void) +{ + return glutGet (GLUT_ELAPSED_TIME); +} + +static void +next_frame (demo_view_t *vu) +{ + glutPostRedisplay (); +} + +static void +timed_step (int ms) +{ + demo_view_t *vu = static_vu; + if (vu->animate) { + glutTimerFunc (ms, timed_step, ms); + next_frame (vu); + } +} + +static void +idle_step (void) +{ + demo_view_t *vu = static_vu; + if (vu->animate) { + next_frame (vu); + } + else + glutIdleFunc (NULL); +} + +static void +print_fps (int ms) +{ + demo_view_t *vu = static_vu; + if (vu->animate) { + glutTimerFunc (ms, print_fps, ms); + long t = current_time (); + LOGI ("%gfps\n", vu->num_frames * 1000. / (t - vu->fps_start_time)); + vu->num_frames = 0; + vu->fps_start_time = t; + } else + vu->has_fps_timer = false; +} + +static void +start_animation (demo_view_t *vu) +{ + vu->num_frames = 0; + vu->last_frame_time = vu->fps_start_time = current_time (); + //glutTimerFunc (1000/60, timed_step, 1000/60); + glutIdleFunc (idle_step); + if (!vu->has_fps_timer) { + vu->has_fps_timer = true; + glutTimerFunc (5000, print_fps, 5000); + } +} + +static void +demo_view_toggle_animation (demo_view_t *vu) +{ + vu->animate = !vu->animate; + if (vu->animate) + start_animation (vu); +} + + +static void +demo_view_toggle_vsync (demo_view_t *vu) +{ + vu->vsync = !vu->vsync; + LOGI ("Setting vsync %s.\n", vu->vsync ? "on" : "off"); +#if defined(__APPLE__) + CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &vu->vsync); +#elif defined(__WGLEW__) + if (wglewIsSupported ("WGL_EXT_swap_control")) + wglSwapIntervalEXT (vu->vsync); + else + LOGW ("WGL_EXT_swal_control not supported; failed to set vsync\n"); +#elif defined(__GLXEW_H__) + if (glxewIsSupported ("GLX_SGI_swap_control")) + glXSwapIntervalSGI (vu->vsync); + else + LOGW ("GLX_SGI_swap_control not supported; failed to set vsync\n"); +#else + LOGW ("No vsync extension found; failed to set vsync\n"); +#endif +} + +static void +demo_view_toggle_srgb (demo_view_t *vu) +{ + vu->srgb = !vu->srgb; + LOGI ("Setting sRGB framebuffer %s.\n", vu->srgb ? "on" : "off"); +#if defined(GL_FRAMEBUFFER_SRGB) && defined(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT) + GLboolean available = false; + if ((glewIsSupported ("GL_ARB_framebuffer_sRGB") || glewIsSupported ("GL_EXT_framebuffer_sRGB")) && + (glGetBooleanv (GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &available), available)) { + if (vu->srgb) + glEnable (GL_FRAMEBUFFER_SRGB); + else + glDisable (GL_FRAMEBUFFER_SRGB); + } else +#endif + LOGW ("No sRGB framebuffer extension found; failed to set sRGB framebuffer\n"); +} + +static void +demo_view_toggle_fullscreen (demo_view_t *vu) +{ + vu->fullscreen = !vu->fullscreen; + if (vu->fullscreen) { + vu->x = glutGet (GLUT_WINDOW_X); + vu->y = glutGet (GLUT_WINDOW_Y); + vu->width = glutGet (GLUT_WINDOW_WIDTH); + vu->height = glutGet (GLUT_WINDOW_HEIGHT); + glutFullScreen (); + } else { + glutReshapeWindow (vu->width, vu->height); + glutPositionWindow (vu->x, vu->y); + } +} + +static void +demo_view_toggle_debug (demo_view_t *vu) +{ + demo_glstate_toggle_debug (vu->st); +} + + +void +demo_view_reshape_func (demo_view_t *vu, int width, int height) +{ + glViewport (0, 0, width, height); + glutPostRedisplay (); +} + +#define STEP 1.05 +void +demo_view_keyboard_func (demo_view_t *vu, unsigned char key, int x, int y) +{ + switch (key) + { + case '\033': + case 'q': + exit (0); + break; + + case ' ': + demo_view_toggle_animation (vu); + break; + case 'v': + demo_view_toggle_vsync (vu); + break; + + case 'f': + demo_view_toggle_fullscreen (vu); + break; + + case 'd': + demo_view_toggle_debug (vu); + break; + + case 'o': + demo_view_toggle_outline (vu); + break; + case 'p': + demo_view_scale_outline_thickness (vu, STEP); + break; + case 'i': + demo_view_scale_outline_thickness (vu, 1. / STEP); + break; + + case '0': + demo_view_adjust_boldness (vu, +.01); + break; + case '9': + demo_view_adjust_boldness (vu, -.01); + break; + + + case 'a': + demo_view_scale_contrast (vu, STEP); + break; + case 'z': + demo_view_scale_contrast (vu, 1. / STEP); + break; + case 'g': + demo_view_scale_gamma_adjust (vu, STEP); + break; + case 'b': + demo_view_scale_gamma_adjust (vu, 1. / STEP); + break; + case 'c': + demo_view_toggle_srgb (vu); + break; + + case '=': + demo_view_scale (vu, STEP); + break; + case '-': + demo_view_scale (vu, 1. / STEP); + break; + + case 'k': + demo_view_translate (vu, 0, -.1); + break; + case 'j': + demo_view_translate (vu, 0, +.1); + break; + case 'h': + demo_view_translate (vu, +.1, 0); + break; + case 'l': + demo_view_translate (vu, -.1, 0); + break; + + case 'r': + demo_view_reset (vu); + break; + + default: + return; + } + glutPostRedisplay (); +} + +void +demo_view_special_func (demo_view_t *vu, int key, int x, int y) +{ + switch (key) + { + case GLUT_KEY_UP: + demo_view_translate (vu, 0, -.1); + break; + case GLUT_KEY_DOWN: + demo_view_translate (vu, 0, +.1); + break; + case GLUT_KEY_LEFT: + demo_view_translate (vu, +.1, 0); + break; + case GLUT_KEY_RIGHT: + demo_view_translate (vu, -.1, 0); + break; + + default: + return; + } + glutPostRedisplay (); +} + +void +demo_view_mouse_func (demo_view_t *vu, int button, int state, int x, int y) +{ + if (state == GLUT_DOWN) { + vu->buttons |= (1 << button); + vu->click_handled = false; + } else + vu->buttons &= !(1 << button); + vu->modifiers = glutGetModifiers (); + + switch (button) + { + case GLUT_RIGHT_BUTTON: + switch (state) { + case GLUT_DOWN: + if (vu->animate) { + demo_view_toggle_animation (vu); + vu->click_handled = true; + } + break; + case GLUT_UP: + if (!vu->animate) + { + if (!vu->dragged && !vu->click_handled) + demo_view_toggle_animation (vu); + else if (vu->dt) { + double speed = hypot (vu->dx, vu->dy) / vu->dt; + if (speed > 0.1) + demo_view_toggle_animation (vu); + } + vu->dx = vu->dy = vu->dt = 0; + } + break; + } + break; + +#if !defined(GLUT_WHEEL_UP) +#define GLUT_WHEEL_UP 3 +#define GLUT_WHEEL_DOWN 4 +#endif + + case GLUT_WHEEL_UP: + demo_view_scale (vu, STEP); + break; + + case GLUT_WHEEL_DOWN: + demo_view_scale (vu, 1. / STEP); + break; + } + + vu->beginx = vu->lastx = x; + vu->beginy = vu->lasty = y; + vu->dragged = false; + + glutPostRedisplay (); +} + +void +demo_view_motion_func (demo_view_t *vu, int x, int y) +{ + vu->dragged = true; + + int viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + GLuint width = viewport[2]; + GLuint height = viewport[3]; + + if (vu->buttons & (1 << GLUT_LEFT_BUTTON)) + { + if (vu->modifiers & GLUT_ACTIVE_SHIFT) { + /* adjust contrast/gamma */ + demo_view_scale_gamma_adjust (vu, 1 - ((y - vu->lasty) / height)); + demo_view_scale_contrast (vu, 1 + ((x - vu->lastx) / width)); + } else { + /* translate */ + demo_view_translate (vu, + +2 * (x - vu->lastx) / width, + -2 * (y - vu->lasty) / height); + } + } + + if (vu->buttons & (1 << GLUT_RIGHT_BUTTON)) + { + if (vu->modifiers & GLUT_ACTIVE_SHIFT) { + /* adjust perspective */ + demo_view_scale_perspective (vu, 1 - ((y - vu->lasty) / height) * 5); + } else { + /* rotate */ + float dquat[4]; + trackball (dquat, + (2.0*vu->lastx - width) / width, + ( height - 2.0*vu->lasty) / height, + ( 2.0*x - width) / width, + ( height - 2.0*y) / height ); + + vu->dx = x - vu->lastx; + vu->dy = y - vu->lasty; + vu->dt = current_time () - vu->lastt; + + add_quats (dquat, vu->quat, vu->quat); + + if (vu->dt) { + vcopy (dquat, vu->rot_axis); + vnormal (vu->rot_axis); + vu->rot_speed = 2 * acos (dquat[3]) / vu->dt; + } + } + } + + if (vu->buttons & (1 << GLUT_MIDDLE_BUTTON)) + { + /* scale */ + double factor = 1 - ((y - vu->lasty) / height) * 5; + demo_view_scale (vu, factor); + /* adjust translate so we scale centered at the drag-begin mouse position */ + demo_view_translate (vu, + +(2. * vu->beginx / width - 1) * (1 - factor), + -(2. * vu->beginy / height - 1) * (1 - factor)); + } + + vu->lastx = x; + vu->lasty = y; + vu->lastt = current_time (); + + glutPostRedisplay (); +} + +void +demo_view_print_help (demo_view_t *vu) +{ + LOGI ("Welcome to GLyphy demo\n"); +} + + +static void +advance_frame (demo_view_t *vu, long dtime) +{ + if (vu->animate) { + float dquat[4]; + axis_to_quat (vu->rot_axis, vu->rot_speed * dtime, dquat); + add_quats (dquat, vu->quat, vu->quat); + vu->num_frames++; + } +} + +void +demo_view_display (demo_view_t *vu, demo_buffer_t *buffer) +{ + long new_time = current_time (); + advance_frame (vu, new_time - vu->last_frame_time); + vu->last_frame_time = new_time; + + int viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + GLint width = viewport[2]; + GLint height = viewport[3]; + + + float mat[16]; + + m4LoadIdentity (mat); + + demo_view_apply_transform (vu, mat); + + // Buffer best-fit + glyphy_extents_t extents; + demo_buffer_extents (buffer, NULL, &extents); + double content_scale = .9 * std::min (width / (extents.max_x - extents.min_x), + height / (extents.max_y - extents.min_y)); + m4Scale (mat, content_scale, content_scale, 1); + // Center buffer + m4Translate (mat, + -(extents.max_x + extents.min_x) / 2., + -(extents.max_y + extents.min_y) / 2., 0); + + demo_glstate_set_matrix (vu->st, mat); + + glClearColor (1, 1, 1, 1); + glClear (GL_COLOR_BUFFER_BIT); + + demo_buffer_draw (buffer); + + glutSwapBuffers (); +} + +void +demo_view_setup (demo_view_t *vu) +{ + if (!vu->vsync) + demo_view_toggle_vsync (vu); + if (!vu->srgb) + demo_view_toggle_srgb (vu); + demo_glstate_setup (vu->st); +} diff --git a/viewer/demo-view.h b/viewer/demo-view.h @@ -0,0 +1,66 @@ +/* + * 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_VIEW_H +#define DEMO_VIEW_H + +#include "demo-common.h" +#include "demo-buffer.h" +#include "demo-glstate.h" + +typedef struct demo_view_t demo_view_t; + +demo_view_t * +demo_view_create (demo_glstate_t *st); + +demo_view_t * +demo_view_reference (demo_view_t *vu); + +void +demo_view_destroy (demo_view_t *vu); + + +void +demo_view_reset (demo_view_t *vu); + +void +demo_view_reshape_func (demo_view_t *vu, int width, int height); + +void +demo_view_keyboard_func (demo_view_t *vu, unsigned char key, int x, int y); + +void +demo_view_special_func (demo_view_t *view, int key, int x, int y); + +void +demo_view_mouse_func (demo_view_t *vu, int button, int state, int x, int y); + +void +demo_view_motion_func (demo_view_t *vu, int x, int y); + +void +demo_view_print_help (demo_view_t *vu); + +void +demo_view_display (demo_view_t *vu, demo_buffer_t *buffer); + +void +demo_view_setup (demo_view_t *vu); + + +#endif /* DEMO_VIEW_H */ diff --git a/viewer/demo-vshader-glsl.h b/viewer/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/viewer/matrix4x4.c b/viewer/matrix4x4.c @@ -0,0 +1,398 @@ +/* + * 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; +} diff --git a/viewer/matrix4x4.h b/viewer/matrix4x4.h @@ -0,0 +1,104 @@ +/* + * 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); + +#endif diff --git a/viewer/text.cxx b/viewer/text.cxx @@ -9,12 +9,8 @@ #include "text.h" text::text(af_unix *sock) : - socket(sock), - font(FTGLPixmapFont("DejaVuSansMono.ttf")) + socket(sock) { - if (font.Error()) - errx(1, "%s", "font error"); - assert(socket->read_all(num_tus) == 8); for (int i = 0; i < num_tus; i++) { @@ -29,15 +25,6 @@ text::text(af_unix *sock) : assert(socket->read_all(num_lines) == 8); execution_counts.resize(num_lines); } - - font.FaceSize(24); - - font.Render(file_name.c_str()); - int vertical = num_lines * 24; - for (auto &line : source_file_contents) { - font.Render(line.c_str(), line.size(), FTPoint(0, vertical, 0)); - vertical -= 24; - } } void @@ -69,14 +56,4 @@ text::idle() // Send response back uint8_t msg_type = 1; assert(socket->write_all(&msg_type, 1) == 1); - - int vertical = num_lines * 24; - for (auto &count : execution_counts) { - std::stringstream ss; - ss << count; - std::string s_count = ss.str(); - - font.Render(&s_count[0], s_count.size(), FTPoint(600, vertical, 0)); - vertical -= 24; - } } diff --git a/viewer/text.h b/viewer/text.h @@ -2,7 +2,6 @@ #define TEXT_H #include <vector> -#include <FTGL/ftgl.h> #include "af_unix.h" #include "draw.h" @@ -24,8 +23,6 @@ private: std::vector<std::string> source_file_contents; std::vector<uint64_t> execution_counts; - - FTGLPixmapFont font; }; #endif diff --git a/viewer/trackball.c b/viewer/trackball.c @@ -0,0 +1,337 @@ +#include <stdio.h> +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ +/* + * Trackball code: + * + * Implementation of a virtual trackball. + * Implemented by Gavin Bell, lots of ideas from Thant Tessman and + * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129. + * + * Vector manip code: + * + * Original code from: + * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli + * + * Much mucking with by: + * Gavin Bell + */ +#if defined(_WIN32) +#pragma warning (disable:4244) /* disable bogus conversion warnings */ +#endif +#include <math.h> +#include "trackball.h" + +/* + * This size should really be based on the distance from the center of + * rotation to the point on the object underneath the mouse. That + * point would then track the mouse as closely as possible. This is a + * simple example, though, so that is left as an Exercise for the + * Programmer. + */ +#define TRACKBALLSIZE (0.5f) + +/* + * Local function prototypes (not defined in trackball.h) + */ +static float tb_project_to_sphere(float, float, float); +static void normalize_quat(float [4]); + +void +vzero(float *v) +{ + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; +} + +void +vset(float *v, float x, float y, float z) +{ + v[0] = x; + v[1] = y; + v[2] = z; +} + +void +vsub(const float *src1, const float *src2, float *dst) +{ + dst[0] = src1[0] - src2[0]; + dst[1] = src1[1] - src2[1]; + dst[2] = src1[2] - src2[2]; +} + +void +vcopy(const float *v1, float *v2) +{ + register int i; + for (i = 0 ; i < 3 ; i++) + v2[i] = v1[i]; +} + +void +vcross(const float *v1, const float *v2, float *cross) +{ + float temp[3]; + + temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); + temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); + temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); + vcopy(temp, cross); +} + +float +vlength(const float *v) +{ + return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +} + +void +vscale(float *v, float div) +{ + v[0] *= div; + v[1] *= div; + v[2] *= div; +} + +void +vnormal(float *v) +{ + vscale(v,1.0/vlength(v)); +} + +float +vdot(const float *v1, const float *v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void +vadd(const float *src1, const float *src2, float *dst) +{ + dst[0] = src1[0] + src2[0]; + dst[1] = src1[1] + src2[1]; + dst[2] = src1[2] + src2[2]; +} + +/* + * Ok, simulate a track-ball. Project the points onto the virtual + * trackball, then figure out the axis of rotation, which is the cross + * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) + * Note: This is a deformed trackball-- is a trackball in the center, + * but is deformed into a hyperbolic sheet of rotation away from the + * center. This particular function was chosen after trying out + * several variations. + * + * It is assumed that the arguments to this routine are in the range + * (-1.0 ... 1.0) + */ +void +trackball(float q[4], float p1x, float p1y, float p2x, float p2y) +{ + float a[3]; /* Axis of rotation */ + float phi; /* how much to rotate about axis */ + float p1[3], p2[3], d[3]; + float t; + + if (p1x == p2x && p1y == p2y) { + /* Zero rotation */ + vzero(q); + q[3] = 1.0; + return; + } + + /* + * First, figure out z-coordinates for projection of P1 and P2 to + * deformed sphere + */ + vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y)); + vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y)); + + /* + * Now, we want the cross product of P1 and P2 + */ + vcross(p2,p1,a); + + /* + * Figure out how much to rotate around that axis. + */ + vsub(p1,p2,d); + t = vlength(d) / (2.0*TRACKBALLSIZE); + + /* + * Avoid problems with out-of-control values... + */ + if (t > 1.0) t = 1.0; + if (t < -1.0) t = -1.0; + phi = 2.0 * asin(t); + + axis_to_quat(a,phi,q); +} + +/* + * Given an axis and angle, compute quaternion. + */ +void +axis_to_quat(float a[3], float phi, float q[4]) +{ + vcopy(a,q); + vnormal(q); + vscale(q,sin(phi/2.0)); + q[3] = cos(phi/2.0); +} + +/* + * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet + * if we are away from the center of the sphere. + */ +static float +tb_project_to_sphere(float r, float x, float y) +{ + float d, t, z; + + d = sqrt(x*x + y*y); + if (d < r * 0.70710678118654752440) { /* Inside sphere */ + z = sqrt(r*r - d*d); + } else { /* On hyperbola */ + t = r / 1.41421356237309504880; + z = t*t / d; + } + return z; +} + +/* + * Given two rotations, e1 and e2, expressed as quaternion rotations, + * figure out the equivalent single rotation and stuff it into dest. + * + * This routine also normalizes the result every RENORMCOUNT times it is + * called, to keep error from creeping in. + * + * NOTE: This routine is written so that q1 or q2 may be the same + * as dest (or each other). + */ + +#define RENORMCOUNT 97 + +void +add_quats(float q1[4], float q2[4], float dest[4]) +{ + static int count=0; + float t1[4], t2[4], t3[4]; + float tf[4]; + +#if 0 +printf("q1 = %f %f %f %f\n", q1[0], q1[1], q1[2], q1[3]); +printf("q2 = %f %f %f %f\n", q2[0], q2[1], q2[2], q2[3]); +#endif + + vcopy(q1,t1); + vscale(t1,q2[3]); + + vcopy(q2,t2); + vscale(t2,q1[3]); + + vcross(q2,q1,t3); + vadd(t1,t2,tf); + vadd(t3,tf,tf); + tf[3] = q1[3] * q2[3] - vdot(q1,q2); + +#if 0 +printf("tf = %f %f %f %f\n", tf[0], tf[1], tf[2], tf[3]); +#endif + + dest[0] = tf[0]; + dest[1] = tf[1]; + dest[2] = tf[2]; + dest[3] = tf[3]; + + if (++count > RENORMCOUNT) { + count = 0; + normalize_quat(dest); + } +} + +/* + * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0 + * If they don't add up to 1.0, dividing by their magnitued will + * renormalize them. + * + * Note: See the following for more information on quaternions: + * + * - Shoemake, K., Animating rotation with quaternion curves, Computer + * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985. + * - Pletinckx, D., Quaternion calculus as a basic tool in computer + * graphics, The Visual Computer 5, 2-13, 1989. + */ +static void +normalize_quat(float q[4]) +{ + int i; + float mag; + + mag = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); + for (i = 0; i < 4; i++) q[i] /= mag; +} + +/* + * Build a rotation matrix, given a quaternion rotation. + * + */ +void +build_rotmatrix(float m[4][4], float q[4]) +{ + m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]); + m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]); + m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]); + m[0][3] = 0.0; + + m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]); + m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]); + m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]); + m[1][3] = 0.0; + + m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]); + m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]); + m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]); + m[2][3] = 0.0; + + m[3][0] = 0.0; + m[3][1] = 0.0; + m[3][2] = 0.0; + m[3][3] = 1.0; +} + diff --git a/viewer/trackball.h b/viewer/trackball.h @@ -0,0 +1,109 @@ +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ +/* + * trackball.h + * A virtual trackball implementation + * Written by Gavin Bell for Silicon Graphics, November 1988. + */ + +void +vzero(float *v); + +void +vset(float *v, float x, float y, float z); + +void +vsub(const float *src1, const float *src2, float *dst); + +void +vcopy(const float *v1, float *v2); + +void +vcross(const float *v1, const float *v2, float *cross); + +float +vlength(const float *v); + +void +vscale(float *v, float div); + +void +vnormal(float *v); + +float +vdot(const float *v1, const float *v2); + +void +vadd(const float *src1, const float *src2, float *dst); + + +/* + * Pass the x and y coordinates of the last and current positions of + * the mouse, scaled so they are from (-1.0 ... 1.0). + * + * The resulting rotation is returned as a quaternion rotation in the + * first paramater. + */ +void +trackball(float q[4], float p1x, float p1y, float p2x, float p2y); + +/* + * Given two quaternions, add them together to get a third quaternion. + * Adding quaternions to get a compound rotation is analagous to adding + * translations to get a compound translation. When incrementally + * adding rotations, the first argument here should be the new + * rotation, the second and third the total rotation (which will be + * over-written with the resulting new total rotation). + */ +void +add_quats(float *q1, float *q2, float *dest); + +/* + * A useful function, builds a rotation matrix in Matrix based on + * given quaternion. + */ +void +build_rotmatrix(float m[4][4], float q[4]); + +/* + * This function computes a quaternion based on an axis (defined by + * the given vector) and an angle about which to rotate. The angle is + * expressed in radians. The result is put into the third argument. + */ +void +axis_to_quat(float a[3], float phi, float q[4]); + diff --git a/viewer/viewer.cxx b/viewer/viewer.cxx @@ -3,12 +3,16 @@ #include <iostream> #include <vector> -#include <GL/glew.h> -#include <GL/freeglut.h> - #include "af_unix.h" #include "text.h" +#include "demo-buffer.h" +#include "demo-font.h" +#include "demo-view.h" + +demo_glstate_t *st; +demo_view_t *vu; +demo_buffer_t *buffer; class window { public: @@ -20,7 +24,13 @@ private: static std::vector<drawable*> drawables; static af_unix socket; static void display(); + static void reshape_func(int, int); + static void keyboard_func(unsigned char, int, int); + static void special_func(int, int, int); + static void mouse_func(int, int, int, int); + static void motion_func(int, int); static void idle(); + }; // fuckin c++ @@ -30,55 +40,89 @@ af_unix window::socket; window::window(int argc, char *argv[]) { glutInit(&argc, argv); - glutInitContextVersion(2, 0); - glutInitDisplayMode(GLUT_RGB); glutInitWindowSize(1600, 1200); - glutCreateWindow("Basic Text"); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); + int window = glutCreateWindow("Source Code Visualizer"); + glutReshapeFunc(reshape_func); + glutDisplayFunc(display); + glutKeyboardFunc(keyboard_func); + glutSpecialFunc(special_func); + glutMouseFunc(mouse_func); + glutMotionFunc(motion_func); + glutIdleFunc(idle); GLenum glew_status = glewInit(); - if (GLEW_OK != glew_status) errx(1, "%s", glewGetErrorString(glew_status)); - - if (!GLEW_VERSION_2_0) + if (!glewIsSupported("GL_VERSION_2_0")) errx(1, "No support for OpenGL 2.0 found"); - glutDisplayFunc(window::display); - glutIdleFunc(idle); + st = demo_glstate_create(); + vu = demo_view_create(st); + demo_view_print_help(vu); + + FT_Library ft_library; + FT_Init_FreeType(&ft_library); + + FT_Face ft_face = NULL; + FT_New_Face(ft_library, "DejaVuSansMono.ttf", /* face_index */ 0, &ft_face); + + demo_font_t *font = demo_font_create(ft_face, demo_glstate_get_atlas(st)); + + buffer = demo_buffer_create(); + glyphy_point_t top_left = { 0, 0 }; + demo_buffer_move_to(buffer, &top_left); + const char *the_text = ">>>>>>> HELLO WORLD <<<<<<<<"; + demo_buffer_add_text(buffer, the_text, font, 1); + + demo_font_print_stats(font); + + demo_view_setup(vu); // This creates the socket with SOCK_NONBLOCK socket.set_listen(); } void -window::start() +window::reshape_func(int width, int height) { - glutMainLoop(); + demo_view_reshape_func(vu, width, height); } void -window::add(drawable &d) +window::keyboard_func(unsigned char key, int x, int y) { - drawables.push_back(&d); + demo_view_keyboard_func(vu, key, x, y); } void -window::display(void) +window::special_func(int key, int x, int y) { - /* White background */ - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); + demo_view_special_func(vu, key, x, y); +} - /* Enable blending, necessary for our alpha texture */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +void +window::mouse_func(int button, int state, int x, int y) +{ + demo_view_mouse_func(vu, button, state, x, y); +} - for (auto &d : drawables) - d->draw(); +void +window::motion_func(int x, int y) +{ + demo_view_motion_func(vu, x, y); +} - std::cerr << "window__display" << std::endl; +void +window::start() +{ + glutMainLoop(); +} - glutSwapBuffers(); +void +window::display(void) +{ + demo_view_display(vu, buffer); } void