Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Romanov <a.romanov@blend4web.com>2016-04-08 10:58:40 +0300
committerAlexander Romanov <a.romanov@blend4web.com>2016-04-08 10:58:40 +0300
commitd969192fbe6129021f0399cc35c6c2be6aa72eda (patch)
tree741562b7728eee95105425d260ef150236c8c97c
parenta51e9ece538fb00c939ccaca7d6fbb1fe491bf10 (diff)
Wide lines + line stipple deprecated API replacement
The patch contains an implementation of the wide lines and the line stipple that is necessary for OpenGL upgrade. For the implementation I have chosen the geometry shader because it required minimum changes for the wrapper calls and such implementation is the best for the "basic shader" architecture. There are few shortcomings that can be corrected in future. They all are related to the fact that the lines in one strip are not connected with each other. So the stipple pattern is not continuous on the common vertex of two lines. There is also no continuity of form (each line is an independent rectangular). But the advantage is that even outdated glBegin, glVertex work! Though with the above restrictions. Continuity of form and stipple can be implemented with additional attributes, and it will require more changes in calls. At the moment, the patch replaces calls for some "gestures". It works satisfactorily for "cross" or "rectangular" and not so good for "lasso" and "circle" due to the above-mentioned shortcomings. Don't forget to set USE_GLSL to true for testing. Alexander Romanov (Blend4Web Team) Reviewers: merwin, brecht Reviewed By: merwin, brecht Subscribers: aligorith, Evgeny_Rodygin, AlexKowel, yurikovelenov Differential Revision: https://developer.blender.org/D1880
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/GPU_basic_shader.h6
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c65
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_geom.glsl100
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_vert.glsl8
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c1
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c44
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c1
9 files changed, 210 insertions, 31 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 3b228c18f5e..cfa083116f2 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -73,6 +73,7 @@ set(SRC
shaders/gpu_shader_sep_gaussian_blur_vert.glsl
shaders/gpu_shader_basic_frag.glsl
shaders/gpu_shader_basic_vert.glsl
+ shaders/gpu_shader_basic_geom.glsl
shaders/gpu_shader_vertex.glsl
shaders/gpu_shader_vsm_store_frag.glsl
shaders/gpu_shader_vsm_store_vert.glsl
@@ -105,6 +106,7 @@ data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_basic_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_basic_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_basic_geom.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC)
diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h
index f376850a8f9..df2da971845 100644
--- a/source/blender/gpu/GPU_basic_shader.h
+++ b/source/blender/gpu/GPU_basic_shader.h
@@ -33,6 +33,7 @@
#define __GPU_BASIC_SHADER_H__
#include "BLI_utildefines.h"
+#include "GPU_glew.h"
#ifdef __cplusplus
extern "C" {
@@ -48,7 +49,8 @@ typedef enum GPUBasicShaderOption {
GPU_SHADER_SOLID_LIGHTING = (1 << 4), /* use faster lighting (set automatically) */
GPU_SHADER_STIPPLE = (1 << 5), /* use stipple */
- GPU_SHADER_OPTIONS_NUM = 6,
+ GPU_SHADER_LINE = (1 << 6), /* draw lines */
+ GPU_SHADER_OPTIONS_NUM = 7,
GPU_SHADER_OPTION_COMBINATIONS = (1 << GPU_SHADER_OPTIONS_NUM)
} GPUBasicShaderOption;
@@ -105,6 +107,8 @@ typedef struct GPULightData {
void GPU_basic_shader_light_set(int light_num, GPULightData *light);
void GPU_basic_shader_light_set_viewer(bool local);
void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id);
+void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern);
+void GPU_basic_shader_line_width(float line_width);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
index 4a27965aee1..abaf1944302 100644
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -61,6 +61,8 @@ static struct {
int lights_enabled;
int lights_directional;
+ float line_width;
+ GLint viewport[4];
} GPU_MATERIAL_STATE;
@@ -325,6 +327,8 @@ static GPUShader *gpu_basic_shader(int options)
/* glsl code */
extern char datatoc_gpu_shader_basic_vert_glsl[];
extern char datatoc_gpu_shader_basic_frag_glsl[];
+ extern char datatoc_gpu_shader_basic_geom_glsl[];
+ char *geom_glsl = NULL;
GPUShader *shader;
/* detect if we can do faster lighting for solid draw mode */
@@ -347,7 +351,10 @@ static GPUShader *gpu_basic_shader(int options)
strcat(defines, "#define USE_TEXTURE\n");
if (options & GPU_SHADER_STIPPLE)
strcat(defines, "#define USE_STIPPLE\n");
-
+ if (options & GPU_SHADER_LINE) {
+ strcat(defines, "#define DRAW_LINE\n");
+ geom_glsl = datatoc_gpu_shader_basic_geom_glsl;
+ }
if (options & GPU_SHADER_SOLID_LIGHTING)
strcat(defines, "#define USE_SOLID_LIGHTING\n");
else if (options & GPU_SHADER_LIGHTING)
@@ -356,7 +363,7 @@ static GPUShader *gpu_basic_shader(int options)
shader = GPU_shader_create(
datatoc_gpu_shader_basic_vert_glsl,
datatoc_gpu_shader_basic_frag_glsl,
- NULL,
+ geom_glsl,
NULL,
defines, 0, 0, 0);
@@ -377,6 +384,15 @@ static GPUShader *gpu_basic_shader(int options)
return shader;
}
+static void GPU_basic_shader_uniform_autoset(GPUShader *shader, int options)
+{
+ if (options & GPU_SHADER_LINE) {
+ glGetIntegerv(GL_VIEWPORT, &GPU_MATERIAL_STATE.viewport[0]);
+ glUniform4iv(GPU_shader_get_uniform(shader, "viewport"), 1, &GPU_MATERIAL_STATE.viewport[0]);
+ glUniform1f(GPU_shader_get_uniform(shader, "line_width"), GPU_MATERIAL_STATE.line_width);
+ }
+}
+
/* Bind / unbind */
void GPU_basic_shader_bind(int options)
@@ -385,8 +401,10 @@ void GPU_basic_shader_bind(int options)
if (options) {
GPUShader *shader = gpu_basic_shader(options);
- if (shader)
+ if (shader) {
GPU_shader_bind(shader);
+ GPU_basic_shader_uniform_autoset(shader, options);
+ }
}
else {
GPU_shader_unbind();
@@ -424,10 +442,19 @@ void GPU_basic_shader_bind(int options)
glDisable(GL_TEXTURE_2D);
}
- if (options & GPU_SHADER_STIPPLE)
- glEnable(GL_POLYGON_STIPPLE);
- else if (bound_options & GPU_SHADER_STIPPLE)
- glDisable(GL_POLYGON_STIPPLE);
+ if (options & GPU_SHADER_LINE) {
+ if (options & GPU_SHADER_STIPPLE)
+ glEnable(GL_LINE_STIPPLE);
+ else if (bound_options & GPU_SHADER_STIPPLE)
+ glDisable(GL_LINE_STIPPLE);
+ }
+ else {
+ if (options & GPU_SHADER_STIPPLE)
+ glEnable(GL_POLYGON_STIPPLE);
+ else if (bound_options & GPU_SHADER_STIPPLE)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+
}
GPU_MATERIAL_STATE.bound_options = options;
@@ -592,3 +619,27 @@ void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id)
}
}
}
+
+void GPU_basic_shader_line_width(float line_width)
+{
+ if (USE_GLSL) {
+ GPU_MATERIAL_STATE.line_width = line_width;
+ if (GPU_MATERIAL_STATE.bound_options & GPU_SHADER_LINE) {
+ glUniform1f(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "line_width"), line_width);
+ }
+ }
+ else {
+ glLineWidth(line_width);
+ }
+}
+
+void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern)
+{
+ if (USE_GLSL) {
+ glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_factor"), stipple_factor);
+ glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_pattern"), stipple_pattern);
+ }
+ else {
+ glLineStipple(stipple_factor, stipple_pattern);
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
index 7b4df51c12d..c7b29ee5707 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
@@ -45,11 +45,20 @@ uniform sampler2D texture_map;
#ifdef USE_STIPPLE
uniform int stipple_id;
+#if defined(DRAW_LINE)
+varying in float t;
+uniform int stipple_pattern;
+#endif
#endif
void main()
{
#if defined(USE_STIPPLE)
+#if defined(DRAW_LINE)
+ /* GLSL 1.3 */
+ if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
+ discard;
+#else
/* We have to use mod function and integer casting.
* This can be optimized further with the bitwise operations
* when GLSL 1.3 is supported. */
@@ -123,9 +132,8 @@ void main()
discard;
}
}
-
-
-#endif
+#endif /* !DRAW_LINE */
+#endif /* USE_STIPPLE */
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
/* compute normal */
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
new file mode 100644
index 00000000000..ffd747ab1eb
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
@@ -0,0 +1,100 @@
+/*
+* Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
+*/
+
+#define PASSTHROUGH 0
+
+layout(lines) in;
+
+#if defined(DRAW_LINE)
+
+#if PASSTHROUGH
+layout(line_strip, max_vertices = 10) out;
+#else
+layout(triangle_strip, max_vertices = 6) out;
+#endif
+
+varying out float t;
+varying in vec4 varying_vertex_color_line[];
+varying out vec4 varying_vertex_color;
+
+uniform ivec4 viewport;
+uniform float line_width;
+uniform int stipple_factor;
+
+void main(void)
+{
+ vec2 window_size = viewport.zw;
+ vec4 start = gl_in[0].gl_Position;
+ vec4 end = gl_in[1].gl_Position;
+#if PASSTHROUGH
+ gl_Position = start; EmitVertex();
+ gl_Position = end; EmitVertex();
+ EndPrimitive();
+ return;
+#endif
+
+/* t = 0 t = ~(len(end - start) + 2*line_width)
+ * A-------------------------------------B
+ * | | | |
+ * | side | |
+ * | | | |
+ * |--axis--*start--------------*end-----|
+ * | | | |
+ * | | | |
+ * | | | |
+ * D-------------------------------------C
+ */
+
+ /* Clip the line before homogenization.
+ * Compute line start and end distances to nearplane in clipspace
+ * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
+ */
+ float t0 = start.z + start.w;
+ float t1 = end.z + end.w;
+ if(t0 < 0.0) {
+ if(t1 < 0.0) {
+ return;
+ }
+ start = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+ if(t1 < 0.0) {
+ end = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+
+ /* Compute line axis and side vector in screen space */
+ vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
+ vec2 endInNDC = end.xy / end.w;
+ vec2 lineInNDC = endInNDC - startInNDC;
+ vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
+
+ vec2 axisInScreen = normalize(lineInScreen);
+ vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
+ vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
+ vec2 sideInNDC = sideInScreen / window_size;
+ vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
+ vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
+
+ vec4 A = (start + (side - axis) * start.w);
+ vec4 B = (end + (side + axis) * end.w);
+ vec4 C = (end - (side - axis) * end.w);
+ vec4 D = (start - (side + axis) * start.w);
+
+ /* There is no relation between lines yet */
+ /* TODO Pass here t0 to make continuous pattern. */
+ t0 = 0;
+ t1 = (length(lineInScreen) + 2*line_width)/ (2*line_width * stipple_factor);
+
+ gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ EndPrimitive();
+}
+
+#else
+void main(void)
+{
+
+}
+#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
index 8ccd0feb5e2..04900001998 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
@@ -8,8 +8,12 @@ varying vec3 varying_position;
#endif
#ifdef USE_COLOR
+#ifdef DRAW_LINE
+varying vec4 varying_vertex_color_line;
+#else
varying vec4 varying_vertex_color;
#endif
+#endif
#ifdef USE_TEXTURE
varying vec2 varying_texture_coord;
@@ -44,8 +48,12 @@ void main()
#endif
#ifdef USE_COLOR
+#ifdef DRAW_LINE
+ varying_vertex_color_line = gl_Color;
+#else
varying_vertex_color = gl_Color;
#endif
+#endif
#ifdef USE_TEXTURE
varying_texture_coord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).st;
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index d20cffe9382..f8a879d0485 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -59,6 +59,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
+#include "GPU_basic_shader.h"
#include "RE_engine.h"
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 92c9b81cdef..26d1d4c3266 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -51,6 +51,7 @@
#include "wm.h"
#include "wm_subwindow.h"
#include "wm_draw.h"
+#include "GPU_basic_shader.h"
#include "BIF_glutil.h"
@@ -180,29 +181,29 @@ static void wm_gesture_draw_rect(wmGesture *gt)
glEnd();
glDisable(GL_BLEND);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xCCCC);
+ GPU_basic_shader_line_stipple(1, 0xCCCC);
sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x3333);
+ GPU_basic_shader_line_stipple(1, 0x3333);
sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
static void wm_gesture_draw_line(wmGesture *gt)
{
rcti *rect = (rcti *)gt->customdata;
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x5555);
+ GPU_basic_shader_line_stipple(1, 0x5555);
sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
@@ -217,15 +218,16 @@ static void wm_gesture_draw_circle(wmGesture *gt)
glutil_draw_filled_arc(0.0, M_PI * 2.0, rect->xmax, 40);
glDisable(GL_BLEND);
- glEnable(GL_LINE_STIPPLE);
+ // for USE_GLSL works bad because of no relation between lines
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x5555);
+ GPU_basic_shader_line_stipple(1, 0x5555);
glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
glTranslatef(-rect->xmin, -rect->ymin, 0.0f);
}
@@ -303,9 +305,10 @@ static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
draw_filled_lasso(win, gt);
}
- glEnable(GL_LINE_STIPPLE);
+ // for USE_GLSL can't check this yet
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
glBegin(GL_LINE_STRIP);
for (i = 0; i < gt->points; i++, lasso += 2)
glVertex2sv(lasso);
@@ -314,7 +317,7 @@ static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
glEnd();
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x5555);
+ GPU_basic_shader_line_stipple(1, 0x5555);
glBegin(GL_LINE_STRIP);
lasso = (short *)gt->customdata;
for (i = 0; i < gt->points; i++, lasso += 2)
@@ -323,7 +326,7 @@ static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
glVertex2sv((short *)gt->customdata);
glEnd();
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
@@ -333,17 +336,17 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xCCCC);
+ GPU_basic_shader_line_stipple(1, 0xCCCC);
sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x3333);
+ GPU_basic_shader_line_stipple(1, 0x3333);
sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
/* called in wm_draw.c */
@@ -351,6 +354,7 @@ void wm_gesture_draw(wmWindow *win)
{
wmGesture *gt = (wmGesture *)win->gesture.first;
+ GPU_basic_shader_line_width(1);
for (; gt; gt = gt->next) {
/* all in subwindow space */
wmSubWindowSet(win, gt->swinid);
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 243f7467f25..6526d419914 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -48,6 +48,7 @@
#include "BIF_gl.h"
#include "GPU_extensions.h"
+#include "GPU_basic_shader.h"
#include "WM_api.h"
#include "wm_subwindow.h"