Compare commits
126 Commits
Author | SHA1 | Date | |
---|---|---|---|
5dfd86ebe7 | |||
9e41f687a0 | |||
61356caa06 | |||
4300f1f91d | |||
d26dc4ae44 | |||
bd45a00fa3 | |||
793a9d45e1 | |||
43295bdcc4 | |||
43e12dab7b | |||
c4535fdf85 | |||
d2c3272eb7 | |||
90c4b6492f | |||
b7bf42e778 | |||
e849667be6 | |||
424016d66c | |||
a4f55d4986 | |||
1b33a5a3a7 | |||
36111270aa | |||
6e0cfd3e55 | |||
5671f0a284 | |||
a7e63bea6c | |||
94b3c334e5 | |||
efb0addb62 | |||
988da215c8 | |||
551a57ed7f | |||
b7366b5b53 | |||
5e8d8b9ade | |||
4726f3d5d3 | |||
91ef7515de | |||
317f6c0910 | |||
6a3d521466 | |||
1363246d44 | |||
0b6560fac4 | |||
d4c3870286 | |||
4bdf9a1e70 | |||
1909977a67 | |||
655a783891 | |||
a4596becc4 | |||
7015bb3efd | |||
d2c762cc66 | |||
04d429b743 | |||
0b21dcfe08 | |||
7c939d78c2 | |||
8a2b82897d | |||
e95c365cf0 | |||
a32cb7133b | |||
967966cdee | |||
06d67b6abf | |||
f15ce01e2b | |||
e48516679c | |||
65a6c4c361 | |||
b51c468c0f | |||
2e7d02f1ce | |||
dc4fe780f7 | |||
d682cdb078 | |||
ff7a42b8bc | |||
4b1805c306 | |||
03c00e4944 | |||
cb05b16414 | |||
b9fe9c736a | |||
3dd8861fbf | |||
753066598f | |||
3da8c1bfdc | |||
f8ee974628 | |||
f36120757f | |||
bc178b711f | |||
5dad87cfb9 | |||
0f8f607e4c | |||
282aada13a | |||
47002bf0cd | |||
3d47c7edc1 | |||
bc350f37f5 | |||
b55e2e1df9 | |||
43baf643d4 | |||
21b8ae10b8 | |||
425a10de11 | |||
d0ef660ff6 | |||
506e06589b | |||
1d75d5aa2f | |||
645d596f9d | |||
3e967d731a | |||
167fd07e01 | |||
fbd6366edd | |||
23d0bdd46d | |||
0d0834f87c | |||
676997e0af | |||
633d5d1b84 | |||
f620f43353 | |||
eb6e1f694a | |||
6aead84d7a | |||
5b984c1e53 | |||
7660ca2579 | |||
ac52631e8a | |||
5b30a52bbd | |||
a5294ce55f | |||
553372ffb7 | |||
f672d6ee3b | |||
ba3417667f | |||
50fa002a19 | |||
f0718c7d95 | |||
e74c2e42cf | |||
ce64ab5449 | |||
8df3b21a51 | |||
08431a127a | |||
3f068d1138 | |||
6f0e5b0b56 | |||
fe27a6ea3b | |||
1301770dcb | |||
1551b6d386 | |||
a6f94696e2 | |||
c389aadff9 | |||
37eda498f2 | |||
7d2df52336 | |||
5d27e5415d | |||
625773fba4 | |||
7d79ae7b07 | |||
5817779656 | |||
5f5ce08ba4 | |||
223f033780 | |||
50e0ae3cf3 | |||
a8f6cada88 | |||
7f488e3e1d | |||
059d2144b2 | |||
902302a174 | |||
f98ca7683c | |||
479fb0549c |
@ -1,4 +1,4 @@
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||
|
||||
stages:
|
||||
- review
|
||||
|
@ -1,32 +1,27 @@
|
||||
# Rebuild and push with
|
||||
#
|
||||
# cd .gitlab-ci/
|
||||
# podman build --format docker --no-cache -t registry.gitlab.gnome.org/gnome/mutter/master:v3 .
|
||||
# podman push registry.gitlab.gnome.org/gnome/mutter/master:v3
|
||||
# podman build --format docker --no-cache -t registry.gitlab.gnome.org/gnome/mutter/master:v4 .
|
||||
# podman push registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||
#
|
||||
|
||||
FROM fedora:31
|
||||
FROM fedora:32
|
||||
|
||||
RUN dnf -y update && dnf -y upgrade && \
|
||||
dnf install -y 'dnf-command(builddep)' && \
|
||||
dnf install -y 'dnf-command(copr)' && \
|
||||
dnf copr enable -y fmuellner/gnome-shell-ci && \
|
||||
dnf copr enable -y jadahl/mutter-ci && \
|
||||
dnf -y update && dnf -y upgrade && \
|
||||
|
||||
dnf builddep -y mutter && \
|
||||
|
||||
# Until Fedora catches up with new build-deps
|
||||
dnf install -y 'pkgconfig(graphene-gobject-1.0)' 'pkgconfig(sysprof-capture-3)' && \
|
||||
dnf builddep -y mutter --setopt=install_weak_deps=False && \
|
||||
|
||||
# For running unit tests
|
||||
dnf install -y xorg-x11-server-Xvfb mesa-dri-drivers dbus dbus-x11 '*/xvfb-run' gdm-lib accountsservice-libs gnome-control-center && \
|
||||
dnf install -y xorg-x11-server-Xvfb mesa-dri-drivers dbus dbus-x11 \
|
||||
'*/xvfb-run' gdm-lib accountsservice-libs gnome-control-center \
|
||||
--setopt=install_weak_deps=False && \
|
||||
|
||||
# GNOME Shell
|
||||
dnf builddep -y gnome-shell --setopt=install_weak_deps=False && \
|
||||
dnf remove -y gnome-bluetooth-libs-devel dbus-glib-devel upower-devel python3-devel && \
|
||||
dnf remove -y gnome-bluetooth-libs-devel && \
|
||||
dnf remove -y --noautoremove mutter mutter-devel && \
|
||||
|
||||
dnf upgrade -y 'pkgconfig(libpipewire-0.3)' && \
|
||||
|
||||
dnf clean all
|
||||
|
64
NEWS
64
NEWS
@ -1,45 +1,35 @@
|
||||
3.36.1
|
||||
3.37.1
|
||||
======
|
||||
* Fix hardware cursor on GPU hotplpug [Pekka; !1097]
|
||||
* Fix black areas around XWayland windows when resizing [Robert, Olivier; !1091]
|
||||
* Fix applying wrong scale to monitors on X11 [Jonas; !1118]
|
||||
* Fix moving/resizing windows via keyboard on wayland [Alynx; !997]
|
||||
* Fix locate-pointer feature interfering with keybindings [Carlos; !1014]
|
||||
* Add support for middle-click emulation [Andrew; !256]
|
||||
* Fix freeze when moving cursor between scaled monitors [Robert; !1125]
|
||||
* Fix popup misplacement with focus-follows-mouse [Jonas Å.; !1122]
|
||||
* Fix misplaced cursor in preedit strings [Carlos; !1132]
|
||||
* Support mirroring with proprietary Nvidia driver [Jonas Å.; !1098]
|
||||
* Support tablets with multiple mode switch buttons in a group [Carlos; !970]
|
||||
* Ignore foreground color for color glyphs (emojis) [Carlos; !1148]
|
||||
* Allow pad mode switches while showing OSD [Carlos; !975]
|
||||
* Fix positioning of OSD for display-attached tablets [Carlos; !971]
|
||||
* Respect configured RANDR panning on X11 [Jonas Å.; !1085]
|
||||
* Use correct texture filtering with scaled displays [Jonas; !1124]
|
||||
* Fix cursor hotspots in virtual machines [Jonas Å.; !1136]
|
||||
* Fix build with GLES and no GL [Georges; !1151]
|
||||
* Work around Firefox bug when copying images on wayland [Robert; !1141]
|
||||
* Fix wrong cursor rotation on rotated displays [Hans; !1153]
|
||||
* Fix glitches in window screencasts [Georges; !1129]
|
||||
* Fix IM support for deleting surrounding text [Takao, Carlos; #539]
|
||||
* Fix map animation of maximized windows [Robert; !1164]
|
||||
* Fixed crashes [Jonas Å., Carlos, Florian, Robert; !1120, !1121,
|
||||
#917, #1132, #1083, !1147, #1147]
|
||||
* Misc. bug fixes and cleanups [Jonas Å., Olivier, Mart, Sebastian, Corentin,
|
||||
Andre, Daniel, Robert, Carlos, Peter, Georges, Jonas D., Florian, Christian;
|
||||
!1115, !1102, !1104, !1106, !1117, !1119, !1101, !1123, #1124, !1130, !1131,
|
||||
!1133, #1065, !1108, !1144, !1145, !1109, !1059, !1107, !999, !1152, #1128,
|
||||
!1155, !1156, !1158, !1157, #1146, !1161, !1163]
|
||||
* Fix screencasting non-maximized windows [Jonas Å.; !1174]
|
||||
* Make window-aliveness checks less aggressive [Jonas Å.; !1182]
|
||||
* Fix stylus coordinates when using screen rotation [Jonas T.; #1118]
|
||||
* Preserve keyboard state on VT switch [Olivier; !1185]
|
||||
* Remove Clutter's drag and drop actions [Jonas D.; !789]
|
||||
* Cancel clicks/gestures actions on disable [Georges; !1188]
|
||||
* Fix various clipboard issues [Carlos; !1186, !1198, !1203, !1204, !1206]
|
||||
* Fix trackball button scrolling [Phillip; #1120]
|
||||
* Fix tiled monitor support [Jonas; !1199]
|
||||
* Support unredirecting fullscreen wayland surfaces [Jonas Å.; !798]
|
||||
* Support area screencasts [Jonas Å.; !1207]
|
||||
* Synchronize shadows to server-side decorations [Olivier; !1214]
|
||||
* Allow inhibiting remote access [Jonas Å.; !1212]
|
||||
* Fix overview key on X11 when using multiple keyboard layouts [Olivier; !1219]
|
||||
* Fixed crashes [Jonas, D., Carlos; !1173, !1183, !1012]
|
||||
* Misc. bug fixes and cleanups [Andre, Georges, Christian, Jonas Å., Andre,
|
||||
Simon, Florian, Carlos, Adam, Marco, Thomas, Elias, Pekka, Jonas D.,
|
||||
Laurent; !1169, !1168, !1166, !1170, !1167, !1172, !1175, !1176, !1184,
|
||||
!1126, !1187, !1191, !1195, !1179, !1200, !1193, !1209, !1213, !1208,
|
||||
#1074, !1223]
|
||||
|
||||
Contributors:
|
||||
Jonas Dreßler, Olivier Fourdan, Takao Fujiwara, Carlos Garnacho, Andrew Gaul,
|
||||
Hans de Goede, Peter Hutterer, Sebastian Keller, Robert Mader,
|
||||
Andre Moreira Magalhaes, Florian Müllner, Georges Basile Stavracas Neto,
|
||||
Corentin Noël, Pekka Paalanen, Christian Rauch, Mart Raudsepp,
|
||||
Daniel van Vugt, Alynx Zhou, Jonas Ådahl
|
||||
Marco Trevisan (Treviño), Elias Aebi, Thomas Hindoe Paaboel Andersen,
|
||||
Laurent Bigonville, Jonas Dreßler, Olivier Fourdan, Carlos Garnacho,
|
||||
Adam Jackson, Andre Moreira Magalhaes, Simon McVittie, Florian Müllner,
|
||||
Georges Basile Stavracas Neto, Pekka Paalanen, Christian Rauch, Jonas Troeger,
|
||||
Phillip Wood, Jonas Ådahl
|
||||
|
||||
Translators:
|
||||
Марко Костић [sr], Daniel Șerbănescu [ro]
|
||||
Dušan Kazik [sk], Christian Kirbach [de]
|
||||
|
||||
3.36.0
|
||||
======
|
||||
|
@ -88,6 +88,10 @@ static void
|
||||
clutter_actor_meta_real_set_actor (ClutterActorMeta *meta,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
g_warn_if_fail (!meta->priv->actor ||
|
||||
!CLUTTER_ACTOR_IN_PAINT (meta->priv->actor));
|
||||
g_warn_if_fail (!actor || !CLUTTER_ACTOR_IN_PAINT (actor));
|
||||
|
||||
if (meta->priv->actor == actor)
|
||||
return;
|
||||
|
||||
@ -101,6 +105,18 @@ clutter_actor_meta_real_set_actor (ClutterActorMeta *meta,
|
||||
meta);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_actor_meta_real_set_enabled (ClutterActorMeta *meta,
|
||||
gboolean is_enabled)
|
||||
{
|
||||
g_warn_if_fail (!meta->priv->actor ||
|
||||
!CLUTTER_ACTOR_IN_PAINT (meta->priv->actor));
|
||||
|
||||
meta->priv->is_enabled = is_enabled;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_ENABLED]);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_actor_meta_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
@ -172,6 +188,7 @@ clutter_actor_meta_class_init (ClutterActorMetaClass *klass)
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
klass->set_actor = clutter_actor_meta_real_set_actor;
|
||||
klass->set_enabled = clutter_actor_meta_real_set_enabled;
|
||||
|
||||
/**
|
||||
* ClutterActorMeta:actor:
|
||||
@ -298,9 +315,7 @@ clutter_actor_meta_set_enabled (ClutterActorMeta *meta,
|
||||
if (meta->priv->is_enabled == is_enabled)
|
||||
return;
|
||||
|
||||
meta->priv->is_enabled = is_enabled;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_ENABLED]);
|
||||
CLUTTER_ACTOR_META_GET_CLASS (meta)->set_enabled (meta, is_enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,6 +87,9 @@ struct _ClutterActorMetaClass
|
||||
void (* set_actor) (ClutterActorMeta *meta,
|
||||
ClutterActor *actor);
|
||||
|
||||
void (* set_enabled) (ClutterActorMeta *meta,
|
||||
gboolean is_enabled);
|
||||
|
||||
/*< private >*/
|
||||
void (* _clutter_meta1) (void);
|
||||
void (* _clutter_meta2) (void);
|
||||
@ -94,7 +97,6 @@ struct _ClutterActorMetaClass
|
||||
void (* _clutter_meta4) (void);
|
||||
void (* _clutter_meta5) (void);
|
||||
void (* _clutter_meta6) (void);
|
||||
void (* _clutter_meta7) (void);
|
||||
};
|
||||
|
||||
CLUTTER_EXPORT
|
||||
|
@ -2410,6 +2410,7 @@ clutter_actor_should_pick_paint (ClutterActor *self)
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
||||
|
||||
if (CLUTTER_ACTOR_IS_MAPPED (self) &&
|
||||
clutter_actor_has_allocation (self) &&
|
||||
(_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
|
||||
CLUTTER_ACTOR_IS_REACTIVE (self)))
|
||||
return TRUE;
|
||||
@ -3865,14 +3866,7 @@ clutter_actor_paint_node (ClutterActor *actor,
|
||||
|
||||
fb = clutter_paint_context_get_base_framebuffer (paint_context);
|
||||
|
||||
if (clutter_stage_get_use_alpha (CLUTTER_STAGE (actor)))
|
||||
{
|
||||
bg_color.alpha = priv->opacity
|
||||
* priv->bg_color.alpha
|
||||
/ 255;
|
||||
}
|
||||
else
|
||||
bg_color.alpha = 255;
|
||||
bg_color.alpha = 255;
|
||||
|
||||
CLUTTER_NOTE (PAINT, "Stage clear color: (%d, %d, %d, %d)",
|
||||
bg_color.red,
|
||||
@ -19966,6 +19960,23 @@ clutter_actor_get_transition (ClutterActor *self,
|
||||
return clos->transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_has_transitions: (skip)
|
||||
*/
|
||||
gboolean
|
||||
clutter_actor_has_transitions (ClutterActor *self)
|
||||
{
|
||||
const ClutterAnimationInfo *info;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
||||
|
||||
info = _clutter_actor_get_animation_info_or_defaults (self);
|
||||
if (info->transitions == NULL)
|
||||
return FALSE;
|
||||
|
||||
return g_hash_table_size (info->transitions) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_save_easing_state:
|
||||
* @self: a #ClutterActor
|
||||
|
@ -50,8 +50,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterConstraint, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterContainer, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDeformEffect, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDesaturateEffect, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDragAction, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDropAction, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterEffect, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterFixedLayout, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterFlowLayout, g_object_unref)
|
||||
|
@ -238,6 +238,7 @@ click_action_query_long_press (ClutterClickAction *action)
|
||||
|
||||
if (result)
|
||||
{
|
||||
g_clear_handle_id (&priv->long_press_id, g_source_remove);
|
||||
priv->long_press_id =
|
||||
clutter_threads_add_timeout (timeout,
|
||||
click_action_emit_long_press,
|
||||
@ -467,6 +468,20 @@ clutter_click_action_set_actor (ClutterActorMeta *meta,
|
||||
CLUTTER_ACTOR_META_CLASS (clutter_click_action_parent_class)->set_actor (meta, actor);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_click_action_set_enabled (ClutterActorMeta *meta,
|
||||
gboolean is_enabled)
|
||||
{
|
||||
ClutterClickAction *click_action = CLUTTER_CLICK_ACTION (meta);
|
||||
ClutterActorMetaClass *parent_class =
|
||||
CLUTTER_ACTOR_META_CLASS (clutter_click_action_parent_class);
|
||||
|
||||
if (!is_enabled)
|
||||
clutter_click_action_release (click_action);
|
||||
|
||||
parent_class->set_enabled (meta, is_enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_click_action_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
@ -546,6 +561,7 @@ clutter_click_action_class_init (ClutterClickActionClass *klass)
|
||||
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
|
||||
|
||||
meta_class->set_actor = clutter_click_action_set_actor;
|
||||
meta_class->set_enabled = clutter_click_action_set_enabled;
|
||||
|
||||
gobject_class->dispose = clutter_click_action_dispose;
|
||||
gobject_class->set_property = clutter_click_action_set_property;
|
||||
|
@ -9,7 +9,13 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@CLUTTER_CONFIG_DEFINES@
|
||||
#mesondefine CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
|
||||
#mesondefine CLUTTER_WINDOWING_X11
|
||||
#mesondefine CLUTTER_INPUT_X11
|
||||
#mesondefine CLUTTER_WINDOWING_GLX
|
||||
#mesondefine CLUTTER_WINDOWING_EGL
|
||||
#mesondefine CLUTTER_INPUT_EVDEV
|
||||
#mesondefine CLUTTER_INPUT_NULL
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -160,28 +160,26 @@ constraint_update_preferred_size (ClutterConstraint *constraint,
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_constraint_notify (GObject *gobject,
|
||||
GParamSpec *pspec)
|
||||
clutter_constraint_set_enabled (ClutterActorMeta *meta,
|
||||
gboolean is_enabled)
|
||||
{
|
||||
if (strcmp (pspec->name, "enabled") == 0)
|
||||
{
|
||||
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
|
||||
ClutterActor *actor = clutter_actor_meta_get_actor (meta);
|
||||
ClutterActorMetaClass *parent_class =
|
||||
CLUTTER_ACTOR_META_CLASS (clutter_constraint_parent_class);
|
||||
ClutterActor *actor;
|
||||
|
||||
if (actor != NULL)
|
||||
clutter_actor_queue_relayout (actor);
|
||||
}
|
||||
actor = clutter_actor_meta_get_actor (meta);
|
||||
if (actor)
|
||||
clutter_actor_queue_relayout (actor);
|
||||
|
||||
if (G_OBJECT_CLASS (clutter_constraint_parent_class)->notify != NULL)
|
||||
G_OBJECT_CLASS (clutter_constraint_parent_class)->notify (gobject, pspec);
|
||||
parent_class->set_enabled (meta, is_enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_constraint_class_init (ClutterConstraintClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorMetaClass *actor_meta_class = CLUTTER_ACTOR_META_CLASS (klass);
|
||||
|
||||
gobject_class->notify = clutter_constraint_notify;
|
||||
actor_meta_class->set_enabled = clutter_constraint_set_enabled;
|
||||
|
||||
klass->update_allocation = constraint_update_allocation;
|
||||
klass->update_preferred_size = constraint_update_preferred_size;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2010 Intel Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author:
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLUTTER_DRAG_ACTION_H__
|
||||
#define __CLUTTER_DRAG_ACTION_H__
|
||||
|
||||
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
|
||||
#error "Only <clutter/clutter.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <clutter/clutter-action.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_DRAG_ACTION (clutter_drag_action_get_type ())
|
||||
#define CLUTTER_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragAction))
|
||||
#define CLUTTER_IS_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DRAG_ACTION))
|
||||
#define CLUTTER_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass))
|
||||
#define CLUTTER_IS_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DRAG_ACTION))
|
||||
#define CLUTTER_DRAG_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass))
|
||||
|
||||
typedef struct _ClutterDragAction ClutterDragAction;
|
||||
typedef struct _ClutterDragActionPrivate ClutterDragActionPrivate;
|
||||
typedef struct _ClutterDragActionClass ClutterDragActionClass;
|
||||
|
||||
/**
|
||||
* ClutterDragAction:
|
||||
*
|
||||
* The #ClutterDragAction structure contains only
|
||||
* private data and should be accessed using the provided API
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
struct _ClutterDragAction
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterAction parent_instance;
|
||||
|
||||
ClutterDragActionPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* ClutterDragActionClass:
|
||||
* @drag_begin: class handler of the #ClutterDragAction::drag-begin signal
|
||||
* @drag_motion: class handler of the #ClutterDragAction::drag-motion signal
|
||||
* @drag_end: class handler of the #ClutterDragAction::drag-end signal
|
||||
* @drag_progress: class handler of the #ClutterDragAction::drag-progress signal
|
||||
*
|
||||
* The #ClutterDragActionClass structure contains
|
||||
* only private data
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
struct _ClutterDragActionClass
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActionClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
void (* drag_begin) (ClutterDragAction *action,
|
||||
ClutterActor *actor,
|
||||
gfloat event_x,
|
||||
gfloat event_y,
|
||||
ClutterModifierType modifiers);
|
||||
void (* drag_motion) (ClutterDragAction *action,
|
||||
ClutterActor *actor,
|
||||
gfloat delta_x,
|
||||
gfloat delta_y);
|
||||
void (* drag_end) (ClutterDragAction *action,
|
||||
ClutterActor *actor,
|
||||
gfloat event_x,
|
||||
gfloat event_y,
|
||||
ClutterModifierType modifiers);
|
||||
gboolean (* drag_progress) (ClutterDragAction *action,
|
||||
ClutterActor *actor,
|
||||
gfloat delta_x,
|
||||
gfloat delta_y);
|
||||
|
||||
/*< private >*/
|
||||
void (* _clutter_drag_action1) (void);
|
||||
void (* _clutter_drag_action2) (void);
|
||||
void (* _clutter_drag_action3) (void);
|
||||
void (* _clutter_drag_action4) (void);
|
||||
};
|
||||
|
||||
CLUTTER_EXPORT
|
||||
GType clutter_drag_action_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterAction * clutter_drag_action_new (void);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_drag_action_set_drag_threshold (ClutterDragAction *action,
|
||||
gint x_threshold,
|
||||
gint y_threshold);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_drag_action_get_drag_threshold (ClutterDragAction *action,
|
||||
guint *x_threshold,
|
||||
guint *y_threshold);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_drag_action_set_drag_handle (ClutterDragAction *action,
|
||||
ClutterActor *handle);
|
||||
CLUTTER_EXPORT
|
||||
ClutterActor * clutter_drag_action_get_drag_handle (ClutterDragAction *action);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_drag_action_set_drag_axis (ClutterDragAction *action,
|
||||
ClutterDragAxis axis);
|
||||
CLUTTER_EXPORT
|
||||
ClutterDragAxis clutter_drag_action_get_drag_axis (ClutterDragAction *action);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_drag_action_get_press_coords (ClutterDragAction *action,
|
||||
gfloat *press_x,
|
||||
gfloat *press_y);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_drag_action_get_motion_coords (ClutterDragAction *action,
|
||||
gfloat *motion_x,
|
||||
gfloat *motion_y);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_drag_action_get_drag_area (ClutterDragAction *action,
|
||||
graphene_rect_t *drag_area);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_drag_action_set_drag_area (ClutterDragAction *action,
|
||||
const graphene_rect_t *drag_area);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_DRAG_ACTION_H__ */
|
@ -1,527 +0,0 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright © 2011 Intel Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author:
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:clutter-drop-action
|
||||
* @Title: ClutterDropAction
|
||||
* @short_description: An action for drop targets
|
||||
*
|
||||
* #ClutterDropAction is a #ClutterAction that allows a #ClutterActor
|
||||
* implementation to control what happens when an actor dragged using
|
||||
* a #ClutterDragAction crosses the target area or when a dragged actor
|
||||
* is released (or "dropped") on the target area.
|
||||
*
|
||||
* A trivial use of #ClutterDropAction consists in connecting to the
|
||||
* #ClutterDropAction::drop signal and handling the drop from there,
|
||||
* for instance:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* ClutterAction *action = clutter_drop_action ();
|
||||
*
|
||||
* g_signal_connect (action, "drop", G_CALLBACK (on_drop), NULL);
|
||||
* clutter_actor_add_action (an_actor, action);
|
||||
* ]|
|
||||
*
|
||||
* The #ClutterDropAction::can-drop can be used to control whether the
|
||||
* #ClutterDropAction::drop signal is going to be emitted; returning %FALSE
|
||||
* from a handler connected to the #ClutterDropAction::can-drop signal will
|
||||
* cause the #ClutterDropAction::drop signal to be skipped when the input
|
||||
* device button is released.
|
||||
*
|
||||
* It's important to note that #ClutterDropAction will only work with
|
||||
* actors dragged using #ClutterDragAction.
|
||||
*
|
||||
* See [drop-action.c](https://git.gnome.org/browse/clutter/tree/examples/drop-action.c?h=clutter-1.18)
|
||||
* for an example of how to use #ClutterDropAction.
|
||||
*
|
||||
* #ClutterDropAction is available since Clutter 1.8
|
||||
*/
|
||||
|
||||
#include "clutter-build-config.h"
|
||||
|
||||
#include "clutter-drop-action.h"
|
||||
|
||||
#include "clutter-actor-meta-private.h"
|
||||
#include "clutter-actor-private.h"
|
||||
#include "clutter-drag-action.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-marshal.h"
|
||||
#include "clutter-stage-private.h"
|
||||
|
||||
struct _ClutterDropActionPrivate
|
||||
{
|
||||
ClutterActor *actor;
|
||||
ClutterActor *stage;
|
||||
|
||||
gulong mapped_id;
|
||||
};
|
||||
|
||||
typedef struct _DropTarget {
|
||||
ClutterActor *stage;
|
||||
|
||||
gulong capture_id;
|
||||
|
||||
GHashTable *actions;
|
||||
|
||||
ClutterDropAction *last_action;
|
||||
} DropTarget;
|
||||
|
||||
enum
|
||||
{
|
||||
CAN_DROP,
|
||||
OVER_IN,
|
||||
OVER_OUT,
|
||||
DROP,
|
||||
DROP_CANCEL,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint drop_signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (ClutterDropAction, clutter_drop_action, CLUTTER_TYPE_ACTION)
|
||||
|
||||
static void
|
||||
drop_target_free (gpointer _data)
|
||||
{
|
||||
DropTarget *data = _data;
|
||||
|
||||
g_clear_signal_handler (&data->capture_id, data->stage);
|
||||
g_hash_table_destroy (data->actions);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_stage_capture (ClutterStage *stage,
|
||||
ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
DropTarget *data = user_data;
|
||||
gfloat event_x, event_y;
|
||||
ClutterActor *actor, *drag_actor;
|
||||
ClutterDropAction *drop_action;
|
||||
ClutterInputDevice *device;
|
||||
gboolean was_reactive;
|
||||
|
||||
switch (clutter_event_type (event))
|
||||
{
|
||||
case CLUTTER_MOTION:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
if (clutter_event_type (event) == CLUTTER_MOTION &&
|
||||
!(clutter_event_get_state (event) & CLUTTER_BUTTON1_MASK))
|
||||
return CLUTTER_EVENT_PROPAGATE;
|
||||
|
||||
if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE &&
|
||||
clutter_event_get_button (event) != CLUTTER_BUTTON_PRIMARY)
|
||||
return CLUTTER_EVENT_PROPAGATE;
|
||||
|
||||
device = clutter_event_get_device (event);
|
||||
drag_actor = _clutter_stage_get_pointer_drag_actor (stage, device);
|
||||
if (drag_actor == NULL)
|
||||
return CLUTTER_EVENT_PROPAGATE;
|
||||
break;
|
||||
|
||||
case CLUTTER_TOUCH_UPDATE:
|
||||
case CLUTTER_TOUCH_END:
|
||||
drag_actor = _clutter_stage_get_touch_drag_actor (stage,
|
||||
clutter_event_get_event_sequence (event));
|
||||
if (drag_actor == NULL)
|
||||
return CLUTTER_EVENT_PROPAGATE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return CLUTTER_EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
clutter_event_get_coords (event, &event_x, &event_y);
|
||||
|
||||
/* get the actor under the cursor, excluding the dragged actor; we
|
||||
* use reactivity because it won't cause any scene invalidation
|
||||
*/
|
||||
was_reactive = clutter_actor_get_reactive (drag_actor);
|
||||
clutter_actor_set_reactive (drag_actor, FALSE);
|
||||
|
||||
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_REACTIVE,
|
||||
event_x,
|
||||
event_y);
|
||||
if (actor == NULL || actor == CLUTTER_ACTOR (stage))
|
||||
{
|
||||
if (data->last_action != NULL)
|
||||
{
|
||||
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
|
||||
|
||||
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
|
||||
clutter_actor_meta_get_actor (meta));
|
||||
|
||||
data->last_action = NULL;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
drop_action = g_hash_table_lookup (data->actions, actor);
|
||||
|
||||
if (drop_action == NULL)
|
||||
{
|
||||
if (data->last_action != NULL)
|
||||
{
|
||||
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
|
||||
|
||||
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
|
||||
clutter_actor_meta_get_actor (meta));
|
||||
|
||||
data->last_action = NULL;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data->last_action != drop_action)
|
||||
{
|
||||
ClutterActorMeta *meta;
|
||||
|
||||
if (data->last_action != NULL)
|
||||
{
|
||||
meta = CLUTTER_ACTOR_META (data->last_action);
|
||||
|
||||
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
|
||||
clutter_actor_meta_get_actor (meta));
|
||||
}
|
||||
|
||||
meta = CLUTTER_ACTOR_META (drop_action);
|
||||
|
||||
g_signal_emit (drop_action, drop_signals[OVER_IN], 0,
|
||||
clutter_actor_meta_get_actor (meta));
|
||||
}
|
||||
|
||||
data->last_action = drop_action;
|
||||
}
|
||||
|
||||
out:
|
||||
if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE ||
|
||||
clutter_event_type (event) == CLUTTER_TOUCH_END)
|
||||
{
|
||||
if (data->last_action != NULL)
|
||||
{
|
||||
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
|
||||
gboolean can_drop = FALSE;
|
||||
|
||||
g_signal_emit (data->last_action, drop_signals[CAN_DROP], 0,
|
||||
clutter_actor_meta_get_actor (meta),
|
||||
event_x, event_y,
|
||||
&can_drop);
|
||||
|
||||
if (can_drop)
|
||||
{
|
||||
g_signal_emit (data->last_action, drop_signals[DROP], 0,
|
||||
clutter_actor_meta_get_actor (meta),
|
||||
event_x, event_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_signal_emit (data->last_action, drop_signals[DROP_CANCEL], 0,
|
||||
clutter_actor_meta_get_actor (meta),
|
||||
event_x, event_y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data->last_action = NULL;
|
||||
}
|
||||
|
||||
if (drag_actor != NULL)
|
||||
clutter_actor_set_reactive (drag_actor, was_reactive);
|
||||
|
||||
return CLUTTER_EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
static void
|
||||
drop_action_register (ClutterDropAction *self)
|
||||
{
|
||||
ClutterDropActionPrivate *priv = self->priv;
|
||||
DropTarget *data;
|
||||
|
||||
g_assert (priv->stage != NULL);
|
||||
|
||||
data = g_object_get_data (G_OBJECT (priv->stage), "__clutter_drop_targets");
|
||||
if (data == NULL)
|
||||
{
|
||||
data = g_new0 (DropTarget, 1);
|
||||
|
||||
data->stage = priv->stage;
|
||||
data->actions = g_hash_table_new (NULL, NULL);
|
||||
data->capture_id = g_signal_connect (priv->stage, "captured-event",
|
||||
G_CALLBACK (on_stage_capture),
|
||||
data);
|
||||
g_object_set_data_full (G_OBJECT (priv->stage), "__clutter_drop_targets",
|
||||
data,
|
||||
drop_target_free);
|
||||
}
|
||||
|
||||
g_hash_table_replace (data->actions, priv->actor, self);
|
||||
}
|
||||
|
||||
static void
|
||||
drop_action_unregister (ClutterDropAction *self)
|
||||
{
|
||||
ClutterDropActionPrivate *priv = self->priv;
|
||||
DropTarget *data = NULL;
|
||||
|
||||
if (priv->stage != NULL)
|
||||
data = g_object_get_data (G_OBJECT (priv->stage), "__clutter_drop_targets");
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
g_hash_table_remove (data->actions, priv->actor);
|
||||
if (g_hash_table_size (data->actions) == 0)
|
||||
g_object_set_data (G_OBJECT (data->stage), "__clutter_drop_targets", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_actor_mapped (ClutterActor *actor,
|
||||
GParamSpec *pspec,
|
||||
ClutterDropAction *self)
|
||||
{
|
||||
if (clutter_actor_is_mapped (actor))
|
||||
{
|
||||
if (self->priv->stage == NULL)
|
||||
self->priv->stage = clutter_actor_get_stage (actor);
|
||||
|
||||
drop_action_register (self);
|
||||
}
|
||||
else
|
||||
drop_action_unregister (self);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_drop_action_set_actor (ClutterActorMeta *meta,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
ClutterDropActionPrivate *priv = CLUTTER_DROP_ACTION (meta)->priv;
|
||||
|
||||
if (priv->actor != NULL)
|
||||
{
|
||||
drop_action_unregister (CLUTTER_DROP_ACTION (meta));
|
||||
|
||||
g_clear_signal_handler (&priv->mapped_id, priv->actor);
|
||||
|
||||
priv->stage = NULL;
|
||||
priv->actor = NULL;
|
||||
}
|
||||
|
||||
priv->actor = actor;
|
||||
|
||||
if (priv->actor != NULL)
|
||||
{
|
||||
priv->stage = clutter_actor_get_stage (actor);
|
||||
priv->mapped_id = g_signal_connect (actor, "notify::mapped",
|
||||
G_CALLBACK (on_actor_mapped),
|
||||
meta);
|
||||
|
||||
if (priv->stage != NULL)
|
||||
drop_action_register (CLUTTER_DROP_ACTION (meta));
|
||||
}
|
||||
|
||||
CLUTTER_ACTOR_META_CLASS (clutter_drop_action_parent_class)->set_actor (meta, actor);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
signal_accumulator (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer user_data)
|
||||
{
|
||||
gboolean continue_emission;
|
||||
|
||||
continue_emission = g_value_get_boolean (handler_return);
|
||||
g_value_set_boolean (return_accu, continue_emission);
|
||||
|
||||
return continue_emission;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_drop_action_real_can_drop (ClutterDropAction *action,
|
||||
ClutterActor *actor,
|
||||
gfloat event_x,
|
||||
gfloat event_y)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_drop_action_class_init (ClutterDropActionClass *klass)
|
||||
{
|
||||
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
|
||||
|
||||
meta_class->set_actor = clutter_drop_action_set_actor;
|
||||
|
||||
klass->can_drop = clutter_drop_action_real_can_drop;
|
||||
|
||||
/**
|
||||
* ClutterDropAction::can-drop:
|
||||
* @action: the #ClutterDropAction that emitted the signal
|
||||
* @actor: the #ClutterActor attached to the @action
|
||||
* @event_x: the X coordinate (in stage space) of the drop event
|
||||
* @event_y: the Y coordinate (in stage space) of the drop event
|
||||
*
|
||||
* The ::can-drop signal is emitted when the dragged actor is dropped
|
||||
* on @actor. The return value of the ::can-drop signal will determine
|
||||
* whether or not the #ClutterDropAction::drop signal is going to be
|
||||
* emitted on @action.
|
||||
*
|
||||
* The default implementation of #ClutterDropAction returns %TRUE for
|
||||
* this signal.
|
||||
*
|
||||
* Return value: %TRUE if the drop is accepted, and %FALSE otherwise
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
drop_signals[CAN_DROP] =
|
||||
g_signal_new (I_("can-drop"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, can_drop),
|
||||
signal_accumulator, NULL,
|
||||
_clutter_marshal_BOOLEAN__OBJECT_FLOAT_FLOAT,
|
||||
G_TYPE_BOOLEAN, 3,
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
G_TYPE_FLOAT,
|
||||
G_TYPE_FLOAT);
|
||||
|
||||
/**
|
||||
* ClutterDropAction::over-in:
|
||||
* @action: the #ClutterDropAction that emitted the signal
|
||||
* @actor: the #ClutterActor attached to the @action
|
||||
*
|
||||
* The ::over-in signal is emitted when the dragged actor crosses
|
||||
* into @actor.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
drop_signals[OVER_IN] =
|
||||
g_signal_new (I_("over-in"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, over_in),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/**
|
||||
* ClutterDropAction::over-out:
|
||||
* @action: the #ClutterDropAction that emitted the signal
|
||||
* @actor: the #ClutterActor attached to the @action
|
||||
*
|
||||
* The ::over-out signal is emitted when the dragged actor crosses
|
||||
* outside @actor.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
drop_signals[OVER_OUT] =
|
||||
g_signal_new (I_("over-out"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, over_out),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/**
|
||||
* ClutterDropAction::drop:
|
||||
* @action: the #ClutterDropAction that emitted the signal
|
||||
* @actor: the #ClutterActor attached to the @action
|
||||
* @event_x: the X coordinate (in stage space) of the drop event
|
||||
* @event_y: the Y coordinate (in stage space) of the drop event
|
||||
*
|
||||
* The ::drop signal is emitted when the dragged actor is dropped
|
||||
* on @actor. This signal is only emitted if at least an handler of
|
||||
* #ClutterDropAction::can-drop returns %TRUE.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
drop_signals[DROP] =
|
||||
g_signal_new (I_("drop"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, drop),
|
||||
NULL, NULL,
|
||||
_clutter_marshal_VOID__OBJECT_FLOAT_FLOAT,
|
||||
G_TYPE_NONE, 3,
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
G_TYPE_FLOAT,
|
||||
G_TYPE_FLOAT);
|
||||
|
||||
|
||||
/**
|
||||
* ClutterDropAction::drop-cancel:
|
||||
* @action: the #ClutterDropAction that emitted the signal
|
||||
* @actor: the #ClutterActor attached to the @action
|
||||
* @event_x: the X coordinate (in stage space) of the drop event
|
||||
* @event_y: the Y coordinate (in stage space) of the drop event
|
||||
*
|
||||
* The ::drop-cancel signal is emitted when the drop is refused
|
||||
* by an emission of the #ClutterDropAction::can-drop signal.
|
||||
*
|
||||
* After the ::drop-cancel signal is fired the active drag is
|
||||
* terminated.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
drop_signals[DROP_CANCEL] =
|
||||
g_signal_new (I_("drop-cancel"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, drop),
|
||||
NULL, NULL,
|
||||
_clutter_marshal_VOID__OBJECT_FLOAT_FLOAT,
|
||||
G_TYPE_NONE, 3,
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
G_TYPE_FLOAT,
|
||||
G_TYPE_FLOAT);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_drop_action_init (ClutterDropAction *self)
|
||||
{
|
||||
self->priv = clutter_drop_action_get_instance_private (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_drop_action_new:
|
||||
*
|
||||
* Creates a new #ClutterDropAction.
|
||||
*
|
||||
* Use clutter_actor_add_action() to add the action to a #ClutterActor.
|
||||
*
|
||||
* Return value: the newly created #ClutterDropAction
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
ClutterAction *
|
||||
clutter_drop_action_new (void)
|
||||
{
|
||||
return g_object_new (CLUTTER_TYPE_DROP_ACTION, NULL);
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright © 2011 Intel Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author:
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLUTTER_DROP_ACTION_H__
|
||||
#define __CLUTTER_DROP_ACTION_H__
|
||||
|
||||
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
|
||||
#error "Only <clutter/clutter.h> can be directly included."
|
||||
#endif
|
||||
|
||||
#include <clutter/clutter-action.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_DROP_ACTION (clutter_drop_action_get_type ())
|
||||
#define CLUTTER_DROP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DROP_ACTION, ClutterDropAction))
|
||||
#define CLUTTER_IS_DROP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DROP_ACTION))
|
||||
#define CLUTTER_DROP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DROP_ACTION, ClutterDropActionClass))
|
||||
#define CLUTTER_IS_DROP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DROP_ACTION))
|
||||
#define CLUTTER_DROP_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DROP_ACTION, ClutterDropActionClass))
|
||||
|
||||
typedef struct _ClutterDropAction ClutterDropAction;
|
||||
typedef struct _ClutterDropActionPrivate ClutterDropActionPrivate;
|
||||
typedef struct _ClutterDropActionClass ClutterDropActionClass;
|
||||
|
||||
/**
|
||||
* ClutterDropAction:
|
||||
*
|
||||
* The #ClutterDropAction structure contains only
|
||||
* private data and should be accessed using the provided API.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
struct _ClutterDropAction
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterAction parent_instance;
|
||||
|
||||
ClutterDropActionPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* ClutterDropActionClass:
|
||||
* @can_drop: class handler for the #ClutterDropAction::can-drop signal
|
||||
* @over_in: class handler for the #ClutterDropAction::over-in signal
|
||||
* @over_out: class handler for the #ClutterDropAction::over-out signal
|
||||
* @drop: class handler for the #ClutterDropAction::drop signal
|
||||
*
|
||||
* The #ClutterDropActionClass structure contains
|
||||
* only private data.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
struct _ClutterDropActionClass
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActionClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
gboolean (* can_drop) (ClutterDropAction *action,
|
||||
ClutterActor *actor,
|
||||
gfloat event_x,
|
||||
gfloat event_y);
|
||||
|
||||
void (* over_in) (ClutterDropAction *action,
|
||||
ClutterActor *actor);
|
||||
void (* over_out) (ClutterDropAction *action,
|
||||
ClutterActor *actor);
|
||||
|
||||
void (* drop) (ClutterDropAction *action,
|
||||
ClutterActor *actor,
|
||||
gfloat event_x,
|
||||
gfloat event_y);
|
||||
|
||||
/*< private >*/
|
||||
void (*_clutter_drop_action1) (void);
|
||||
void (*_clutter_drop_action2) (void);
|
||||
void (*_clutter_drop_action3) (void);
|
||||
void (*_clutter_drop_action4) (void);
|
||||
void (*_clutter_drop_action5) (void);
|
||||
void (*_clutter_drop_action6) (void);
|
||||
void (*_clutter_drop_action7) (void);
|
||||
void (*_clutter_drop_action8) (void);
|
||||
};
|
||||
|
||||
CLUTTER_EXPORT
|
||||
GType clutter_drop_action_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterAction * clutter_drop_action_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_DROP_ACTION_H__ */
|
@ -230,28 +230,26 @@ clutter_effect_real_pick (ClutterEffect *effect,
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_effect_notify (GObject *gobject,
|
||||
GParamSpec *pspec)
|
||||
clutter_effect_set_enabled (ClutterActorMeta *meta,
|
||||
gboolean is_enabled)
|
||||
{
|
||||
if (strcmp (pspec->name, "enabled") == 0)
|
||||
{
|
||||
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
|
||||
ClutterActor *actor = clutter_actor_meta_get_actor (meta);
|
||||
ClutterActorMetaClass *parent_class =
|
||||
CLUTTER_ACTOR_META_CLASS (clutter_effect_parent_class);
|
||||
ClutterActor *actor;
|
||||
|
||||
if (actor != NULL)
|
||||
clutter_actor_queue_redraw (actor);
|
||||
}
|
||||
actor = clutter_actor_meta_get_actor (meta);
|
||||
if (actor)
|
||||
clutter_actor_queue_redraw (actor);
|
||||
|
||||
if (G_OBJECT_CLASS (clutter_effect_parent_class)->notify != NULL)
|
||||
G_OBJECT_CLASS (clutter_effect_parent_class)->notify (gobject, pspec);
|
||||
parent_class->set_enabled (meta, is_enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_effect_class_init (ClutterEffectClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorMetaClass *actor_meta_class = CLUTTER_ACTOR_META_CLASS (klass);
|
||||
|
||||
gobject_class->notify = clutter_effect_notify;
|
||||
actor_meta_class->set_enabled = clutter_effect_set_enabled;
|
||||
|
||||
klass->pre_paint = clutter_effect_real_pre_paint;
|
||||
klass->post_paint = clutter_effect_real_post_paint;
|
||||
|
@ -556,6 +556,21 @@ clutter_gesture_action_set_actor (ClutterActorMeta *meta,
|
||||
meta_class->set_actor (meta, actor);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_gesture_action_set_enabled (ClutterActorMeta *meta,
|
||||
gboolean is_enabled)
|
||||
{
|
||||
ClutterActorMetaClass *meta_class =
|
||||
CLUTTER_ACTOR_META_CLASS (clutter_gesture_action_parent_class);
|
||||
ClutterGestureAction *gesture_action = CLUTTER_GESTURE_ACTION (meta);
|
||||
ClutterGestureActionPrivate *priv = gesture_action->priv;
|
||||
|
||||
if (!is_enabled && priv->in_gesture)
|
||||
cancel_gesture (gesture_action);
|
||||
|
||||
meta_class->set_enabled (meta, is_enabled);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
default_event_handler (ClutterGestureAction *action,
|
||||
ClutterActor *actor)
|
||||
@ -654,6 +669,7 @@ clutter_gesture_action_class_init (ClutterGestureActionClass *klass)
|
||||
gobject_class->get_property = clutter_gesture_action_get_property;
|
||||
|
||||
meta_class->set_actor = clutter_gesture_action_set_actor;
|
||||
meta_class->set_enabled = clutter_gesture_action_set_enabled;
|
||||
|
||||
klass->gesture_begin = default_event_handler;
|
||||
klass->gesture_progress = default_event_handler;
|
||||
|
@ -36,6 +36,9 @@
|
||||
#include "cogl/clutter-stage-cogl.h"
|
||||
#include "clutter/x11/clutter-backend-x11.h"
|
||||
|
||||
CLUTTER_EXPORT
|
||||
GList * clutter_stage_peek_stage_views (ClutterStage *stage);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_set_custom_backend_func (ClutterBackend *(* func) (void));
|
||||
|
||||
@ -48,6 +51,23 @@ void clutter_stage_capture_into (ClutterStage *stage,
|
||||
cairo_rectangle_int_t *rect,
|
||||
uint8_t *data);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_paint_to_framebuffer (ClutterStage *stage,
|
||||
CoglFramebuffer *framebuffer,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
float scale,
|
||||
ClutterPaintFlag paint_flags);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_stage_paint_to_buffer (ClutterStage *stage,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
float scale,
|
||||
uint8_t *data,
|
||||
int stride,
|
||||
CoglPixelFormat format,
|
||||
ClutterPaintFlag paint_flags,
|
||||
GError **error);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_freeze_updates (ClutterStage *stage);
|
||||
|
||||
@ -57,9 +77,16 @@ void clutter_stage_thaw_updates (ClutterStage *stage);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_update_resource_scales (ClutterStage *stage);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view,
|
||||
CoglScanout *scanout);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_actor_has_damage (ClutterActor *actor);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_actor_has_transitions (ClutterActor *actor);
|
||||
|
||||
#undef __CLUTTER_H_INSIDE__
|
||||
|
||||
#endif /* __CLUTTER_MUTTER_H__ */
|
||||
|
@ -81,7 +81,7 @@
|
||||
struct _ClutterOffscreenEffectPrivate
|
||||
{
|
||||
CoglHandle offscreen;
|
||||
CoglPipeline *target;
|
||||
CoglPipeline *pipeline;
|
||||
CoglHandle texture;
|
||||
|
||||
ClutterActor *actor;
|
||||
@ -140,7 +140,7 @@ ensure_pipeline_filter_for_scale (ClutterOffscreenEffect *self,
|
||||
{
|
||||
CoglPipelineFilter filter;
|
||||
|
||||
if (!self->priv->target)
|
||||
if (!self->priv->pipeline)
|
||||
return;
|
||||
|
||||
/* If no fractional scaling is set, we're always going to render the texture
|
||||
@ -154,7 +154,7 @@ ensure_pipeline_filter_for_scale (ClutterOffscreenEffect *self,
|
||||
else
|
||||
filter = COGL_PIPELINE_FILTER_LINEAR;
|
||||
|
||||
cogl_pipeline_set_layer_filters (self->priv->target, 0 /* layer_index */,
|
||||
cogl_pipeline_set_layer_filters (self->priv->pipeline, 0 /* layer_index */,
|
||||
filter, filter);
|
||||
}
|
||||
|
||||
@ -185,12 +185,12 @@ update_fbo (ClutterEffect *effect,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (priv->target == NULL)
|
||||
if (priv->pipeline == NULL)
|
||||
{
|
||||
CoglContext *ctx =
|
||||
clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
|
||||
priv->target = cogl_pipeline_new (ctx);
|
||||
priv->pipeline = cogl_pipeline_new (ctx);
|
||||
ensure_pipeline_filter_for_scale (self, resource_scale);
|
||||
}
|
||||
|
||||
@ -202,7 +202,7 @@ update_fbo (ClutterEffect *effect,
|
||||
if (priv->texture == NULL)
|
||||
return FALSE;
|
||||
|
||||
cogl_pipeline_set_layer_texture (priv->target, 0, priv->texture);
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->texture);
|
||||
|
||||
priv->target_width = target_width;
|
||||
priv->target_height = target_height;
|
||||
@ -212,8 +212,8 @@ update_fbo (ClutterEffect *effect,
|
||||
{
|
||||
g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC);
|
||||
|
||||
cogl_object_unref (priv->target);
|
||||
priv->target = NULL;
|
||||
cogl_object_unref (priv->pipeline);
|
||||
priv->pipeline = NULL;
|
||||
|
||||
priv->target_width = 0;
|
||||
priv->target_height = 0;
|
||||
@ -380,7 +380,7 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
|
||||
|
||||
paint_opacity = clutter_actor_get_paint_opacity (priv->actor);
|
||||
|
||||
cogl_pipeline_set_color4ub (priv->target,
|
||||
cogl_pipeline_set_color4ub (priv->pipeline,
|
||||
paint_opacity,
|
||||
paint_opacity,
|
||||
paint_opacity,
|
||||
@ -392,7 +392,7 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
|
||||
* hadn't been redirected offscreen.
|
||||
*/
|
||||
cogl_framebuffer_draw_textured_rectangle (framebuffer,
|
||||
priv->target,
|
||||
priv->pipeline,
|
||||
0, 0,
|
||||
cogl_texture_get_width (priv->texture),
|
||||
cogl_texture_get_height (priv->texture),
|
||||
@ -446,13 +446,16 @@ clutter_offscreen_effect_post_paint (ClutterEffect *effect,
|
||||
ClutterOffscreenEffectPrivate *priv = self->priv;
|
||||
CoglFramebuffer *framebuffer;
|
||||
|
||||
if (priv->offscreen == NULL ||
|
||||
priv->target == NULL ||
|
||||
priv->actor == NULL)
|
||||
return;
|
||||
g_warn_if_fail (priv->offscreen);
|
||||
g_warn_if_fail (priv->pipeline);
|
||||
g_warn_if_fail (priv->actor);
|
||||
|
||||
/* Restore the previous opacity override */
|
||||
clutter_actor_set_opacity_override (priv->actor, priv->old_opacity_override);
|
||||
if (priv->actor)
|
||||
{
|
||||
clutter_actor_set_opacity_override (priv->actor,
|
||||
priv->old_opacity_override);
|
||||
}
|
||||
|
||||
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
|
||||
cogl_framebuffer_pop_matrix (framebuffer);
|
||||
@ -498,16 +501,17 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_offscreen_effect_notify (GObject *gobject,
|
||||
GParamSpec *pspec)
|
||||
clutter_offscreen_effect_set_enabled (ClutterActorMeta *meta,
|
||||
gboolean is_enabled)
|
||||
{
|
||||
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (gobject);
|
||||
ClutterActorMetaClass *parent_class =
|
||||
CLUTTER_ACTOR_META_CLASS (clutter_offscreen_effect_parent_class);
|
||||
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (meta);
|
||||
ClutterOffscreenEffectPrivate *priv = offscreen_effect->priv;
|
||||
|
||||
if (strcmp (pspec->name, "enabled") == 0)
|
||||
g_clear_pointer (&priv->offscreen, cogl_object_unref);
|
||||
g_clear_pointer (&priv->offscreen, cogl_object_unref);
|
||||
|
||||
G_OBJECT_CLASS (clutter_offscreen_effect_parent_class)->notify (gobject, pspec);
|
||||
parent_class->set_enabled (meta, is_enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -518,7 +522,7 @@ clutter_offscreen_effect_finalize (GObject *gobject)
|
||||
|
||||
g_clear_pointer (&priv->offscreen, cogl_object_unref);
|
||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
||||
g_clear_pointer (&priv->target, cogl_object_unref);
|
||||
g_clear_pointer (&priv->pipeline, cogl_object_unref);
|
||||
|
||||
G_OBJECT_CLASS (clutter_offscreen_effect_parent_class)->finalize (gobject);
|
||||
}
|
||||
@ -534,13 +538,13 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
|
||||
klass->paint_target = clutter_offscreen_effect_real_paint_target;
|
||||
|
||||
meta_class->set_actor = clutter_offscreen_effect_set_actor;
|
||||
meta_class->set_enabled = clutter_offscreen_effect_set_enabled;
|
||||
|
||||
effect_class->pre_paint = clutter_offscreen_effect_pre_paint;
|
||||
effect_class->post_paint = clutter_offscreen_effect_post_paint;
|
||||
effect_class->paint = clutter_offscreen_effect_paint;
|
||||
|
||||
gobject_class->finalize = clutter_offscreen_effect_finalize;
|
||||
gobject_class->notify = clutter_offscreen_effect_notify;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -600,7 +604,7 @@ clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect)
|
||||
g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect),
|
||||
NULL);
|
||||
|
||||
return (CoglMaterial *)effect->priv->target;
|
||||
return (CoglMaterial *)effect->priv->pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,8 @@
|
||||
#include "clutter-paint-context.h"
|
||||
|
||||
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip);
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags);
|
||||
|
||||
gboolean clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context);
|
||||
|
||||
|
@ -23,6 +23,8 @@ struct _ClutterPaintContext
|
||||
{
|
||||
grefcount ref_count;
|
||||
|
||||
ClutterPaintFlag paint_flags;
|
||||
|
||||
GList *framebuffers;
|
||||
|
||||
ClutterStageView *view;
|
||||
@ -36,7 +38,8 @@ G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
|
||||
|
||||
ClutterPaintContext *
|
||||
clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip)
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags)
|
||||
{
|
||||
ClutterPaintContext *paint_context;
|
||||
CoglFramebuffer *framebuffer;
|
||||
@ -45,6 +48,7 @@ clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
g_ref_count_init (&paint_context->ref_count);
|
||||
paint_context->view = view;
|
||||
paint_context->redraw_clip = cairo_region_copy (redraw_clip);
|
||||
paint_context->paint_flags = paint_flags;
|
||||
|
||||
framebuffer = clutter_stage_view_get_framebuffer (view);
|
||||
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
|
||||
@ -56,12 +60,16 @@ clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
* clutter_paint_context_new_for_framebuffer: (skip)
|
||||
*/
|
||||
ClutterPaintContext *
|
||||
clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer)
|
||||
clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer,
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags)
|
||||
{
|
||||
ClutterPaintContext *paint_context;
|
||||
|
||||
paint_context = g_new0 (ClutterPaintContext, 1);
|
||||
g_ref_count_init (&paint_context->ref_count);
|
||||
paint_context->redraw_clip = cairo_region_copy (redraw_clip);
|
||||
paint_context->paint_flags = paint_flags;
|
||||
|
||||
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
|
||||
|
||||
@ -170,3 +178,12 @@ clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context)
|
||||
|
||||
return !paint_context->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_paint_context_get_paint_flags: (skip)
|
||||
*/
|
||||
ClutterPaintFlag
|
||||
clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context)
|
||||
{
|
||||
return paint_context->paint_flags;
|
||||
}
|
||||
|
@ -29,13 +29,21 @@
|
||||
|
||||
typedef struct _ClutterPaintContext ClutterPaintContext;
|
||||
|
||||
typedef enum _ClutterPaintFlag
|
||||
{
|
||||
CLUTTER_PAINT_FLAG_NONE = 0,
|
||||
CLUTTER_PAINT_FLAG_NO_CURSORS = 1 << 0,
|
||||
} ClutterPaintFlag;
|
||||
|
||||
#define CLUTTER_TYPE_PAINT_CONTEXT (clutter_paint_context_get_type ())
|
||||
|
||||
CLUTTER_EXPORT
|
||||
GType clutter_paint_context_get_type (void);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterPaintContext * clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer);
|
||||
ClutterPaintContext * clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer,
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterPaintContext * clutter_paint_context_ref (ClutterPaintContext *paint_context);
|
||||
@ -62,4 +70,7 @@ void clutter_paint_context_pop_framebuffer (ClutterPaintContext *paint_context);
|
||||
CLUTTER_EXPORT
|
||||
const cairo_region_t * clutter_paint_context_get_redraw_clip (ClutterPaintContext *paint_context);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterPaintFlag clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context);
|
||||
|
||||
#endif /* CLUTTER_PAINT_CONTEXT_H */
|
||||
|
@ -83,7 +83,6 @@ typedef enum
|
||||
PAINT_OP_INVALID = 0,
|
||||
PAINT_OP_TEX_RECT,
|
||||
PAINT_OP_MULTITEX_RECT,
|
||||
PAINT_OP_PATH,
|
||||
PAINT_OP_PRIMITIVE
|
||||
} PaintOpCode;
|
||||
|
||||
@ -96,8 +95,6 @@ struct _ClutterPaintOperation
|
||||
union {
|
||||
float texrect[8];
|
||||
|
||||
CoglPath *path;
|
||||
|
||||
CoglPrimitive *primitive;
|
||||
} op;
|
||||
};
|
||||
|
@ -782,11 +782,6 @@ clutter_paint_operation_clear (ClutterPaintOperation *op)
|
||||
g_array_unref (op->multitex_coords);
|
||||
break;
|
||||
|
||||
case PAINT_OP_PATH:
|
||||
if (op->op.path != NULL)
|
||||
cogl_object_unref (op->op.path);
|
||||
break;
|
||||
|
||||
case PAINT_OP_PRIMITIVE:
|
||||
if (op->op.primitive != NULL)
|
||||
cogl_object_unref (op->op.primitive);
|
||||
@ -836,16 +831,6 @@ clutter_paint_op_init_multitex_rect (ClutterPaintOperation *op,
|
||||
op->op.texrect[3] = rect->y2;
|
||||
}
|
||||
|
||||
static inline void
|
||||
clutter_paint_op_init_path (ClutterPaintOperation *op,
|
||||
CoglPath *path)
|
||||
{
|
||||
clutter_paint_operation_clear (op);
|
||||
|
||||
op->opcode = PAINT_OP_PATH;
|
||||
op->op.path = cogl_object_ref (path);
|
||||
}
|
||||
|
||||
static inline void
|
||||
clutter_paint_op_init_primitive (ClutterPaintOperation *op,
|
||||
CoglPrimitive *primitive)
|
||||
@ -950,34 +935,6 @@ clutter_paint_node_add_multitexture_rectangle (ClutterPaintNode *node,
|
||||
g_array_append_val (node->operations, operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_paint_node_add_path: (skip)
|
||||
* @node: a #ClutterPaintNode
|
||||
* @path: a Cogl path
|
||||
*
|
||||
* Adds a region described as a path to the @node.
|
||||
*
|
||||
* This function acquires a reference on the passed @path, so it
|
||||
* is safe to call cogl_object_unref() when it returns.
|
||||
*
|
||||
* Since: 1.10
|
||||
* Stability: unstable
|
||||
*/
|
||||
void
|
||||
clutter_paint_node_add_path (ClutterPaintNode *node,
|
||||
CoglPath *path)
|
||||
{
|
||||
ClutterPaintOperation operation = PAINT_OP_INIT;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
|
||||
g_return_if_fail (cogl_is_path (path));
|
||||
|
||||
clutter_paint_node_maybe_init_operations (node);
|
||||
|
||||
clutter_paint_op_init_path (&operation, path);
|
||||
g_array_append_val (node->operations, operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_paint_node_add_primitive: (skip)
|
||||
* @node: a #ClutterPaintNode
|
||||
@ -1114,11 +1071,6 @@ clutter_paint_node_to_json (ClutterPaintNode *node)
|
||||
json_builder_end_array (builder);
|
||||
break;
|
||||
|
||||
case PAINT_OP_PATH:
|
||||
json_builder_set_member_name (builder, "path");
|
||||
json_builder_add_int_value (builder, (intptr_t) op->op.path);
|
||||
break;
|
||||
|
||||
case PAINT_OP_PRIMITIVE:
|
||||
json_builder_set_member_name (builder, "primitive");
|
||||
json_builder_add_int_value (builder, (intptr_t) op->op.primitive);
|
||||
|
@ -84,9 +84,6 @@ void clutter_paint_node_add_multitexture_rectangle (ClutterP
|
||||
unsigned int text_coords_len);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_paint_node_add_path (ClutterPaintNode *node,
|
||||
CoglPath *path);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_paint_node_add_primitive (ClutterPaintNode *node,
|
||||
CoglPrimitive *primitive);
|
||||
|
||||
|
@ -477,10 +477,6 @@ clutter_pipeline_node_draw (ClutterPaintNode *node,
|
||||
op->multitex_coords->len);
|
||||
break;
|
||||
|
||||
case PAINT_OP_PATH:
|
||||
cogl_framebuffer_fill_path (fb, pnode->pipeline, op->op.path);
|
||||
break;
|
||||
|
||||
case PAINT_OP_PRIMITIVE:
|
||||
cogl_framebuffer_draw_primitive (fb,
|
||||
pnode->pipeline,
|
||||
@ -876,7 +872,6 @@ clutter_text_node_draw (ClutterPaintNode *node,
|
||||
break;
|
||||
|
||||
case PAINT_OP_MULTITEX_RECT:
|
||||
case PAINT_OP_PATH:
|
||||
case PAINT_OP_PRIMITIVE:
|
||||
case PAINT_OP_INVALID:
|
||||
break;
|
||||
@ -1037,11 +1032,6 @@ clutter_clip_node_pre_draw (ClutterPaintNode *node,
|
||||
retval = TRUE;
|
||||
break;
|
||||
|
||||
case PAINT_OP_PATH:
|
||||
cogl_framebuffer_push_path_clip (fb, op->op.path);
|
||||
retval = TRUE;
|
||||
break;
|
||||
|
||||
case PAINT_OP_MULTITEX_RECT:
|
||||
case PAINT_OP_PRIMITIVE:
|
||||
case PAINT_OP_INVALID:
|
||||
@ -1072,7 +1062,6 @@ clutter_clip_node_post_draw (ClutterPaintNode *node,
|
||||
|
||||
switch (op->opcode)
|
||||
{
|
||||
case PAINT_OP_PATH:
|
||||
case PAINT_OP_TEX_RECT:
|
||||
cogl_framebuffer_pop_clip (fb);
|
||||
break;
|
||||
@ -1242,9 +1231,8 @@ struct _ClutterLayerNode
|
||||
float fbo_width;
|
||||
float fbo_height;
|
||||
|
||||
CoglPipeline *state;
|
||||
CoglPipeline *pipeline;
|
||||
CoglFramebuffer *offscreen;
|
||||
CoglTexture *texture;
|
||||
|
||||
guint8 opacity;
|
||||
};
|
||||
@ -1334,7 +1322,7 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
|
||||
case PAINT_OP_TEX_RECT:
|
||||
/* now we need to paint the texture */
|
||||
cogl_framebuffer_draw_textured_rectangle (fb,
|
||||
lnode->state,
|
||||
lnode->pipeline,
|
||||
op->op.texrect[0],
|
||||
op->op.texrect[1],
|
||||
op->op.texrect[2],
|
||||
@ -1347,7 +1335,7 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
|
||||
|
||||
case PAINT_OP_MULTITEX_RECT:
|
||||
cogl_framebuffer_draw_multitextured_rectangle (fb,
|
||||
lnode->state,
|
||||
lnode->pipeline,
|
||||
op->op.texrect[0],
|
||||
op->op.texrect[1],
|
||||
op->op.texrect[2],
|
||||
@ -1356,12 +1344,10 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
|
||||
op->multitex_coords->len);
|
||||
break;
|
||||
|
||||
case PAINT_OP_PATH:
|
||||
cogl_framebuffer_fill_path (fb, lnode->state, op->op.path);
|
||||
break;
|
||||
|
||||
case PAINT_OP_PRIMITIVE:
|
||||
cogl_framebuffer_draw_primitive (fb, lnode->state, op->op.primitive);
|
||||
cogl_framebuffer_draw_primitive (fb,
|
||||
lnode->pipeline,
|
||||
op->op.primitive);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1372,8 +1358,8 @@ clutter_layer_node_finalize (ClutterPaintNode *node)
|
||||
{
|
||||
ClutterLayerNode *lnode = CLUTTER_LAYER_NODE (node);
|
||||
|
||||
if (lnode->state != NULL)
|
||||
cogl_object_unref (lnode->state);
|
||||
if (lnode->pipeline != NULL)
|
||||
cogl_object_unref (lnode->pipeline);
|
||||
|
||||
if (lnode->offscreen != NULL)
|
||||
cogl_object_unref (lnode->offscreen);
|
||||
@ -1425,6 +1411,8 @@ clutter_layer_node_new (const CoglMatrix *projection,
|
||||
guint8 opacity)
|
||||
{
|
||||
ClutterLayerNode *res;
|
||||
CoglContext *context;
|
||||
CoglTexture *texture;
|
||||
CoglColor color;
|
||||
|
||||
res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
|
||||
@ -1436,19 +1424,17 @@ clutter_layer_node_new (const CoglMatrix *projection,
|
||||
res->opacity = opacity;
|
||||
|
||||
/* the texture backing the FBO */
|
||||
res->texture = cogl_texture_new_with_size (MAX (res->fbo_width, 1),
|
||||
MAX (res->fbo_height, 1),
|
||||
COGL_TEXTURE_NO_SLICING,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE);
|
||||
context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
|
||||
res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (res->texture));
|
||||
texture = cogl_texture_2d_new_with_size (context,
|
||||
MAX (res->fbo_width, 1),
|
||||
MAX (res->fbo_height, 1));
|
||||
cogl_texture_set_premultiplied (texture, TRUE);
|
||||
|
||||
res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (texture));
|
||||
if (res->offscreen == NULL)
|
||||
{
|
||||
g_critical ("%s: Unable to create an offscreen buffer", G_STRLOC);
|
||||
|
||||
cogl_object_unref (res->texture);
|
||||
res->texture = NULL;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1458,14 +1444,15 @@ clutter_layer_node_new (const CoglMatrix *projection,
|
||||
* interpolation filters because the texture is always
|
||||
* going to be painted at a 1:1 texel:pixel ratio
|
||||
*/
|
||||
res->state = cogl_pipeline_copy (default_texture_pipeline);
|
||||
cogl_pipeline_set_layer_filters (res->state, 0,
|
||||
res->pipeline = cogl_pipeline_copy (default_texture_pipeline);
|
||||
cogl_pipeline_set_layer_filters (res->pipeline, 0,
|
||||
COGL_PIPELINE_FILTER_NEAREST,
|
||||
COGL_PIPELINE_FILTER_NEAREST);
|
||||
cogl_pipeline_set_layer_texture (res->state, 0, res->texture);
|
||||
cogl_pipeline_set_color (res->state, &color);
|
||||
cogl_object_unref (res->texture);
|
||||
cogl_pipeline_set_layer_texture (res->pipeline, 0, texture);
|
||||
cogl_pipeline_set_color (res->pipeline, &color);
|
||||
|
||||
out:
|
||||
cogl_object_unref (texture);
|
||||
|
||||
return (ClutterPaintNode *) res;
|
||||
}
|
||||
|
@ -139,8 +139,6 @@ void _clutter_stage_presented (ClutterStage *stag
|
||||
CoglFrameEvent frame_event,
|
||||
ClutterFrameInfo *frame_info);
|
||||
|
||||
GList * _clutter_stage_peek_stage_views (ClutterStage *stage);
|
||||
|
||||
void clutter_stage_queue_actor_relayout (ClutterStage *stage,
|
||||
ClutterActor *actor);
|
||||
|
||||
|
@ -43,4 +43,6 @@ const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *vi
|
||||
|
||||
cairo_region_t * clutter_stage_view_take_redraw_clip (ClutterStageView *view);
|
||||
|
||||
CoglScanout * clutter_stage_view_take_scanout (ClutterStageView *view);
|
||||
|
||||
#endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "clutter/clutter-private.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "cogl/cogl.h"
|
||||
|
||||
enum
|
||||
{
|
||||
@ -52,6 +54,8 @@ typedef struct _ClutterStageViewPrivate
|
||||
CoglOffscreen *shadowfb;
|
||||
CoglPipeline *shadowfb_pipeline;
|
||||
|
||||
CoglScanout *next_scanout;
|
||||
|
||||
gboolean has_redraw_clip;
|
||||
cairo_region_t *redraw_clip;
|
||||
|
||||
@ -407,6 +411,25 @@ clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *vie
|
||||
cogl_matrix_init_identity (matrix);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_view_assign_next_scanout (ClutterStageView *view,
|
||||
CoglScanout *scanout)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
g_set_object (&priv->next_scanout, scanout);
|
||||
}
|
||||
|
||||
CoglScanout *
|
||||
clutter_stage_view_take_scanout (ClutterStageView *view)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
return g_steal_pointer (&priv->next_scanout);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
|
@ -62,16 +62,6 @@ _clutter_stage_window_set_title (ClutterStageWindow *window,
|
||||
iface->set_title (window, title);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_window_set_cursor_visible (ClutterStageWindow *window,
|
||||
gboolean is_visible)
|
||||
{
|
||||
ClutterStageWindowInterface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
|
||||
|
||||
if (iface->set_cursor_visible)
|
||||
iface->set_cursor_visible (window, is_visible);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_clutter_stage_window_realize (ClutterStageWindow *window)
|
||||
{
|
||||
@ -178,19 +168,6 @@ _clutter_stage_window_clear_update_time (ClutterStageWindow *window)
|
||||
iface->clear_update_time (window);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_window_set_accept_focus (ClutterStageWindow *window,
|
||||
gboolean accept_focus)
|
||||
{
|
||||
ClutterStageWindowInterface *iface;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
|
||||
|
||||
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
|
||||
if (iface->set_accept_focus)
|
||||
iface->set_accept_focus (window, accept_focus);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_window_redraw (ClutterStageWindow *window)
|
||||
{
|
||||
|
@ -30,8 +30,6 @@ struct _ClutterStageWindowInterface
|
||||
|
||||
void (* set_title) (ClutterStageWindow *stage_window,
|
||||
const gchar *title);
|
||||
void (* set_cursor_visible) (ClutterStageWindow *stage_window,
|
||||
gboolean cursor_visible);
|
||||
|
||||
gboolean (* realize) (ClutterStageWindow *stage_window);
|
||||
void (* unrealize) (ClutterStageWindow *stage_window);
|
||||
@ -51,9 +49,6 @@ struct _ClutterStageWindowInterface
|
||||
gint64 (* get_update_time) (ClutterStageWindow *stage_window);
|
||||
void (* clear_update_time) (ClutterStageWindow *stage_window);
|
||||
|
||||
void (* set_accept_focus) (ClutterStageWindow *stage_window,
|
||||
gboolean accept_focus);
|
||||
|
||||
void (* redraw) (ClutterStageWindow *stage_window);
|
||||
|
||||
gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window);
|
||||
|
@ -140,19 +140,12 @@ struct _ClutterStagePrivate
|
||||
|
||||
ClutterStageState current_state;
|
||||
|
||||
gpointer paint_data;
|
||||
GDestroyNotify paint_notify;
|
||||
|
||||
int update_freeze_count;
|
||||
|
||||
guint redraw_pending : 1;
|
||||
guint is_cursor_visible : 1;
|
||||
guint throttle_motion_events : 1;
|
||||
guint use_alpha : 1;
|
||||
guint min_size_changed : 1;
|
||||
guint accept_focus : 1;
|
||||
guint motion_events_enabled : 1;
|
||||
guint has_custom_perspective : 1;
|
||||
guint stage_was_relayout : 1;
|
||||
};
|
||||
|
||||
@ -161,12 +154,9 @@ enum
|
||||
PROP_0,
|
||||
|
||||
PROP_COLOR,
|
||||
PROP_CURSOR_VISIBLE,
|
||||
PROP_PERSPECTIVE,
|
||||
PROP_TITLE,
|
||||
PROP_USE_ALPHA,
|
||||
PROP_KEY_FOCUS,
|
||||
PROP_ACCEPT_FOCUS,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
@ -562,7 +552,7 @@ clutter_stage_add_redraw_clip (ClutterStage *stage,
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = _clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
|
||||
@ -934,7 +924,8 @@ clutter_stage_do_paint_view (ClutterStage *stage,
|
||||
ClutterPaintContext *paint_context;
|
||||
cairo_rectangle_int_t clip_rect;
|
||||
|
||||
paint_context = clutter_paint_context_new_for_view (view, redraw_clip);
|
||||
paint_context = clutter_paint_context_new_for_view (view, redraw_clip,
|
||||
CLUTTER_PAINT_FLAG_NONE);
|
||||
|
||||
cairo_region_get_extents (redraw_clip, &clip_rect);
|
||||
setup_view_for_pick_or_paint (stage, view, &clip_rect);
|
||||
@ -1320,15 +1311,9 @@ clutter_stage_queue_actor_relayout (ClutterStage *stage,
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
|
||||
if (g_hash_table_contains (priv->pending_relayouts, stage))
|
||||
return;
|
||||
|
||||
if (g_hash_table_size (priv->pending_relayouts) == 0)
|
||||
_clutter_stage_schedule_update (stage);
|
||||
|
||||
if (actor == (ClutterActor *) stage)
|
||||
g_hash_table_remove_all (priv->pending_relayouts);
|
||||
|
||||
g_hash_table_add (priv->pending_relayouts, g_object_ref (actor));
|
||||
priv->pending_relayouts_version++;
|
||||
}
|
||||
@ -1588,7 +1573,7 @@ is_full_stage_redraw_queued (ClutterStage *stage)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = _clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
|
||||
@ -1852,33 +1837,14 @@ clutter_stage_set_property (GObject *object,
|
||||
clutter_value_get_color (value));
|
||||
break;
|
||||
|
||||
case PROP_CURSOR_VISIBLE:
|
||||
if (g_value_get_boolean (value))
|
||||
clutter_stage_show_cursor (stage);
|
||||
else
|
||||
clutter_stage_hide_cursor (stage);
|
||||
break;
|
||||
|
||||
case PROP_PERSPECTIVE:
|
||||
clutter_stage_set_perspective (stage, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_TITLE:
|
||||
clutter_stage_set_title (stage, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_USE_ALPHA:
|
||||
clutter_stage_set_use_alpha (stage, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_KEY_FOCUS:
|
||||
clutter_stage_set_key_focus (stage, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_ACCEPT_FOCUS:
|
||||
clutter_stage_set_accept_focus (stage, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -1905,10 +1871,6 @@ clutter_stage_get_property (GObject *gobject,
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_CURSOR_VISIBLE:
|
||||
g_value_set_boolean (value, priv->is_cursor_visible);
|
||||
break;
|
||||
|
||||
case PROP_PERSPECTIVE:
|
||||
g_value_set_boxed (value, &priv->perspective);
|
||||
break;
|
||||
@ -1917,18 +1879,10 @@ clutter_stage_get_property (GObject *gobject,
|
||||
g_value_set_string (value, priv->title);
|
||||
break;
|
||||
|
||||
case PROP_USE_ALPHA:
|
||||
g_value_set_boolean (value, priv->use_alpha);
|
||||
break;
|
||||
|
||||
case PROP_KEY_FOCUS:
|
||||
g_value_set_object (value, priv->key_focused_actor);
|
||||
break;
|
||||
|
||||
case PROP_ACCEPT_FOCUS:
|
||||
g_value_set_boolean (value, priv->accept_focus);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
@ -1992,9 +1946,6 @@ clutter_stage_finalize (GObject *object)
|
||||
if (priv->fps_timer != NULL)
|
||||
g_timer_destroy (priv->fps_timer);
|
||||
|
||||
if (priv->paint_notify != NULL)
|
||||
priv->paint_notify (priv->paint_data);
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -2036,18 +1987,6 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
||||
|
||||
klass->paint_view = clutter_stage_real_paint_view;
|
||||
|
||||
/**
|
||||
* ClutterStage:cursor-visible:
|
||||
*
|
||||
* Whether the mouse pointer should be visible
|
||||
*/
|
||||
obj_props[PROP_CURSOR_VISIBLE] =
|
||||
g_param_spec_boolean ("cursor-visible",
|
||||
P_("Cursor Visible"),
|
||||
P_("Whether the mouse pointer is visible on the main stage"),
|
||||
TRUE,
|
||||
CLUTTER_PARAM_READWRITE);
|
||||
|
||||
/**
|
||||
* ClutterStage:color:
|
||||
*
|
||||
@ -2077,7 +2016,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
||||
P_("Perspective"),
|
||||
P_("Perspective projection parameters"),
|
||||
CLUTTER_TYPE_PERSPECTIVE,
|
||||
CLUTTER_PARAM_READWRITE);
|
||||
CLUTTER_PARAM_READABLE);
|
||||
|
||||
/**
|
||||
* ClutterStage:title:
|
||||
@ -2093,23 +2032,6 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
||||
NULL,
|
||||
CLUTTER_PARAM_READWRITE);
|
||||
|
||||
/**
|
||||
* ClutterStage:use-alpha:
|
||||
*
|
||||
* Whether the #ClutterStage should honour the alpha component of the
|
||||
* #ClutterStage:color property when painting. If Clutter is run under
|
||||
* a compositing manager this will result in the stage being blended
|
||||
* with the underlying window(s)
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
obj_props[PROP_USE_ALPHA] =
|
||||
g_param_spec_boolean ("use-alpha",
|
||||
P_("Use Alpha"),
|
||||
P_("Whether to honour the alpha component of the stage color"),
|
||||
FALSE,
|
||||
CLUTTER_PARAM_READWRITE);
|
||||
|
||||
/**
|
||||
* ClutterStage:key-focus:
|
||||
*
|
||||
@ -2127,20 +2049,6 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
CLUTTER_PARAM_READWRITE);
|
||||
|
||||
/**
|
||||
* ClutterStage:accept-focus:
|
||||
*
|
||||
* Whether the #ClutterStage should accept key focus when shown.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
obj_props[PROP_ACCEPT_FOCUS] =
|
||||
g_param_spec_boolean ("accept-focus",
|
||||
P_("Accept Focus"),
|
||||
P_("Whether the stage should accept focus on show"),
|
||||
TRUE,
|
||||
CLUTTER_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
|
||||
|
||||
/**
|
||||
@ -2315,7 +2223,6 @@ clutter_stage_init (ClutterStage *self)
|
||||
|
||||
priv->event_queue = g_queue_new ();
|
||||
|
||||
priv->is_cursor_visible = TRUE;
|
||||
priv->throttle_motion_events = TRUE;
|
||||
priv->min_size_changed = FALSE;
|
||||
priv->sync_delay = -1;
|
||||
@ -2438,8 +2345,8 @@ clutter_stage_get_color (ClutterStage *stage,
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_set_perspective_internal (ClutterStage *stage,
|
||||
ClutterPerspective *perspective)
|
||||
clutter_stage_set_perspective (ClutterStage *stage,
|
||||
ClutterPerspective *perspective)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
|
||||
@ -2464,36 +2371,6 @@ clutter_stage_set_perspective_internal (ClutterStage *stage,
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_set_perspective:
|
||||
* @stage: A #ClutterStage
|
||||
* @perspective: A #ClutterPerspective
|
||||
*
|
||||
* Sets the stage perspective. Using this function is not recommended
|
||||
* because it will disable Clutter's attempts to generate an
|
||||
* appropriate perspective based on the size of the stage.
|
||||
*/
|
||||
void
|
||||
clutter_stage_set_perspective (ClutterStage *stage,
|
||||
ClutterPerspective *perspective)
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||
g_return_if_fail (perspective != NULL);
|
||||
g_return_if_fail (perspective->z_far - perspective->z_near != 0);
|
||||
|
||||
priv = stage->priv;
|
||||
|
||||
/* If the application ever calls this function then we'll stop
|
||||
automatically updating the perspective when the stage changes
|
||||
size */
|
||||
priv->has_custom_perspective = TRUE;
|
||||
|
||||
clutter_stage_set_perspective_internal (stage, perspective);
|
||||
clutter_stage_update_view_perspective (stage);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_get_perspective:
|
||||
* @stage: A #ClutterStage
|
||||
@ -2520,7 +2397,7 @@ clutter_stage_get_perspective (ClutterStage *stage,
|
||||
* @stage.
|
||||
*
|
||||
* Retrieves the @stage's projection matrix. This is derived from the
|
||||
* current perspective set using clutter_stage_set_perspective().
|
||||
* current perspective.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
@ -2684,72 +2561,6 @@ _clutter_stage_get_viewport (ClutterStage *stage,
|
||||
*height = priv->viewport[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_show_cursor:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Shows the cursor on the stage window
|
||||
*/
|
||||
void
|
||||
clutter_stage_show_cursor (ClutterStage *stage)
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||
|
||||
priv = stage->priv;
|
||||
if (!priv->is_cursor_visible)
|
||||
{
|
||||
ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
|
||||
ClutterStageWindowInterface *iface;
|
||||
|
||||
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
|
||||
if (iface->set_cursor_visible)
|
||||
{
|
||||
priv->is_cursor_visible = TRUE;
|
||||
|
||||
iface->set_cursor_visible (impl, TRUE);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (stage),
|
||||
obj_props[PROP_CURSOR_VISIBLE]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_hide_cursor:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Makes the cursor invisible on the stage window
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_stage_hide_cursor (ClutterStage *stage)
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||
|
||||
priv = stage->priv;
|
||||
if (priv->is_cursor_visible)
|
||||
{
|
||||
ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
|
||||
ClutterStageWindowInterface *iface;
|
||||
|
||||
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
|
||||
if (iface->set_cursor_visible)
|
||||
{
|
||||
priv->is_cursor_visible = FALSE;
|
||||
|
||||
iface->set_cursor_visible (impl, FALSE);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (stage),
|
||||
obj_props[PROP_CURSOR_VISIBLE]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_read_pixels:
|
||||
* @stage: A #ClutterStage
|
||||
@ -3301,30 +3112,20 @@ clutter_stage_update_view_perspective (ClutterStage *stage)
|
||||
|
||||
perspective = priv->perspective;
|
||||
|
||||
/* Ideally we want to regenerate the perspective matrix whenever
|
||||
* the size changes but if the user has provided a custom matrix
|
||||
* then we don't want to override it */
|
||||
if (!priv->has_custom_perspective)
|
||||
{
|
||||
perspective.fovy = 60.0; /* 60 Degrees */
|
||||
perspective.z_near = 0.1;
|
||||
perspective.aspect = priv->viewport[2] / priv->viewport[3];
|
||||
z_2d = calculate_z_translation (perspective.z_near);
|
||||
perspective.fovy = 60.0; /* 60 Degrees */
|
||||
perspective.z_near = 0.1;
|
||||
perspective.aspect = priv->viewport[2] / priv->viewport[3];
|
||||
z_2d = calculate_z_translation (perspective.z_near);
|
||||
|
||||
/* NB: z_2d is only enough room for 85% of the stage_height between
|
||||
* the stage and the z_near plane. For behind the stage plane we
|
||||
* want a more consistent gap of 10 times the stage_height before
|
||||
* hitting the far plane so we calculate that relative to the final
|
||||
* height of the stage plane at the z_2d_distance we got... */
|
||||
perspective.z_far = z_2d +
|
||||
tanf (_DEG_TO_RAD (perspective.fovy / 2.0f)) * z_2d * 20.0f;
|
||||
/* NB: z_2d is only enough room for 85% of the stage_height between
|
||||
* the stage and the z_near plane. For behind the stage plane we
|
||||
* want a more consistent gap of 10 times the stage_height before
|
||||
* hitting the far plane so we calculate that relative to the final
|
||||
* height of the stage plane at the z_2d_distance we got... */
|
||||
perspective.z_far = z_2d +
|
||||
tanf (_DEG_TO_RAD (perspective.fovy / 2.0f)) * z_2d * 20.0f;
|
||||
|
||||
clutter_stage_set_perspective_internal (stage, &perspective);
|
||||
}
|
||||
else
|
||||
{
|
||||
z_2d = calculate_z_translation (perspective.z_near);
|
||||
}
|
||||
clutter_stage_set_perspective (stage, &perspective);
|
||||
|
||||
cogl_matrix_init_identity (&priv->view);
|
||||
cogl_matrix_view_2d_in_perspective (&priv->view,
|
||||
@ -3554,56 +3355,6 @@ clutter_stage_get_throttle_motion_events (ClutterStage *stage)
|
||||
return stage->priv->throttle_motion_events;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_set_use_alpha:
|
||||
* @stage: a #ClutterStage
|
||||
* @use_alpha: whether the stage should honour the opacity or the
|
||||
* alpha channel of the stage color
|
||||
*
|
||||
* Sets whether the @stage should honour the #ClutterActor:opacity and
|
||||
* the alpha channel of the #ClutterStage:color
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
void
|
||||
clutter_stage_set_use_alpha (ClutterStage *stage,
|
||||
gboolean use_alpha)
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||
|
||||
priv = stage->priv;
|
||||
|
||||
if (priv->use_alpha != use_alpha)
|
||||
{
|
||||
priv->use_alpha = use_alpha;
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (stage), obj_props[PROP_USE_ALPHA]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_get_use_alpha:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Retrieves the value set using clutter_stage_set_use_alpha()
|
||||
*
|
||||
* Return value: %TRUE if the stage should honour the opacity and the
|
||||
* alpha channel of the stage color
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
gboolean
|
||||
clutter_stage_get_use_alpha (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
|
||||
|
||||
return stage->priv->use_alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_set_minimum_size:
|
||||
* @stage: a #ClutterStage
|
||||
@ -3950,56 +3701,6 @@ clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_set_accept_focus:
|
||||
* @stage: a #ClutterStage
|
||||
* @accept_focus: %TRUE to accept focus on show
|
||||
*
|
||||
* Sets whether the @stage should accept the key focus when shown.
|
||||
*
|
||||
* This function should be called before showing @stage using
|
||||
* clutter_actor_show().
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
void
|
||||
clutter_stage_set_accept_focus (ClutterStage *stage,
|
||||
gboolean accept_focus)
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||
|
||||
accept_focus = !!accept_focus;
|
||||
|
||||
priv = stage->priv;
|
||||
|
||||
if (priv->accept_focus != accept_focus)
|
||||
{
|
||||
_clutter_stage_window_set_accept_focus (priv->impl, accept_focus);
|
||||
g_object_notify_by_pspec (G_OBJECT (stage), obj_props[PROP_ACCEPT_FOCUS]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_get_accept_focus:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Retrieves the value set with clutter_stage_set_accept_focus().
|
||||
*
|
||||
* Return value: %TRUE if the #ClutterStage should accept focus, and %FALSE
|
||||
* otherwise
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
gboolean
|
||||
clutter_stage_get_accept_focus (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), TRUE);
|
||||
|
||||
return stage->priv->accept_focus;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_set_motion_events_enabled:
|
||||
* @stage: a #ClutterStage
|
||||
@ -4463,6 +4164,97 @@ clutter_stage_get_capture_final_size (ClutterStage *stage,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_paint_to_framebuffer (ClutterStage *stage,
|
||||
CoglFramebuffer *framebuffer,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
float scale,
|
||||
ClutterPaintFlag paint_flags)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
ClutterPaintContext *paint_context;
|
||||
cairo_region_t *redraw_clip;
|
||||
|
||||
redraw_clip = cairo_region_create_rectangle (rect);
|
||||
paint_context =
|
||||
clutter_paint_context_new_for_framebuffer (framebuffer,
|
||||
redraw_clip,
|
||||
paint_flags);
|
||||
cairo_region_destroy (redraw_clip);
|
||||
|
||||
cogl_framebuffer_push_matrix (framebuffer);
|
||||
cogl_framebuffer_set_projection_matrix (framebuffer, &priv->projection);
|
||||
cogl_framebuffer_set_viewport (framebuffer,
|
||||
-(rect->x * scale),
|
||||
-(rect->y * scale),
|
||||
priv->viewport[2] * scale,
|
||||
priv->viewport[3] * scale);
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage), paint_context);
|
||||
cogl_framebuffer_pop_matrix (framebuffer);
|
||||
|
||||
clutter_paint_context_destroy (paint_context);
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_stage_paint_to_buffer (ClutterStage *stage,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
float scale,
|
||||
uint8_t *data,
|
||||
int stride,
|
||||
CoglPixelFormat format,
|
||||
ClutterPaintFlag paint_flags,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
||||
CoglContext *cogl_context =
|
||||
clutter_backend_get_cogl_context (clutter_backend);
|
||||
int texture_width, texture_height;
|
||||
CoglTexture2D *texture;
|
||||
CoglOffscreen *offscreen;
|
||||
CoglFramebuffer *framebuffer;
|
||||
CoglBitmap *bitmap;
|
||||
|
||||
texture_width = (int) ceilf (rect->width * scale);
|
||||
texture_height = (int) ceilf (rect->height * scale);
|
||||
texture = cogl_texture_2d_new_with_size (cogl_context,
|
||||
texture_width,
|
||||
texture_height);
|
||||
if (!texture)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Failed to create %dx%d texture",
|
||||
texture_width, texture_height);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture));
|
||||
framebuffer = COGL_FRAMEBUFFER (offscreen);
|
||||
|
||||
cogl_object_unref (texture);
|
||||
|
||||
if (!cogl_framebuffer_allocate (framebuffer, error))
|
||||
return FALSE;
|
||||
|
||||
clutter_stage_paint_to_framebuffer (stage, framebuffer,
|
||||
rect, scale, paint_flags);
|
||||
|
||||
bitmap = cogl_bitmap_new_for_data (cogl_context,
|
||||
texture_width, texture_height,
|
||||
format,
|
||||
stride,
|
||||
data);
|
||||
|
||||
cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
|
||||
0, 0,
|
||||
COGL_READ_PIXELS_COLOR_BUFFER,
|
||||
bitmap);
|
||||
|
||||
cogl_object_unref (bitmap);
|
||||
cogl_object_unref (framebuffer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
capture_view_into (ClutterStage *stage,
|
||||
gboolean paint,
|
||||
@ -4610,8 +4402,11 @@ clutter_stage_thaw_updates (ClutterStage *stage)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_peek_stage_views: (skip)
|
||||
*/
|
||||
GList *
|
||||
_clutter_stage_peek_stage_views (ClutterStage *stage)
|
||||
clutter_stage_peek_stage_views (ClutterStage *stage)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
|
||||
|
@ -103,8 +103,7 @@ struct _ClutterStageClass
|
||||
* @z_far: the distance from the viewer to the far clipping
|
||||
* plane (always positive)
|
||||
*
|
||||
* Stage perspective definition. #ClutterPerspective is only used by
|
||||
* the fixed point version of clutter_stage_set_perspective().
|
||||
* Stage perspective definition.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
@ -140,17 +139,10 @@ GType clutter_stage_get_type (void) G_GNUC_CONST;
|
||||
CLUTTER_EXPORT
|
||||
ClutterActor * clutter_stage_new (void);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_set_perspective (ClutterStage *stage,
|
||||
ClutterPerspective *perspective);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_get_perspective (ClutterStage *stage,
|
||||
ClutterPerspective *perspective);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_show_cursor (ClutterStage *stage);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_hide_cursor (ClutterStage *stage);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_set_title (ClutterStage *stage,
|
||||
const gchar *title);
|
||||
CLUTTER_EXPORT
|
||||
@ -186,11 +178,6 @@ void clutter_stage_set_motion_events_enabled (ClutterStage
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_stage_get_motion_events_enabled (ClutterStage *stage);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_set_accept_focus (ClutterStage *stage,
|
||||
gboolean accept_focus);
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_stage_get_accept_focus (ClutterStage *stage);
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_stage_event (ClutterStage *stage,
|
||||
ClutterEvent *event);
|
||||
|
||||
|
@ -1907,14 +1907,6 @@ clutter_text_foreach_selection_rectangle (ClutterText *self,
|
||||
g_free (utf8);
|
||||
}
|
||||
|
||||
static void
|
||||
add_selection_rectangle_to_path (ClutterText *text,
|
||||
const ClutterActorBox *box,
|
||||
gpointer user_data)
|
||||
{
|
||||
cogl_path_rectangle (user_data, box->x1, box->y1, box->x2, box->y2);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_text_foreach_selection_rectangle_prescaled (ClutterText *self,
|
||||
ClutterTextSelectionFunc func,
|
||||
@ -1923,6 +1915,60 @@ clutter_text_foreach_selection_rectangle_prescaled (ClutterText *se
|
||||
clutter_text_foreach_selection_rectangle (self, 1.0f, func, user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
paint_selection_rectangle (ClutterText *self,
|
||||
const ClutterActorBox *box,
|
||||
gpointer user_data)
|
||||
{
|
||||
CoglFramebuffer *fb = user_data;
|
||||
ClutterTextPrivate *priv = self->priv;
|
||||
ClutterActor *actor = CLUTTER_ACTOR (self);
|
||||
guint8 paint_opacity = clutter_actor_get_paint_opacity (actor);
|
||||
CoglPipeline *color_pipeline = cogl_pipeline_copy (default_color_pipeline);
|
||||
PangoLayout *layout = clutter_text_get_layout (self);
|
||||
CoglColor cogl_color = { 0, };
|
||||
const ClutterColor *color;
|
||||
|
||||
/* Paint selection background */
|
||||
if (priv->selection_color_set)
|
||||
color = &priv->selection_color;
|
||||
else if (priv->cursor_color_set)
|
||||
color = &priv->cursor_color;
|
||||
else
|
||||
color = &priv->text_color;
|
||||
|
||||
cogl_color_init_from_4ub (&cogl_color,
|
||||
color->red,
|
||||
color->green,
|
||||
color->blue,
|
||||
paint_opacity * color->alpha / 255);
|
||||
cogl_color_premultiply (&cogl_color);
|
||||
cogl_pipeline_set_color (color_pipeline, &cogl_color);
|
||||
|
||||
cogl_framebuffer_push_rectangle_clip (fb,
|
||||
box->x1, box->y1,
|
||||
box->x2, box->y2);
|
||||
cogl_framebuffer_draw_rectangle (fb, color_pipeline,
|
||||
box->x1, box->y1,
|
||||
box->x2, box->y2);
|
||||
|
||||
if (priv->selected_text_color_set)
|
||||
color = &priv->selected_text_color;
|
||||
else
|
||||
color = &priv->text_color;
|
||||
|
||||
cogl_color_init_from_4ub (&cogl_color,
|
||||
color->red,
|
||||
color->green,
|
||||
color->blue,
|
||||
paint_opacity * color->alpha / 255);
|
||||
|
||||
cogl_pango_show_layout (fb, layout, priv->text_x, 0, &cogl_color);
|
||||
|
||||
cogl_framebuffer_pop_clip (fb);
|
||||
cogl_object_unref (color_pipeline);
|
||||
}
|
||||
|
||||
/* Draws the selected text, its background, and the cursor */
|
||||
static void
|
||||
selection_paint (ClutterText *self,
|
||||
@ -1965,52 +2011,9 @@ selection_paint (ClutterText *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Paint selection background first */
|
||||
CoglPipeline *color_pipeline = cogl_pipeline_copy (default_color_pipeline);
|
||||
PangoLayout *layout = clutter_text_get_layout (self);
|
||||
CoglPath *selection_path = cogl_path_new ();
|
||||
CoglColor cogl_color = { 0, };
|
||||
|
||||
/* Paint selection background */
|
||||
if (priv->selection_color_set)
|
||||
color = &priv->selection_color;
|
||||
else if (priv->cursor_color_set)
|
||||
color = &priv->cursor_color;
|
||||
else
|
||||
color = &priv->text_color;
|
||||
|
||||
cogl_color_init_from_4ub (&cogl_color,
|
||||
color->red,
|
||||
color->green,
|
||||
color->blue,
|
||||
paint_opacity * color->alpha / 255);
|
||||
cogl_color_premultiply (&cogl_color);
|
||||
cogl_pipeline_set_color (color_pipeline, &cogl_color);
|
||||
|
||||
clutter_text_foreach_selection_rectangle_prescaled (self,
|
||||
add_selection_rectangle_to_path,
|
||||
selection_path);
|
||||
|
||||
cogl_framebuffer_fill_path (fb, color_pipeline, selection_path);
|
||||
|
||||
/* Paint selected text */
|
||||
cogl_framebuffer_push_path_clip (fb, selection_path);
|
||||
cogl_object_unref (selection_path);
|
||||
|
||||
if (priv->selected_text_color_set)
|
||||
color = &priv->selected_text_color;
|
||||
else
|
||||
color = &priv->text_color;
|
||||
|
||||
cogl_color_init_from_4ub (&cogl_color,
|
||||
color->red,
|
||||
color->green,
|
||||
color->blue,
|
||||
paint_opacity * color->alpha / 255);
|
||||
|
||||
cogl_pango_show_layout (fb, layout, priv->text_x, 0, &cogl_color);
|
||||
|
||||
cogl_framebuffer_pop_clip (fb);
|
||||
paint_selection_rectangle,
|
||||
fb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,8 +56,6 @@
|
||||
#include "clutter-content.h"
|
||||
#include "clutter-deform-effect.h"
|
||||
#include "clutter-desaturate-effect.h"
|
||||
#include "clutter-drag-action.h"
|
||||
#include "clutter-drop-action.h"
|
||||
#include "clutter-effect.h"
|
||||
#include "clutter-enums.h"
|
||||
#include "clutter-enum-types.h"
|
||||
|
@ -375,15 +375,11 @@ static gboolean
|
||||
swap_framebuffer (ClutterStageWindow *stage_window,
|
||||
ClutterStageView *view,
|
||||
cairo_region_t *swap_region,
|
||||
gboolean swap_with_damage,
|
||||
cairo_region_t *queued_redraw_clip)
|
||||
gboolean swap_with_damage)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
|
||||
int *damage, n_rects, i;
|
||||
|
||||
if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION)))
|
||||
paint_damage_region (stage_window, view, swap_region, queued_redraw_clip);
|
||||
|
||||
n_rects = cairo_region_num_rectangles (swap_region);
|
||||
damage = g_newa (int, n_rects * 4);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
@ -620,7 +616,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
gboolean swap_with_damage;
|
||||
ClutterActor *wrapper;
|
||||
cairo_region_t *redraw_clip;
|
||||
cairo_region_t *queued_redraw_clip;
|
||||
cairo_region_t *queued_redraw_clip = NULL;
|
||||
cairo_region_t *fb_clip_region;
|
||||
cairo_region_t *swap_region;
|
||||
cairo_rectangle_int_t redraw_rect;
|
||||
@ -644,6 +640,8 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
has_buffer_age = cogl_is_onscreen (fb) && is_buffer_age_enabled ();
|
||||
|
||||
redraw_clip = clutter_stage_view_take_redraw_clip (view);
|
||||
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION))
|
||||
queued_redraw_clip = cairo_region_copy (redraw_clip);
|
||||
|
||||
/* NB: a NULL redraw clip == full stage redraw */
|
||||
if (!redraw_clip)
|
||||
@ -711,8 +709,6 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
redraw_clip = cairo_region_create_rectangle (&view_rect);
|
||||
}
|
||||
|
||||
queued_redraw_clip = cairo_region_copy (redraw_clip);
|
||||
|
||||
if (may_use_clipped_redraw &&
|
||||
G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
|
||||
use_clipped_redraw = TRUE;
|
||||
@ -922,7 +918,6 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
}
|
||||
|
||||
g_clear_pointer (&redraw_clip, cairo_region_destroy);
|
||||
g_clear_pointer (&queued_redraw_clip, cairo_region_destroy);
|
||||
g_clear_pointer (&fb_clip_region, cairo_region_destroy);
|
||||
|
||||
if (do_swap_buffer)
|
||||
@ -943,11 +938,17 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
swap_region = transformed_swap_region;
|
||||
}
|
||||
|
||||
if (queued_redraw_clip)
|
||||
{
|
||||
paint_damage_region (stage_window, view,
|
||||
swap_region, queued_redraw_clip);
|
||||
cairo_region_destroy (queued_redraw_clip);
|
||||
}
|
||||
|
||||
res = swap_framebuffer (stage_window,
|
||||
view,
|
||||
swap_region,
|
||||
swap_with_damage,
|
||||
queued_redraw_clip);
|
||||
swap_with_damage);
|
||||
|
||||
cairo_region_destroy (swap_region);
|
||||
|
||||
@ -955,10 +956,25 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_pointer (&queued_redraw_clip, cairo_region_destroy);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
|
||||
ClutterStageView *view,
|
||||
CoglScanout *scanout)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
|
||||
CoglOnscreen *onscreen;
|
||||
|
||||
g_return_if_fail (cogl_is_onscreen (framebuffer));
|
||||
|
||||
onscreen = COGL_ONSCREEN (framebuffer);
|
||||
cogl_onscreen_direct_scanout (onscreen, scanout);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
{
|
||||
@ -971,11 +987,23 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
g_autoptr (CoglScanout) scanout = NULL;
|
||||
|
||||
if (!clutter_stage_view_has_redraw_clip (view))
|
||||
continue;
|
||||
|
||||
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
|
||||
scanout = clutter_stage_view_take_scanout (view);
|
||||
if (scanout)
|
||||
{
|
||||
clutter_stage_cogl_scanout_view (stage_cogl,
|
||||
view,
|
||||
scanout);
|
||||
swap_event = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
|
||||
}
|
||||
}
|
||||
|
||||
_clutter_stage_emit_after_paint (stage_cogl->wrapper);
|
||||
|
@ -30,8 +30,6 @@ clutter_headers = [
|
||||
'clutter-deform-effect.h',
|
||||
'clutter-deprecated.h',
|
||||
'clutter-desaturate-effect.h',
|
||||
'clutter-drag-action.h',
|
||||
'clutter-drop-action.h',
|
||||
'clutter-effect.h',
|
||||
'clutter-enums.h',
|
||||
'clutter-event.h',
|
||||
@ -118,8 +116,6 @@ clutter_sources = [
|
||||
'clutter-content.c',
|
||||
'clutter-deform-effect.c',
|
||||
'clutter-desaturate-effect.c',
|
||||
'clutter-drag-action.c',
|
||||
'clutter-drop-action.c',
|
||||
'clutter-effect.c',
|
||||
'clutter-event.c',
|
||||
'clutter-feature.c',
|
||||
@ -341,35 +337,20 @@ clutter_build_config_h = configure_file(
|
||||
)
|
||||
clutter_built_private_headers += clutter_build_config_h
|
||||
|
||||
clutter_config_defines = []
|
||||
cdata = configuration_data()
|
||||
if have_wayland
|
||||
clutter_config_defines += [
|
||||
'#define CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT 1',
|
||||
]
|
||||
cdata.set10('CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT', true)
|
||||
endif
|
||||
if have_x11
|
||||
clutter_config_defines += [
|
||||
'#define CLUTTER_WINDOWING_X11 "x11"',
|
||||
'#define CLUTTER_INPUT_X11 "x11"',
|
||||
'#define CLUTTER_WINDOWING_GLX "glx"',
|
||||
]
|
||||
cdata.set_quoted('CLUTTER_WINDOWING_X11', 'x11')
|
||||
cdata.set_quoted('CLUTTER_INPUT_X11', 'x11')
|
||||
cdata.set_quoted('CLUTTER_WINDOWING_GLX', 'glx')
|
||||
endif
|
||||
if have_native_backend
|
||||
clutter_config_defines += [
|
||||
'#define CLUTTER_WINDOWING_EGL "eglnative"',
|
||||
'#define CLUTTER_INPUT_EVDEV "evdev"',
|
||||
]
|
||||
cdata.set_quoted('CLUTTER_WINDOWING_EGL', 'eglnative')
|
||||
cdata.set_quoted('CLUTTER_INPUT_EVDEV', 'evdev')
|
||||
endif
|
||||
clutter_config_defines += [
|
||||
'#define CLUTTER_INPUT_NULL "null"',
|
||||
]
|
||||
clutter_config_defines_string = ''
|
||||
foreach clutter_config_define : clutter_config_defines
|
||||
clutter_config_defines_string += clutter_config_define + '\n'
|
||||
endforeach
|
||||
|
||||
cdata = configuration_data()
|
||||
cdata.set('CLUTTER_CONFIG_DEFINES', clutter_config_defines_string)
|
||||
cdata.set_quoted('CLUTTER_INPUT_NULL', 'null')
|
||||
|
||||
clutter_config_h = configure_file(
|
||||
input: 'clutter-config.h.in',
|
||||
@ -429,7 +410,6 @@ libmutter_clutter = shared_library(libmutter_clutter_name,
|
||||
link_with: [
|
||||
libmutter_cogl,
|
||||
libmutter_cogl_pango,
|
||||
libmutter_cogl_path,
|
||||
],
|
||||
install_rpath: pkglibdir,
|
||||
install_dir: pkglibdir,
|
||||
|
2
cogl/.gitignore
vendored
2
cogl/.gitignore
vendored
@ -36,8 +36,6 @@ cogl-egl-defines.h
|
||||
cogl-enum-types.c
|
||||
cogl-enum-types.h
|
||||
cogl-gl-header.h
|
||||
cogl-path-enum-types.c
|
||||
cogl-path-enum-types.h
|
||||
cogl-config.h
|
||||
cogl-config.h.in
|
||||
cogl-mutter-config.h
|
||||
|
@ -74,7 +74,7 @@ PangoFontMap *
|
||||
cogl_pango_font_map_new (void)
|
||||
{
|
||||
PangoFontMap *fm = pango_cairo_font_map_new ();
|
||||
CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
|
||||
g_autofree CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
|
||||
|
||||
_COGL_GET_CONTEXT (context, NULL);
|
||||
|
||||
@ -85,7 +85,7 @@ cogl_pango_font_map_new (void)
|
||||
* for now. */
|
||||
g_object_set_qdata_full (G_OBJECT (fm),
|
||||
cogl_pango_font_map_get_priv_key (),
|
||||
priv,
|
||||
g_steal_pointer (&priv),
|
||||
free_priv);
|
||||
|
||||
return fm;
|
||||
|
@ -25,7 +25,7 @@ libmutter_cogl_pango = shared_library('mutter-cogl-pango-' + libmutter_api_versi
|
||||
version: '0.0.0',
|
||||
soversion: 0,
|
||||
c_args: cogl_c_args,
|
||||
include_directories: [cogl_includepath, cogl_path_includepath],
|
||||
include_directories: [cogl_includepath],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
dependencies: [cogl_pango_deps],
|
||||
install_rpath: pkglibdir,
|
||||
|
@ -1,48 +0,0 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#include "cogl-config.h"
|
||||
|
||||
/* We need to undefine this so that we will be sure to include
|
||||
* cogl-path.h instead of cogl2-path.h when we include the framebuffer
|
||||
* header. Otherwise it will include both headers and it won't
|
||||
* compile. */
|
||||
#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
|
||||
|
||||
#include "cogl-path-enum-types.h"
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
|
||||
/* enumerations from "@filename@" */
|
||||
#include "@filename@"
|
||||
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType
|
||||
@enum_name@_get_type (void)
|
||||
{
|
||||
static volatile gsize g_enum_type_id__volatile = 0;
|
||||
|
||||
if (g_once_init_enter (&g_enum_type_id__volatile))
|
||||
{
|
||||
static const G@Type@Value values[] = {
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN value-production ***/
|
||||
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
|
||||
/*** END value-production ***/
|
||||
|
||||
/*** BEGIN value-tail ***/
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType g_enum_type_id;
|
||||
|
||||
g_enum_type_id =
|
||||
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
|
||||
|
||||
g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
|
||||
}
|
||||
|
||||
return g_enum_type_id__volatile;
|
||||
}
|
||||
/*** END value-tail ***/
|
@ -1,25 +0,0 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#ifndef __COGL_PATH_ENUM_TYPES_H__
|
||||
#define __COGL_PATH_ENUM_TYPES_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
/* enumerations from "@basename@" */
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN file-tail ***/
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COGL_PATH_ENUM_TYPES_H__ */
|
||||
/*** END file-tail ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType @enum_name@_get_type (void) G_GNUC_CONST;
|
||||
#define COGL_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
|
||||
|
||||
/*** END value-header ***/
|
@ -1,487 +0,0 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2008,2009,2013 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
|
||||
#error "Only <cogl/cogl.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COGL_PATH_FUNCTIONS_H__
|
||||
#define __COGL_PATH_FUNCTIONS_H__
|
||||
|
||||
#include <cogl/cogl-types.h>
|
||||
#ifdef COGL_COMPILATION
|
||||
#include "cogl-context.h"
|
||||
#else
|
||||
#include <cogl/cogl.h>
|
||||
#endif
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* cogl_path_get_gtype:
|
||||
*
|
||||
* Returns: a #GType that can be used with the GLib type system.
|
||||
*/
|
||||
COGL_EXPORT
|
||||
GType cogl_path_get_gtype (void);
|
||||
|
||||
#define cogl_path_new cogl2_path_new
|
||||
/**
|
||||
* cogl_path_new:
|
||||
*
|
||||
* Creates a new, empty path object. The default fill rule is
|
||||
* %COGL_PATH_FILL_RULE_EVEN_ODD.
|
||||
*
|
||||
* Return value: A pointer to a newly allocated #CoglPath, which can
|
||||
* be freed using cogl_object_unref().
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT CoglPath *
|
||||
cogl_path_new (void);
|
||||
|
||||
/**
|
||||
* cogl_path_copy:
|
||||
* @path: A #CoglPath object
|
||||
*
|
||||
* Returns a new copy of the path in @path. The new path has a
|
||||
* reference count of 1 so you should unref it with
|
||||
* cogl_object_unref() if you no longer need it.
|
||||
*
|
||||
* Internally the path will share the data until one of the paths is
|
||||
* modified so copying paths should be relatively cheap.
|
||||
*
|
||||
* Return value: (transfer full): a copy of the path in @path.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT CoglPath *
|
||||
cogl_path_copy (CoglPath *path);
|
||||
|
||||
/**
|
||||
* cogl_is_path:
|
||||
* @object: A #CoglObject
|
||||
*
|
||||
* Gets whether the given object references an existing path object.
|
||||
*
|
||||
* Return value: %TRUE if the object references a #CoglPath,
|
||||
* %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT gboolean
|
||||
cogl_is_path (void *object);
|
||||
|
||||
#define cogl_path_move_to cogl2_path_move_to
|
||||
/**
|
||||
* cogl_path_move_to:
|
||||
* @x: X coordinate of the pen location to move to.
|
||||
* @y: Y coordinate of the pen location to move to.
|
||||
*
|
||||
* Moves the pen to the given location. If there is an existing path
|
||||
* this will start a new disjoint subpath.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_move_to (CoglPath *path,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
#define cogl_path_rel_move_to cogl2_path_rel_move_to
|
||||
/**
|
||||
* cogl_path_rel_move_to:
|
||||
* @x: X offset from the current pen location to move the pen to.
|
||||
* @y: Y offset from the current pen location to move the pen to.
|
||||
*
|
||||
* Moves the pen to the given offset relative to the current pen
|
||||
* location. If there is an existing path this will start a new
|
||||
* disjoint subpath.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_rel_move_to (CoglPath *path,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
#define cogl_path_line_to cogl2_path_line_to
|
||||
/**
|
||||
* cogl_path_line_to:
|
||||
* @x: X coordinate of the end line vertex
|
||||
* @y: Y coordinate of the end line vertex
|
||||
*
|
||||
* Adds a straight line segment to the current path that ends at the
|
||||
* given coordinates.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_line_to (CoglPath *path,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
#define cogl_path_rel_line_to cogl2_path_rel_line_to
|
||||
/**
|
||||
* cogl_path_rel_line_to:
|
||||
* @x: X offset from the current pen location of the end line vertex
|
||||
* @y: Y offset from the current pen location of the end line vertex
|
||||
*
|
||||
* Adds a straight line segment to the current path that ends at the
|
||||
* given coordinates relative to the current pen location.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_rel_line_to (CoglPath *path,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
#define cogl_path_arc cogl2_path_arc
|
||||
/**
|
||||
* cogl_path_arc:
|
||||
* @center_x: X coordinate of the elliptical arc center
|
||||
* @center_y: Y coordinate of the elliptical arc center
|
||||
* @radius_x: X radius of the elliptical arc
|
||||
* @radius_y: Y radius of the elliptical arc
|
||||
* @angle_1: Angle in degrees at which the arc begin
|
||||
* @angle_2: Angle in degrees at which the arc ends
|
||||
*
|
||||
* Adds an elliptical arc segment to the current path. A straight line
|
||||
* segment will link the current pen location with the first vertex
|
||||
* of the arc. If you perform a move_to to the arcs start just before
|
||||
* drawing it you create a free standing arc.
|
||||
*
|
||||
* The angles are measured in degrees where 0° is in the direction of
|
||||
* the positive X axis and 90° is in the direction of the positive Y
|
||||
* axis. The angle of the arc begins at @angle_1 and heads towards
|
||||
* @angle_2 (so if @angle_2 is less than @angle_1 it will decrease,
|
||||
* otherwise it will increase).
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_arc (CoglPath *path,
|
||||
float center_x,
|
||||
float center_y,
|
||||
float radius_x,
|
||||
float radius_y,
|
||||
float angle_1,
|
||||
float angle_2);
|
||||
|
||||
#define cogl_path_curve_to cogl2_path_curve_to
|
||||
/**
|
||||
* cogl_path_curve_to:
|
||||
* @x_1: X coordinate of the second bezier control point
|
||||
* @y_1: Y coordinate of the second bezier control point
|
||||
* @x_2: X coordinate of the third bezier control point
|
||||
* @y_2: Y coordinate of the third bezier control point
|
||||
* @x_3: X coordinate of the fourth bezier control point
|
||||
* @y_3: Y coordinate of the fourth bezier control point
|
||||
*
|
||||
* Adds a cubic bezier curve segment to the current path with the given
|
||||
* second, third and fourth control points and using current pen location
|
||||
* as the first control point.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_curve_to (CoglPath *path,
|
||||
float x_1,
|
||||
float y_1,
|
||||
float x_2,
|
||||
float y_2,
|
||||
float x_3,
|
||||
float y_3);
|
||||
|
||||
#define cogl_path_rel_curve_to cogl2_path_rel_curve_to
|
||||
/**
|
||||
* cogl_path_rel_curve_to:
|
||||
* @x_1: X coordinate of the second bezier control point
|
||||
* @y_1: Y coordinate of the second bezier control point
|
||||
* @x_2: X coordinate of the third bezier control point
|
||||
* @y_2: Y coordinate of the third bezier control point
|
||||
* @x_3: X coordinate of the fourth bezier control point
|
||||
* @y_3: Y coordinate of the fourth bezier control point
|
||||
*
|
||||
* Adds a cubic bezier curve segment to the current path with the given
|
||||
* second, third and fourth control points and using current pen location
|
||||
* as the first control point. The given coordinates are relative to the
|
||||
* current pen location.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_rel_curve_to (CoglPath *path,
|
||||
float x_1,
|
||||
float y_1,
|
||||
float x_2,
|
||||
float y_2,
|
||||
float x_3,
|
||||
float y_3);
|
||||
|
||||
#define cogl_path_close cogl2_path_close
|
||||
/**
|
||||
* cogl_path_close:
|
||||
*
|
||||
* Closes the path being constructed by adding a straight line segment
|
||||
* to it that ends at the first vertex of the path.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_close (CoglPath *path);
|
||||
|
||||
#define cogl_path_line cogl2_path_line
|
||||
/**
|
||||
* cogl_path_line:
|
||||
* @x_1: X coordinate of the start line vertex
|
||||
* @y_1: Y coordinate of the start line vertex
|
||||
* @x_2: X coordinate of the end line vertex
|
||||
* @y_2: Y coordinate of the end line vertex
|
||||
*
|
||||
* Constructs a straight line shape starting and ending at the given
|
||||
* coordinates. If there is an existing path this will start a new
|
||||
* disjoint sub-path.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_line (CoglPath *path,
|
||||
float x_1,
|
||||
float y_1,
|
||||
float x_2,
|
||||
float y_2);
|
||||
|
||||
#define cogl_path_polyline cogl2_path_polyline
|
||||
/**
|
||||
* cogl_path_polyline:
|
||||
* @coords: (in) (array) (transfer none): A pointer to the first element of an
|
||||
* array of fixed-point values that specify the vertex coordinates.
|
||||
* @num_points: The total number of vertices.
|
||||
*
|
||||
* Constructs a series of straight line segments, starting from the
|
||||
* first given vertex coordinate. If there is an existing path this
|
||||
* will start a new disjoint sub-path. Each subsequent segment starts
|
||||
* where the previous one ended and ends at the next given vertex
|
||||
* coordinate.
|
||||
*
|
||||
* The coords array must contain 2 * num_points values. The first value
|
||||
* represents the X coordinate of the first vertex, the second value
|
||||
* represents the Y coordinate of the first vertex, continuing in the same
|
||||
* fashion for the rest of the vertices. (num_points - 1) segments will
|
||||
* be constructed.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_polyline (CoglPath *path,
|
||||
const float *coords,
|
||||
int num_points);
|
||||
|
||||
#define cogl_path_polygon cogl2_path_polygon
|
||||
/**
|
||||
* cogl_path_polygon:
|
||||
* @coords: (in) (array) (transfer none): A pointer to the first element of
|
||||
* an array of fixed-point values that specify the vertex coordinates.
|
||||
* @num_points: The total number of vertices.
|
||||
*
|
||||
* Constructs a polygonal shape of the given number of vertices. If
|
||||
* there is an existing path this will start a new disjoint sub-path.
|
||||
*
|
||||
* The coords array must contain 2 * num_points values. The first value
|
||||
* represents the X coordinate of the first vertex, the second value
|
||||
* represents the Y coordinate of the first vertex, continuing in the same
|
||||
* fashion for the rest of the vertices.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_polygon (CoglPath *path,
|
||||
const float *coords,
|
||||
int num_points);
|
||||
|
||||
#define cogl_path_rectangle cogl2_path_rectangle
|
||||
/**
|
||||
* cogl_path_rectangle:
|
||||
* @x_1: X coordinate of the top-left corner.
|
||||
* @y_1: Y coordinate of the top-left corner.
|
||||
* @x_2: X coordinate of the bottom-right corner.
|
||||
* @y_2: Y coordinate of the bottom-right corner.
|
||||
*
|
||||
* Constructs a rectangular shape at the given coordinates. If there
|
||||
* is an existing path this will start a new disjoint sub-path.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_rectangle (CoglPath *path,
|
||||
float x_1,
|
||||
float y_1,
|
||||
float x_2,
|
||||
float y_2);
|
||||
|
||||
#define cogl_path_ellipse cogl2_path_ellipse
|
||||
/**
|
||||
* cogl_path_ellipse:
|
||||
* @center_x: X coordinate of the ellipse center
|
||||
* @center_y: Y coordinate of the ellipse center
|
||||
* @radius_x: X radius of the ellipse
|
||||
* @radius_y: Y radius of the ellipse
|
||||
*
|
||||
* Constructs an ellipse shape. If there is an existing path this will
|
||||
* start a new disjoint sub-path.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_ellipse (CoglPath *path,
|
||||
float center_x,
|
||||
float center_y,
|
||||
float radius_x,
|
||||
float radius_y);
|
||||
|
||||
#define cogl_path_round_rectangle cogl2_path_round_rectangle
|
||||
/**
|
||||
* cogl_path_round_rectangle:
|
||||
* @x_1: X coordinate of the top-left corner.
|
||||
* @y_1: Y coordinate of the top-left corner.
|
||||
* @x_2: X coordinate of the bottom-right corner.
|
||||
* @y_2: Y coordinate of the bottom-right corner.
|
||||
* @radius: Radius of the corner arcs.
|
||||
* @arc_step: Angle increment resolution for subdivision of
|
||||
* the corner arcs.
|
||||
*
|
||||
* Constructs a rectangular shape with rounded corners. If there is an
|
||||
* existing path this will start a new disjoint sub-path.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_round_rectangle (CoglPath *path,
|
||||
float x_1,
|
||||
float y_1,
|
||||
float x_2,
|
||||
float y_2,
|
||||
float radius,
|
||||
float arc_step);
|
||||
|
||||
#define cogl_path_set_fill_rule cogl2_path_set_fill_rule
|
||||
/**
|
||||
* cogl_path_set_fill_rule:
|
||||
* @fill_rule: The new fill rule.
|
||||
*
|
||||
* Sets the fill rule of the current path to @fill_rule. This will
|
||||
* affect how the path is filled when cogl_path_fill() is later
|
||||
* called. Note that the fill rule state is attached to the path so
|
||||
* calling cogl_get_path() will preserve the fill rule and calling
|
||||
* cogl_path_new() will reset the fill rule back to the default.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_path_set_fill_rule (CoglPath *path, CoglPathFillRule fill_rule);
|
||||
|
||||
#define cogl_path_get_fill_rule cogl2_path_get_fill_rule
|
||||
/**
|
||||
* cogl_path_get_fill_rule:
|
||||
*
|
||||
* Retrieves the fill rule set using cogl_path_set_fill_rule().
|
||||
*
|
||||
* Return value: the fill rule that is used for the current path.
|
||||
*
|
||||
* Since: 2.0
|
||||
*/
|
||||
COGL_EXPORT CoglPathFillRule
|
||||
cogl_path_get_fill_rule (CoglPath *path);
|
||||
|
||||
/**
|
||||
* cogl_framebuffer_fill_path:
|
||||
* @framebuffer: A #CoglFramebuffer
|
||||
* @pipeline: A #CoglPipeline to render with
|
||||
* @path: The #CoglPath to fill
|
||||
*
|
||||
* Fills the interior of the path using the fragment operations
|
||||
* defined by the pipeline.
|
||||
*
|
||||
* The interior of the shape is determined using the fill rule of the
|
||||
* path. See %CoglPathFillRule for details.
|
||||
*
|
||||
* <note>The result of referencing sliced textures in your current
|
||||
* pipeline when filling a path are undefined. You should pass
|
||||
* the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will
|
||||
* use while filling a path.</note>
|
||||
*
|
||||
* Stability: unstable
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
|
||||
CoglPipeline *pipeline,
|
||||
CoglPath *path);
|
||||
|
||||
/**
|
||||
* cogl_framebuffer_stroke_path:
|
||||
* @framebuffer: A #CoglFramebuffer
|
||||
* @pipeline: A #CoglPipeline to render with
|
||||
* @path: The #CoglPath to stroke
|
||||
*
|
||||
* Strokes the edge of the path using the fragment operations defined
|
||||
* by the pipeline. The stroke line will have a width of 1 pixel
|
||||
* regardless of the current transformation matrix.
|
||||
*
|
||||
* Stability: unstable
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
|
||||
CoglPipeline *pipeline,
|
||||
CoglPath *path);
|
||||
|
||||
/**
|
||||
* cogl_framebuffer_push_path_clip:
|
||||
* @framebuffer: A #CoglFramebuffer pointer
|
||||
* @path: The path to clip with.
|
||||
*
|
||||
* Sets a new clipping area using the silhouette of the specified,
|
||||
* filled @path. The clipping area is intersected with the previous
|
||||
* clipping area. To restore the previous clipping area, call
|
||||
* cogl_framebuffer_pop_clip().
|
||||
*
|
||||
* Since: 1.0
|
||||
* Stability: unstable
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
|
||||
CoglPath *path);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COGL_PATH_FUNCTIONS_H__ */
|
||||
|
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2010 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __COGL_PATH_PRIVATE_H
|
||||
#define __COGL_PATH_PRIVATE_H
|
||||
|
||||
#include "cogl-object.h"
|
||||
#include "cogl-attribute-private.h"
|
||||
|
||||
typedef struct _floatVec2
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} floatVec2;
|
||||
|
||||
typedef struct _CoglPathNode
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
unsigned int path_size;
|
||||
} CoglPathNode;
|
||||
|
||||
typedef struct _CoglBezQuad
|
||||
{
|
||||
floatVec2 p1;
|
||||
floatVec2 p2;
|
||||
floatVec2 p3;
|
||||
} CoglBezQuad;
|
||||
|
||||
typedef struct _CoglBezCubic
|
||||
{
|
||||
floatVec2 p1;
|
||||
floatVec2 p2;
|
||||
floatVec2 p3;
|
||||
floatVec2 p4;
|
||||
} CoglBezCubic;
|
||||
|
||||
typedef struct _CoglPathData CoglPathData;
|
||||
|
||||
struct _CoglPath
|
||||
{
|
||||
CoglObject _parent;
|
||||
|
||||
CoglPathData *data;
|
||||
};
|
||||
|
||||
#define COGL_PATH_N_ATTRIBUTES 2
|
||||
|
||||
struct _CoglPathData
|
||||
{
|
||||
unsigned int ref_count;
|
||||
|
||||
CoglContext *context;
|
||||
|
||||
CoglPathFillRule fill_rule;
|
||||
|
||||
GArray *path_nodes;
|
||||
|
||||
floatVec2 path_start;
|
||||
floatVec2 path_pen;
|
||||
unsigned int last_path;
|
||||
floatVec2 path_nodes_min;
|
||||
floatVec2 path_nodes_max;
|
||||
|
||||
CoglAttributeBuffer *fill_attribute_buffer;
|
||||
CoglIndices *fill_vbo_indices;
|
||||
unsigned int fill_vbo_n_indices;
|
||||
CoglAttribute *fill_attributes[COGL_PATH_N_ATTRIBUTES + 1];
|
||||
CoglPrimitive *fill_primitive;
|
||||
|
||||
CoglAttributeBuffer *stroke_attribute_buffer;
|
||||
CoglAttribute **stroke_attributes;
|
||||
unsigned int stroke_n_attributes;
|
||||
|
||||
/* This is used as an optimisation for when the path contains a
|
||||
single contour specified using cogl2_path_rectangle. Cogl is more
|
||||
optimised to handle rectangles than paths so we can detect this
|
||||
case and divert to the journal or a rectangle clip. If it is TRUE
|
||||
then the entire path can be described by calling
|
||||
_cogl_path_get_bounds */
|
||||
gboolean is_rectangle;
|
||||
};
|
||||
|
||||
void
|
||||
_cogl_add_path_to_stencil_buffer (CoglPath *path,
|
||||
gboolean merge,
|
||||
gboolean need_clear);
|
||||
|
||||
void
|
||||
_cogl_path_get_bounds (CoglPath *path,
|
||||
float *min_x,
|
||||
float *min_y,
|
||||
float *max_x,
|
||||
float *max_y);
|
||||
|
||||
gboolean
|
||||
_cogl_path_is_rectangle (CoglPath *path);
|
||||
|
||||
#endif /* __COGL_PATH_PRIVATE_H */
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2008,2009,2013 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
|
||||
#error "Only <cogl/cogl.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COGL_PATH_TYPES_H__
|
||||
#define __COGL_PATH_TYPES_H__
|
||||
|
||||
#include <cogl/cogl-types.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _CoglPath CoglPath;
|
||||
|
||||
/**
|
||||
* CoglPathFillRule:
|
||||
* @COGL_PATH_FILL_RULE_NON_ZERO: Each time the line crosses an edge of
|
||||
* the path from left to right one is added to a counter and each time
|
||||
* it crosses from right to left the counter is decremented. If the
|
||||
* counter is non-zero then the point will be filled. See <xref
|
||||
* linkend="fill-rule-non-zero"/>.
|
||||
* @COGL_PATH_FILL_RULE_EVEN_ODD: If the line crosses an edge of the
|
||||
* path an odd number of times then the point will filled, otherwise
|
||||
* it won't. See <xref linkend="fill-rule-even-odd"/>.
|
||||
*
|
||||
* #CoglPathFillRule is used to determine how a path is filled. There
|
||||
* are two options - 'non-zero' and 'even-odd'. To work out whether any
|
||||
* point will be filled imagine drawing an infinetely long line in any
|
||||
* direction from that point. The number of times and the direction
|
||||
* that the edges of the path crosses this line determines whether the
|
||||
* line is filled as described below. Any open sub paths are treated
|
||||
* as if there was an extra line joining the first point and the last
|
||||
* point.
|
||||
*
|
||||
* The default fill rule when creating a path is %COGL_PATH_FILL_RULE_EVEN_ODD.
|
||||
*
|
||||
* <figure id="fill-rule-non-zero">
|
||||
* <title>Example of filling various paths using the non-zero rule</title>
|
||||
* <graphic fileref="fill-rule-non-zero.png" format="PNG"/>
|
||||
* </figure>
|
||||
*
|
||||
* <figure id="fill-rule-even-odd">
|
||||
* <title>Example of filling various paths using the even-odd rule</title>
|
||||
* <graphic fileref="fill-rule-even-odd.png" format="PNG"/>
|
||||
* </figure>
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
COGL_PATH_FILL_RULE_NON_ZERO,
|
||||
COGL_PATH_FILL_RULE_EVEN_ODD
|
||||
} CoglPathFillRule;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COGL_PATH_TYPES_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2008,2009,2013 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __COGL_PATH_H__
|
||||
#define __COGL_PATH_H__
|
||||
|
||||
/**
|
||||
* SECTION:cogl-paths
|
||||
* @short_description: Functions for constructing and drawing 2D paths.
|
||||
*
|
||||
* There are two levels on which drawing with cogl-paths can be used.
|
||||
* The highest level functions construct various simple primitive
|
||||
* shapes to be either filled or stroked. Using a lower-level set of
|
||||
* functions more complex and arbitrary paths can be constructed by
|
||||
* concatenating straight line, bezier curve and arc segments.
|
||||
*
|
||||
* When constructing arbitrary paths, the current pen location is
|
||||
* initialized using the move_to command. The subsequent path segments
|
||||
* implicitly use the last pen location as their first vertex and move
|
||||
* the pen location to the last vertex they produce at the end. Also
|
||||
* there are special versions of functions that allow specifying the
|
||||
* vertices of the path segments relative to the last pen location
|
||||
* rather then in the absolute coordinates.
|
||||
*/
|
||||
|
||||
#include <cogl/cogl-defines.h>
|
||||
|
||||
#include <cogl-path/cogl-path-enum-types.h>
|
||||
#include <cogl-path/cogl-path-types.h>
|
||||
#include <cogl-path/cogl-path-functions.h>
|
||||
|
||||
#endif /* __COGL_PATH_H__ */
|
||||
|
@ -1,59 +0,0 @@
|
||||
/* cogl1-path-functions.h */
|
||||
cogl_clip_push_from_path
|
||||
cogl_clip_push_from_path_preserve
|
||||
cogl_get_path
|
||||
cogl_is_path
|
||||
cogl_path_arc
|
||||
cogl_path_close
|
||||
cogl_path_copy
|
||||
cogl_path_curve_to
|
||||
cogl_path_ellipse
|
||||
cogl_path_fill
|
||||
cogl_path_fill_preserve
|
||||
cogl_path_get_fill_rule
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
cogl_path_get_gtype
|
||||
#endif
|
||||
cogl_path_line
|
||||
cogl_path_line_to
|
||||
cogl_path_move_to
|
||||
cogl_path_new
|
||||
cogl_path_polygon
|
||||
cogl_path_polyline
|
||||
cogl_path_rectangle
|
||||
cogl_path_rel_curve_to
|
||||
cogl_path_rel_line_to
|
||||
cogl_path_rel_move_to
|
||||
cogl_path_round_rectangle
|
||||
cogl_path_set_fill_rule
|
||||
cogl_path_stroke
|
||||
cogl_path_stroke_preserve
|
||||
cogl_set_path
|
||||
|
||||
/* cogl2-path-functions.h */
|
||||
cogl_framebuffer_fill_path
|
||||
cogl_framebuffer_push_path_clip
|
||||
cogl_framebuffer_stroke_path
|
||||
cogl2_clip_push_from_path
|
||||
cogl2_path_arc
|
||||
cogl2_path_close
|
||||
cogl2_path_curve_to
|
||||
cogl2_path_ellipse
|
||||
cogl2_path_fill
|
||||
cogl2_path_get_fill_rule
|
||||
cogl2_path_line
|
||||
cogl2_path_line_to
|
||||
cogl2_path_move_to
|
||||
cogl2_path_new
|
||||
cogl2_path_polygon
|
||||
cogl2_path_polyline
|
||||
cogl2_path_rectangle
|
||||
cogl2_path_rel_curve_to
|
||||
cogl2_path_rel_line_to
|
||||
cogl2_path_rel_move_to
|
||||
cogl2_path_round_rectangle
|
||||
cogl2_path_set_fill_rule
|
||||
cogl2_path_stroke
|
||||
|
||||
/* cogl-path-enums.h-contents may change as header is generated */
|
||||
cogl_path_fill_rule_get_type
|
@ -1,87 +0,0 @@
|
||||
cogl_path_includesubdir = join_paths(cogl_includesubdir, 'cogl-path')
|
||||
cogl_path_includedir = join_paths(cogl_includedir, 'cogl-path')
|
||||
|
||||
cogl_path_public_headers = [
|
||||
'cogl-path.h',
|
||||
'cogl-path-functions.h',
|
||||
'cogl-path-types.h',
|
||||
]
|
||||
|
||||
cogl_path_sources = [
|
||||
'cogl-path.c',
|
||||
'cogl-path-private.h',
|
||||
'tesselator/dict-list.h',
|
||||
'tesselator/dict.c',
|
||||
'tesselator/dict.h',
|
||||
'tesselator/geom.c',
|
||||
'tesselator/geom.h',
|
||||
'tesselator/gluos.h',
|
||||
'tesselator/memalloc.h',
|
||||
'tesselator/mesh.c',
|
||||
'tesselator/mesh.h',
|
||||
'tesselator/normal.c',
|
||||
'tesselator/normal.h',
|
||||
'tesselator/priorityq-heap.h',
|
||||
'tesselator/priorityq-sort.h',
|
||||
'tesselator/priorityq.c',
|
||||
'tesselator/priorityq.h',
|
||||
'tesselator/render.c',
|
||||
'tesselator/render.h',
|
||||
'tesselator/sweep.c',
|
||||
'tesselator/sweep.h',
|
||||
'tesselator/tess.c',
|
||||
'tesselator/tess.h',
|
||||
'tesselator/tesselator.h',
|
||||
'tesselator/tessmono.c',
|
||||
'tesselator/tessmono.h',
|
||||
]
|
||||
|
||||
cogl_path_includepath = include_directories('.')
|
||||
|
||||
libmutter_cogl_path_enum_types = gnome.mkenums('cogl-path-enum-types',
|
||||
sources: 'cogl-path-types.h',
|
||||
c_template: 'cogl-path-enum-types.c.in',
|
||||
h_template: 'cogl-path-enum-types.h.in',
|
||||
install_dir: cogl_path_includedir,
|
||||
install_header: true,
|
||||
)
|
||||
libmutter_cogl_path_enum_types_h = libmutter_cogl_path_enum_types[1]
|
||||
|
||||
cogl_path_sources += libmutter_cogl_path_enum_types
|
||||
|
||||
cogl_path_c_args = [
|
||||
cogl_c_args,
|
||||
]
|
||||
|
||||
libmutter_cogl_path = shared_library('mutter-cogl-path-' + libmutter_api_version,
|
||||
sources: [cogl_path_sources, cogl_path_public_headers],
|
||||
version: '0.0.0',
|
||||
soversion: 0,
|
||||
c_args: cogl_path_c_args,
|
||||
include_directories: [cogl_includepath, cogl_path_includepath],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
dependencies: libmutter_cogl_dep,
|
||||
install_rpath: pkglibdir,
|
||||
install_dir: pkglibdir,
|
||||
install: true,
|
||||
)
|
||||
libmutter_cogl_path_dep = declare_dependency(
|
||||
sources: [libmutter_cogl_path_enum_types_h],
|
||||
link_with: libmutter_cogl_path
|
||||
)
|
||||
|
||||
install_headers(cogl_path_public_headers,
|
||||
subdir: cogl_path_includesubdir)
|
||||
|
||||
pkg.generate(libmutter_cogl_path,
|
||||
name: 'CoglPath',
|
||||
filebase: 'mutter-cogl-path-' + libmutter_api_version,
|
||||
description: 'A 2D path drawing library for Cogl in mutter',
|
||||
subdirs: join_paths(pkgname, 'cogl'),
|
||||
requires: [cogl_pkg_deps, libmutter_cogl_name],
|
||||
version: meson.project_version(),
|
||||
variables: [
|
||||
'apiversion=' + libmutter_api_version,
|
||||
],
|
||||
install_dir: pcdir,
|
||||
)
|
@ -1,13 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
apiversion=@LIBMUTTER_API_VERSION@
|
||||
libdir=@libdir@/mutter-${apiversion}
|
||||
includedir=@includedir@/mutter-${apiversion}
|
||||
requires=@COGL_PKG_REQUIRES@ mutter-cogl-${apiversion}
|
||||
|
||||
Name: Cogl
|
||||
Description: A 2D path drawing library for Cogl
|
||||
Version: @MUTTER_VERSION@
|
||||
Libs: -L${libdir} -lmutter-cogl-path-${apiversion}
|
||||
Cflags: -I${includedir}/cogl
|
||||
Requires: ${requires}
|
@ -1,446 +0,0 @@
|
||||
/*
|
||||
*/
|
||||
|
||||
General Polygon Tesselation
|
||||
---------------------------
|
||||
|
||||
This note describes a tesselator for polygons consisting of one or
|
||||
more closed contours. It is backward-compatible with the current
|
||||
OpenGL Utilities tesselator, and is intended to replace it. Here is
|
||||
a summary of the major differences:
|
||||
|
||||
- input contours can be intersecting, self-intersecting, or degenerate.
|
||||
|
||||
- supports a choice of several winding rules for determining which parts
|
||||
of the polygon are on the "interior". This makes it possible to do
|
||||
CSG operations on polygons.
|
||||
|
||||
- boundary extraction: instead of tesselating the polygon, returns a
|
||||
set of closed contours which separate the interior from the exterior.
|
||||
|
||||
- returns the output as a small number of triangle fans and strips,
|
||||
rather than a list of independent triangles (when possible).
|
||||
|
||||
- output is available as an explicit mesh (a quad-edge structure),
|
||||
in addition to the normal callback interface.
|
||||
|
||||
- the algorithm used is extremely robust.
|
||||
|
||||
|
||||
The interface
|
||||
-------------
|
||||
|
||||
The tesselator state is maintained in a "tesselator object".
|
||||
These are allocated and destroyed using
|
||||
|
||||
GLUtesselator *gluNewTess( void );
|
||||
void gluDeleteTess( GLUtesselator *tess );
|
||||
|
||||
Several tesselator objects may be used simultaneously.
|
||||
|
||||
Inputs
|
||||
------
|
||||
|
||||
The input contours are specified with the following routines:
|
||||
|
||||
void gluTessBeginPolygon( GLUtesselator *tess );
|
||||
void gluTessBeginContour( GLUtesselator *tess );
|
||||
void gluTessVertex( GLUtesselator *tess, GLUcoord coords[3], void *data );
|
||||
void gluTessEndContour( GLUtesselator *tess );
|
||||
void gluTessEndPolygon( GLUtesselator *tess );
|
||||
|
||||
Within each BeginPolygon/EndPolygon pair, there can be zero or more
|
||||
calls to BeginContour/EndContour. Within each contour, there are zero
|
||||
or more calls to gluTessVertex(). The vertices specify a closed
|
||||
contour (the last vertex of each contour is automatically linked to
|
||||
the first).
|
||||
|
||||
"coords" give the coordinates of the vertex in 3-space. For useful
|
||||
results, all vertices should lie in some plane, since the vertices
|
||||
are projected onto a plane before tesselation. "data" is a pointer
|
||||
to a user-defined vertex structure, which typically contains other
|
||||
information such as color, texture coordinates, normal, etc. It is
|
||||
used to refer to the vertex during rendering.
|
||||
|
||||
The library can be compiled in single- or double-precision; the type
|
||||
GLUcoord represents either "float" or "double" accordingly. The GLU
|
||||
version will be available in double-precision only. Compile with
|
||||
GLU_TESS_API_FLOAT defined to get the single-precision version.
|
||||
|
||||
When EndPolygon is called, the tesselation algorithm determines
|
||||
which regions are interior to the given contours, according to one
|
||||
of several "winding rules" described below. The interior regions
|
||||
are then tesselated, and the output is provided as callbacks.
|
||||
|
||||
|
||||
Rendering Callbacks
|
||||
-------------------
|
||||
|
||||
Callbacks are specified by the client using
|
||||
|
||||
void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)());
|
||||
|
||||
If "fn" is NULL, any previously defined callback is discarded.
|
||||
|
||||
The callbacks used to provide output are: /* which == */
|
||||
|
||||
void begin( GLenum type ); /* GLU_TESS_BEGIN */
|
||||
void edgeFlag( GLboolean flag ); /* GLU_TESS_EDGE_FLAG */
|
||||
void vertex( void *data ); /* GLU_TESS_VERTEX */
|
||||
void end( void ); /* GLU_TESS_END */
|
||||
|
||||
Any of the callbacks may be left undefined; if so, the corresponding
|
||||
information will not be supplied during rendering.
|
||||
|
||||
The "begin" callback indicates the start of a primitive; type is one
|
||||
of GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES (but see the
|
||||
notes on "boundary extraction" below).
|
||||
|
||||
It is followed by any number of "vertex" callbacks, which supply the
|
||||
vertices in the same order as expected by the corresponding glBegin()
|
||||
call. After the last vertex of a given primitive, there is a callback
|
||||
to "end".
|
||||
|
||||
If the "edgeFlag" callback is provided, no triangle fans or strips
|
||||
will be used. When edgeFlag is called, if "flag" is GL_TRUE then each
|
||||
vertex which follows begins an edge which lies on the polygon boundary
|
||||
(ie. an edge which separates an interior region from an exterior one).
|
||||
If "flag" is GL_FALSE, each vertex which follows begins an edge which lies
|
||||
in the polygon interior. "edgeFlag" will be called before the first
|
||||
call to "vertex".
|
||||
|
||||
Other Callbacks
|
||||
---------------
|
||||
|
||||
void mesh( GLUmesh *mesh ); /* GLU_TESS_MESH */
|
||||
|
||||
- Returns an explicit mesh, represented using the quad-edge structure
|
||||
(Guibas/Stolfi '85). Other implementations of this interface might
|
||||
use a different mesh structure, so this is available only only as an
|
||||
SGI extension. When the mesh is no longer needed, it should be freed
|
||||
using
|
||||
|
||||
void gluDeleteMesh( GLUmesh *mesh );
|
||||
|
||||
There is a brief description of this data structure in the include
|
||||
file "mesh.h". For the full details, see L. Guibas and J. Stolfi,
|
||||
Primitives for the manipulation of general subdivisions and the
|
||||
computation of Voronoi diagrams, ACM Transactions on Graphics,
|
||||
4(2):74-123, April 1985. For an introduction, see the course notes
|
||||
for CS348a, "Mathematical Foundations of Computer Graphics",
|
||||
available at the Stanford bookstore (and taught during the fall
|
||||
quarter).
|
||||
|
||||
void error( GLenum errno ); /* GLU_TESS_ERROR */
|
||||
|
||||
- errno is one of GLU_TESS_MISSING_BEGIN_POLYGON,
|
||||
GLU_TESS_MISSING_END_POLYGON,
|
||||
GLU_TESS_MISSING_BEGIN_CONTOUR,
|
||||
GLU_TESS_MISSING_END_CONTOUR,
|
||||
GLU_TESS_COORD_TOO_LARGE,
|
||||
GLU_TESS_NEED_COMBINE_CALLBACK
|
||||
|
||||
The first four are obvious. The interface recovers from these
|
||||
errors by inserting the missing call(s).
|
||||
|
||||
GLU_TESS_COORD_TOO_LARGE says that some vertex coordinate exceeded
|
||||
the predefined constant GLU_TESS_MAX_COORD in absolute value, and
|
||||
that the value has been clamped. (Coordinate values must be small
|
||||
enough so that two can be multiplied together without overflow.)
|
||||
|
||||
GLU_TESS_NEED_COMBINE_CALLBACK says that the algorithm detected an
|
||||
intersection between two edges in the input data, and the "combine"
|
||||
callback (below) was not provided. No output will be generated.
|
||||
|
||||
|
||||
void combine( GLUcoord coords[3], void *data[4], /* GLU_TESS_COMBINE */
|
||||
GLUcoord weight[4], void **outData );
|
||||
|
||||
- When the algorithm detects an intersection, or wishes to merge
|
||||
features, it needs to create a new vertex. The vertex is defined
|
||||
as a linear combination of up to 4 existing vertices, referenced
|
||||
by data[0..3]. The coefficients of the linear combination are
|
||||
given by weight[0..3]; these weights always sum to 1.0. All vertex
|
||||
pointers are valid even when some of the weights are zero.
|
||||
"coords" gives the location of the new vertex.
|
||||
|
||||
The user must allocate another vertex, interpolate parameters
|
||||
using "data" and "weights", and return the new vertex pointer in
|
||||
"outData". This handle is supplied during rendering callbacks.
|
||||
For example, if the polygon lies in an arbitrary plane in 3-space,
|
||||
and we associate a color with each vertex, the combine callback might
|
||||
look like this:
|
||||
|
||||
void myCombine( GLUcoord coords[3], VERTEX *d[4],
|
||||
GLUcoord w[4], VERTEX **dataOut )
|
||||
{
|
||||
VERTEX *new = new_vertex();
|
||||
|
||||
new->x = coords[0];
|
||||
new->y = coords[1];
|
||||
new->z = coords[2];
|
||||
new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r + w[3]*d[3]->r;
|
||||
new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g + w[3]*d[3]->g;
|
||||
new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b + w[3]*d[3]->b;
|
||||
new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a + w[3]*d[3]->a;
|
||||
*dataOut = new;
|
||||
}
|
||||
|
||||
If the algorithm detects an intersection, then the "combine" callback
|
||||
must be defined, and must write a non-NULL pointer into "dataOut".
|
||||
Otherwise the GLU_TESS_NEED_COMBINE_CALLBACK error occurs, and no
|
||||
output is generated. This is the only error that can occur during
|
||||
tesselation and rendering.
|
||||
|
||||
|
||||
Control over Tesselation
|
||||
------------------------
|
||||
|
||||
void gluTessProperty( GLUtesselator *tess, GLenum which, GLUcoord value );
|
||||
|
||||
Properties defined:
|
||||
|
||||
- GLU_TESS_WINDING_RULE. Possible values:
|
||||
|
||||
GLU_TESS_WINDING_ODD
|
||||
GLU_TESS_WINDING_NONZERO
|
||||
GLU_TESS_WINDING_POSITIVE
|
||||
GLU_TESS_WINDING_NEGATIVE
|
||||
GLU_TESS_WINDING_ABS_GEQ_TWO
|
||||
|
||||
The input contours parition the plane into regions. A winding
|
||||
rule determines which of these regions are inside the polygon.
|
||||
|
||||
For a single contour C, the winding number of a point x is simply
|
||||
the signed number of revolutions we make around x as we travel
|
||||
once around C (where CCW is positive). When there are several
|
||||
contours, the individual winding numbers are summed. This
|
||||
procedure associates a signed integer value with each point x in
|
||||
the plane. Note that the winding number is the same for all
|
||||
points in a single region.
|
||||
|
||||
The winding rule classifies a region as "inside" if its winding
|
||||
number belongs to the chosen category (odd, nonzero, positive,
|
||||
negative, or absolute value of at least two). The current GLU
|
||||
tesselator implements the "odd" rule. The "nonzero" rule is another
|
||||
common way to define the interior. The other three rules are
|
||||
useful for polygon CSG operations (see below).
|
||||
|
||||
- GLU_TESS_BOUNDARY_ONLY. Values: TRUE (non-zero) or FALSE (zero).
|
||||
|
||||
If TRUE, returns a set of closed contours which separate the
|
||||
polygon interior and exterior (rather than a tesselation).
|
||||
Exterior contours are oriented CCW with respect to the normal,
|
||||
interior contours are oriented CW. The GLU_TESS_BEGIN callback
|
||||
uses the type GL_LINE_LOOP for each contour.
|
||||
|
||||
- GLU_TESS_TOLERANCE. Value: a real number between 0.0 and 1.0.
|
||||
|
||||
This specifies a tolerance for merging features to reduce the size
|
||||
of the output. For example, two vertices which are very close to
|
||||
each other might be replaced by a single vertex. The tolerance
|
||||
is multiplied by the largest coordinate magnitude of any input vertex;
|
||||
this specifies the maximum distance that any feature can move as the
|
||||
result of a single merge operation. If a single feature takes part
|
||||
in several merge operations, the total distance moved could be larger.
|
||||
|
||||
Feature merging is completely optional; the tolerance is only a hint.
|
||||
The implementation is free to merge in some cases and not in others,
|
||||
or to never merge features at all. The default tolerance is zero.
|
||||
|
||||
The current implementation merges vertices only if they are exactly
|
||||
coincident, regardless of the current tolerance. A vertex is
|
||||
spliced into an edge only if the implementation is unable to
|
||||
distinguish which side of the edge the vertex lies on.
|
||||
Two edges are merged only when both endpoints are identical.
|
||||
|
||||
|
||||
void gluTessNormal( GLUtesselator *tess,
|
||||
GLUcoord x, GLUcoord y, GLUcoord z )
|
||||
|
||||
- Lets the user supply the polygon normal, if known. All input data
|
||||
is projected into a plane perpendicular to the normal before
|
||||
tesselation. All output triangles are oriented CCW with
|
||||
respect to the normal (CW orientation can be obtained by
|
||||
reversing the sign of the supplied normal). For example, if
|
||||
you know that all polygons lie in the x-y plane, call
|
||||
"gluTessNormal(tess, 0.0, 0.0, 1.0)" before rendering any polygons.
|
||||
|
||||
- If the supplied normal is (0,0,0) (the default value), the
|
||||
normal is determined as follows. The direction of the normal,
|
||||
up to its sign, is found by fitting a plane to the vertices,
|
||||
without regard to how the vertices are connected. It is
|
||||
expected that the input data lies approximately in plane;
|
||||
otherwise projection perpendicular to the computed normal may
|
||||
substantially change the geometry. The sign of the normal is
|
||||
chosen so that the sum of the signed areas of all input contours
|
||||
is non-negative (where a CCW contour has positive area).
|
||||
|
||||
- The supplied normal persists until it is changed by another
|
||||
call to gluTessNormal.
|
||||
|
||||
|
||||
Backward compatibility with the GLU tesselator
|
||||
----------------------------------------------
|
||||
|
||||
The preferred interface is the one described above. The following
|
||||
routines are obsolete, and are provided only for backward compatibility:
|
||||
|
||||
typedef GLUtesselator GLUtriangulatorObj; /* obsolete name */
|
||||
|
||||
void gluBeginPolygon( GLUtesselator *tess );
|
||||
void gluNextContour( GLUtesselator *tess, GLenum type );
|
||||
void gluEndPolygon( GLUtesselator *tess );
|
||||
|
||||
"type" is one of GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or
|
||||
GLU_UNKNOWN. It is ignored by the current GLU tesselator.
|
||||
|
||||
GLU_BEGIN, GLU_VERTEX, GLU_END, GLU_ERROR, and GLU_EDGE_FLAG are defined
|
||||
as synonyms for GLU_TESS_BEGIN, GLU_TESS_VERTEX, GLU_TESS_END,
|
||||
GLU_TESS_ERROR, and GLU_TESS_EDGE_FLAG.
|
||||
|
||||
|
||||
Polygon CSG operations
|
||||
----------------------
|
||||
|
||||
The features of the tesselator make it easy to find the union, difference,
|
||||
or intersection of several polygons.
|
||||
|
||||
First, assume that each polygon is defined so that the winding number
|
||||
is 0 for each exterior region, and 1 for each interior region. Under
|
||||
this model, CCW contours define the outer boundary of the polygon, and
|
||||
CW contours define holes. Contours may be nested, but a nested
|
||||
contour must be oriented oppositely from the contour that contains it.
|
||||
|
||||
If the original polygons do not satisfy this description, they can be
|
||||
converted to this form by first running the tesselator with the
|
||||
GLU_TESS_BOUNDARY_ONLY property turned on. This returns a list of
|
||||
contours satisfying the restriction above. By allocating two
|
||||
tesselator objects, the callbacks from one tesselator can be fed
|
||||
directly to the input of another.
|
||||
|
||||
Given two or more polygons of the form above, CSG operations can be
|
||||
implemented as follows:
|
||||
|
||||
Union
|
||||
Draw all the input contours as a single polygon. The winding number
|
||||
of each resulting region is the number of original polygons
|
||||
which cover it. The union can be extracted using the
|
||||
GLU_TESS_WINDING_NONZERO or GLU_TESS_WINDING_POSITIVE winding rules.
|
||||
Note that with the nonzero rule, we would get the same result if
|
||||
all contour orientations were reversed.
|
||||
|
||||
Intersection (two polygons at a time only)
|
||||
Draw a single polygon using the contours from both input polygons.
|
||||
Extract the result using GLU_TESS_WINDING_ABS_GEQ_TWO. (Since this
|
||||
winding rule looks at the absolute value, reversing all contour
|
||||
orientations does not change the result.)
|
||||
|
||||
Difference
|
||||
|
||||
Suppose we want to compute A \ (B union C union D). Draw a single
|
||||
polygon consisting of the unmodified contours from A, followed by
|
||||
the contours of B,C,D with the vertex order reversed (this changes
|
||||
the winding number of the interior regions to -1). To extract the
|
||||
result, use the GLU_TESS_WINDING_POSITIVE rule.
|
||||
|
||||
If B,C,D are the result of a GLU_TESS_BOUNDARY_ONLY call, an
|
||||
alternative to reversing the vertex order is to reverse the sign of
|
||||
the supplied normal. For example in the x-y plane, call
|
||||
gluTessNormal( tess, 0.0, 0.0, -1.0 ).
|
||||
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
||||
The tesselator is not intended for immediate-mode rendering; when
|
||||
possible the output should be cached in a user structure or display
|
||||
list. General polygon tesselation is an inherently difficult problem,
|
||||
especially given the goal of extreme robustness.
|
||||
|
||||
The implementation makes an effort to output a small number of fans
|
||||
and strips; this should improve the rendering performance when the
|
||||
output is used in a display list.
|
||||
|
||||
Single-contour input polygons are first tested to see whether they can
|
||||
be rendered as a triangle fan with respect to the first vertex (to
|
||||
avoid running the full decomposition algorithm on convex polygons).
|
||||
Non-convex polygons may be rendered by this "fast path" as well, if
|
||||
the algorithm gets lucky in its choice of a starting vertex.
|
||||
|
||||
For best performance follow these guidelines:
|
||||
|
||||
- supply the polygon normal, if available, using gluTessNormal().
|
||||
This represents about 10% of the computation time. For example,
|
||||
if all polygons lie in the x-y plane, use gluTessNormal(tess,0,0,1).
|
||||
|
||||
- render many polygons using the same tesselator object, rather than
|
||||
allocating a new tesselator for each one. (In a multi-threaded,
|
||||
multi-processor environment you may get better performance using
|
||||
several tesselators.)
|
||||
|
||||
|
||||
Comparison with the GLU tesselator
|
||||
----------------------------------
|
||||
|
||||
On polygons which make it through the "fast path", the tesselator is
|
||||
3 to 5 times faster than the GLU tesselator.
|
||||
|
||||
On polygons which don't make it through the fast path (but which don't
|
||||
have self-intersections or degeneracies), it is about 2 times slower.
|
||||
|
||||
On polygons with self-intersections or degeneraces, there is nothing
|
||||
to compare against.
|
||||
|
||||
The new tesselator generates many more fans and strips, reducing the
|
||||
number of vertices that need to be sent to the hardware.
|
||||
|
||||
Key to the statistics:
|
||||
|
||||
vert number of input vertices on all contours
|
||||
cntr number of input contours
|
||||
tri number of triangles in all output primitives
|
||||
strip number of triangle strips
|
||||
fan number of triangle fans
|
||||
ind number of independent triangles
|
||||
ms number of milliseconds for tesselation
|
||||
(on a 150MHz R4400 Indy)
|
||||
|
||||
Convex polygon examples:
|
||||
|
||||
New: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.0459 ms
|
||||
Old: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.149 ms
|
||||
New: 4 vert, 1 cntr, 2 tri, 0 strip, 1 fan, 0 ind, 0.0459 ms
|
||||
Old: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.161 ms
|
||||
New: 36 vert, 1 cntr, 34 tri, 0 strip, 1 fan, 0 ind, 0.153 ms
|
||||
Old: 36 vert, 1 cntr, 34 tri, 0 strip, 0 fan, 34 ind, 0.621 ms
|
||||
|
||||
Concave single-contour polygons:
|
||||
|
||||
New: 5 vert, 1 cntr, 3 tri, 0 strip, 1 fan, 0 ind, 0.052 ms
|
||||
Old: 5 vert, 1 cntr, 3 tri, 0 strip, 0 fan, 3 ind, 0.252 ms
|
||||
New: 19 vert, 1 cntr, 17 tri, 2 strip, 2 fan, 1 ind, 0.911 ms
|
||||
Old: 19 vert, 1 cntr, 17 tri, 0 strip, 0 fan, 17 ind, 0.529 ms
|
||||
New: 151 vert, 1 cntr, 149 tri, 13 strip, 18 fan, 3 ind, 6.82 ms
|
||||
Old: 151 vert, 1 cntr, 149 tri, 0 strip, 3 fan, 143 ind, 2.7 ms
|
||||
New: 574 vert, 1 cntr, 572 tri, 59 strip, 54 fan, 11 ind, 26.6 ms
|
||||
Old: 574 vert, 1 cntr, 572 tri, 0 strip, 31 fan, 499 ind, 12.4 ms
|
||||
|
||||
Multiple contours, but no intersections:
|
||||
|
||||
New: 7 vert, 2 cntr, 7 tri, 1 strip, 0 fan, 0 ind, 0.527 ms
|
||||
Old: 7 vert, 2 cntr, 7 tri, 0 strip, 0 fan, 7 ind, 0.274 ms
|
||||
New: 81 vert, 6 cntr, 89 tri, 9 strip, 7 fan, 6 ind, 3.88 ms
|
||||
Old: 81 vert, 6 cntr, 89 tri, 0 strip, 13 fan, 61 ind, 2.2 ms
|
||||
New: 391 vert, 19 cntr, 413 tri, 37 strip, 32 fan, 26 ind, 20.2 ms
|
||||
Old: 391 vert, 19 cntr, 413 tri, 0 strip, 25 fan, 363 ind, 8.68 ms
|
||||
|
||||
Self-intersecting and degenerate examples:
|
||||
|
||||
Bowtie: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.483 ms
|
||||
Star: 5 vert, 1 cntr, 5 tri, 0 strip, 0 fan, 5 ind, 0.91 ms
|
||||
Random: 24 vert, 7 cntr, 46 tri, 2 strip, 12 fan, 7 ind, 5.32 ms
|
||||
Font: 333 vert, 2 cntr, 331 tri, 32 strip, 16 fan, 3 ind, 14.1 ms
|
||||
: 167 vert, 35 cntr, 254 tri, 8 strip, 56 fan, 52 ind, 46.3 ms
|
||||
: 78 vert, 1 cntr, 2675 tri, 148 strip, 207 fan, 180 ind, 243 ms
|
||||
: 12480 vert, 2 cntr, 12478 tri, 736 strip,1275 fan, 5 ind, 1010 ms
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __dict_list_h_
|
||||
#define __dict_list_h_
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define DictKey DictListKey
|
||||
#define Dict DictList
|
||||
#define DictNode DictListNode
|
||||
|
||||
#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
|
||||
#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
|
||||
|
||||
#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
|
||||
#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
|
||||
#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
|
||||
#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
|
||||
|
||||
#define dictKey(n) __gl_dictListKey(n)
|
||||
#define dictSucc(n) __gl_dictListSucc(n)
|
||||
#define dictPred(n) __gl_dictListPred(n)
|
||||
#define dictMin(d) __gl_dictListMin(d)
|
||||
#define dictMax(d) __gl_dictListMax(d)
|
||||
|
||||
|
||||
|
||||
typedef void *DictKey;
|
||||
typedef struct Dict Dict;
|
||||
typedef struct DictNode DictNode;
|
||||
|
||||
Dict *dictNewDict(
|
||||
void *frame,
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2) );
|
||||
|
||||
void dictDeleteDict( Dict *dict );
|
||||
|
||||
/* Search returns the node with the smallest key greater than or equal
|
||||
* to the given key. If there is no such key, returns a node whose
|
||||
* key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
|
||||
*/
|
||||
DictNode *dictSearch( Dict *dict, DictKey key );
|
||||
DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
|
||||
void dictDelete( Dict *dict, DictNode *node );
|
||||
|
||||
#define __gl_dictListKey(n) ((n)->key)
|
||||
#define __gl_dictListSucc(n) ((n)->next)
|
||||
#define __gl_dictListPred(n) ((n)->prev)
|
||||
#define __gl_dictListMin(d) ((d)->head.next)
|
||||
#define __gl_dictListMax(d) ((d)->head.prev)
|
||||
#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
|
||||
|
||||
|
||||
/*** Private data structures ***/
|
||||
|
||||
struct DictNode {
|
||||
DictKey key;
|
||||
DictNode *next;
|
||||
DictNode *prev;
|
||||
};
|
||||
|
||||
struct Dict {
|
||||
DictNode head;
|
||||
void *frame;
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "dict-list.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
/* really __gl_dictListNewDict */
|
||||
Dict *dictNewDict( void *frame,
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2) )
|
||||
{
|
||||
Dict *dict = (Dict *) memAlloc( sizeof( Dict ));
|
||||
DictNode *head;
|
||||
|
||||
if (dict == NULL) return NULL;
|
||||
|
||||
head = &dict->head;
|
||||
|
||||
head->key = NULL;
|
||||
head->next = head;
|
||||
head->prev = head;
|
||||
|
||||
dict->frame = frame;
|
||||
dict->leq = leq;
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/* really __gl_dictListDeleteDict */
|
||||
void dictDeleteDict( Dict *dict )
|
||||
{
|
||||
DictNode *node, *next;
|
||||
|
||||
for( node = dict->head.next; node != &dict->head; node = next ) {
|
||||
next = node->next;
|
||||
memFree( node );
|
||||
}
|
||||
memFree( dict );
|
||||
}
|
||||
|
||||
/* really __gl_dictListInsertBefore */
|
||||
DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key )
|
||||
{
|
||||
DictNode *newNode;
|
||||
|
||||
do {
|
||||
node = node->prev;
|
||||
} while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key));
|
||||
|
||||
newNode = (DictNode *) memAlloc( sizeof( DictNode ));
|
||||
if (newNode == NULL) return NULL;
|
||||
|
||||
newNode->key = key;
|
||||
newNode->next = node->next;
|
||||
node->next->prev = newNode;
|
||||
newNode->prev = node;
|
||||
node->next = newNode;
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/* really __gl_dictListDelete */
|
||||
void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/
|
||||
{
|
||||
node->next->prev = node->prev;
|
||||
node->prev->next = node->next;
|
||||
memFree( node );
|
||||
}
|
||||
|
||||
/* really __gl_dictListSearch */
|
||||
DictNode *dictSearch( Dict *dict, DictKey key )
|
||||
{
|
||||
DictNode *node = &dict->head;
|
||||
|
||||
do {
|
||||
node = node->next;
|
||||
} while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key));
|
||||
|
||||
return node;
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __dict_list_h_
|
||||
#define __dict_list_h_
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define DictKey DictListKey
|
||||
#define Dict DictList
|
||||
#define DictNode DictListNode
|
||||
|
||||
#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
|
||||
#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
|
||||
|
||||
#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
|
||||
#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
|
||||
#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
|
||||
#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
|
||||
|
||||
#define dictKey(n) __gl_dictListKey(n)
|
||||
#define dictSucc(n) __gl_dictListSucc(n)
|
||||
#define dictPred(n) __gl_dictListPred(n)
|
||||
#define dictMin(d) __gl_dictListMin(d)
|
||||
#define dictMax(d) __gl_dictListMax(d)
|
||||
|
||||
|
||||
|
||||
typedef void *DictKey;
|
||||
typedef struct Dict Dict;
|
||||
typedef struct DictNode DictNode;
|
||||
|
||||
Dict *dictNewDict(
|
||||
void *frame,
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2) );
|
||||
|
||||
void dictDeleteDict( Dict *dict );
|
||||
|
||||
/* Search returns the node with the smallest key greater than or equal
|
||||
* to the given key. If there is no such key, returns a node whose
|
||||
* key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
|
||||
*/
|
||||
DictNode *dictSearch( Dict *dict, DictKey key );
|
||||
DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
|
||||
void dictDelete( Dict *dict, DictNode *node );
|
||||
|
||||
#define __gl_dictListKey(n) ((n)->key)
|
||||
#define __gl_dictListSucc(n) ((n)->next)
|
||||
#define __gl_dictListPred(n) ((n)->prev)
|
||||
#define __gl_dictListMin(d) ((d)->head.next)
|
||||
#define __gl_dictListMax(d) ((d)->head.prev)
|
||||
#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
|
||||
|
||||
|
||||
/*** Private data structures ***/
|
||||
|
||||
struct DictNode {
|
||||
DictKey key;
|
||||
DictNode *next;
|
||||
DictNode *prev;
|
||||
};
|
||||
|
||||
struct Dict {
|
||||
DictNode head;
|
||||
void *frame;
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,264 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <assert.h>
|
||||
#include "mesh.h"
|
||||
#include "geom.h"
|
||||
|
||||
int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
|
||||
{
|
||||
/* Returns TRUE if u is lexicographically <= v. */
|
||||
|
||||
return VertLeq( u, v );
|
||||
}
|
||||
|
||||
GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
|
||||
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
|
||||
* Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
|
||||
* If uw is vertical (and thus passes thru v), the result is zero.
|
||||
*
|
||||
* The calculation is extremely accurate and stable, even when v
|
||||
* is very close to u or w. In particular if we set v->t = 0 and
|
||||
* let r be the negated result (this evaluates (uw)(v->s)), then
|
||||
* r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
|
||||
*/
|
||||
GLdouble gapL, gapR;
|
||||
|
||||
assert( VertLeq( u, v ) && VertLeq( v, w ));
|
||||
|
||||
gapL = v->s - u->s;
|
||||
gapR = w->s - v->s;
|
||||
|
||||
if( gapL + gapR > 0 ) {
|
||||
if( gapL < gapR ) {
|
||||
return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
|
||||
} else {
|
||||
return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
|
||||
}
|
||||
}
|
||||
/* vertical line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* Returns a number whose sign matches EdgeEval(u,v,w) but which
|
||||
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
|
||||
* as v is above, on, or below the edge uw.
|
||||
*/
|
||||
GLdouble gapL, gapR;
|
||||
|
||||
assert( VertLeq( u, v ) && VertLeq( v, w ));
|
||||
|
||||
gapL = v->s - u->s;
|
||||
gapR = w->s - v->s;
|
||||
|
||||
if( gapL + gapR > 0 ) {
|
||||
return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
|
||||
}
|
||||
/* vertical line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Define versions of EdgeSign, EdgeEval with s and t transposed.
|
||||
*/
|
||||
|
||||
GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
|
||||
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
|
||||
* Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
|
||||
* If uw is vertical (and thus passes thru v), the result is zero.
|
||||
*
|
||||
* The calculation is extremely accurate and stable, even when v
|
||||
* is very close to u or w. In particular if we set v->s = 0 and
|
||||
* let r be the negated result (this evaluates (uw)(v->t)), then
|
||||
* r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
|
||||
*/
|
||||
GLdouble gapL, gapR;
|
||||
|
||||
assert( TransLeq( u, v ) && TransLeq( v, w ));
|
||||
|
||||
gapL = v->t - u->t;
|
||||
gapR = w->t - v->t;
|
||||
|
||||
if( gapL + gapR > 0 ) {
|
||||
if( gapL < gapR ) {
|
||||
return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
|
||||
} else {
|
||||
return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
|
||||
}
|
||||
}
|
||||
/* vertical line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* Returns a number whose sign matches TransEval(u,v,w) but which
|
||||
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
|
||||
* as v is above, on, or below the edge uw.
|
||||
*/
|
||||
GLdouble gapL, gapR;
|
||||
|
||||
assert( TransLeq( u, v ) && TransLeq( v, w ));
|
||||
|
||||
gapL = v->t - u->t;
|
||||
gapR = w->t - v->t;
|
||||
|
||||
if( gapL + gapR > 0 ) {
|
||||
return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
|
||||
}
|
||||
/* vertical line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* For almost-degenerate situations, the results are not reliable.
|
||||
* Unless the floating-point arithmetic can be performed without
|
||||
* rounding errors, *any* implementation will give incorrect results
|
||||
* on some degenerate inputs, so the client must have some way to
|
||||
* handle this situation.
|
||||
*/
|
||||
return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
|
||||
}
|
||||
|
||||
/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
|
||||
* or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
|
||||
* this in the rare case that one argument is slightly negative.
|
||||
* The implementation is extremely stable numerically.
|
||||
* In particular it guarantees that the result r satisfies
|
||||
* MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
|
||||
* even when a and b differ greatly in magnitude.
|
||||
*/
|
||||
#define RealInterpolate(a,x,b,y) \
|
||||
(a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \
|
||||
((a <= b) ? ((b == 0) ? ((x+y) / 2) \
|
||||
: (x + (y-x) * (a/(a+b)))) \
|
||||
: (y + (x-y) * (b/(a+b)))))
|
||||
|
||||
#ifndef FOR_TRITE_TEST_PROGRAM
|
||||
#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y)
|
||||
#else
|
||||
|
||||
/* Claim: the ONLY property the sweep algorithm relies on is that
|
||||
* MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
extern int RandomInterpolate;
|
||||
|
||||
GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y)
|
||||
{
|
||||
printf("*********************%d\n",RandomInterpolate);
|
||||
if( RandomInterpolate ) {
|
||||
a = 1.2 * drand48() - 0.1;
|
||||
a = (a < 0) ? 0 : ((a > 1) ? 1 : a);
|
||||
b = 1.0 - a;
|
||||
}
|
||||
return RealInterpolate(a,x,b,y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while (0)
|
||||
|
||||
void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
|
||||
GLUvertex *o2, GLUvertex *d2,
|
||||
GLUvertex *v )
|
||||
/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
|
||||
* The computed point is guaranteed to lie in the intersection of the
|
||||
* bounding rectangles defined by each edge.
|
||||
*/
|
||||
{
|
||||
GLdouble z1, z2;
|
||||
|
||||
/* This is certainly not the most efficient way to find the intersection
|
||||
* of two line segments, but it is very numerically stable.
|
||||
*
|
||||
* Strategy: find the two middle vertices in the VertLeq ordering,
|
||||
* and interpolate the intersection s-value from these. Then repeat
|
||||
* using the TransLeq ordering to find the intersection t-value.
|
||||
*/
|
||||
|
||||
if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
|
||||
if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
|
||||
if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
|
||||
|
||||
if( ! VertLeq( o2, d1 )) {
|
||||
/* Technically, no intersection -- do our best */
|
||||
v->s = (o2->s + d1->s) / 2;
|
||||
} else if( VertLeq( d1, d2 )) {
|
||||
/* Interpolate between o2 and d1 */
|
||||
z1 = EdgeEval( o1, o2, d1 );
|
||||
z2 = EdgeEval( o2, d1, d2 );
|
||||
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
|
||||
v->s = Interpolate( z1, o2->s, z2, d1->s );
|
||||
} else {
|
||||
/* Interpolate between o2 and d2 */
|
||||
z1 = EdgeSign( o1, o2, d1 );
|
||||
z2 = -EdgeSign( o1, d2, d1 );
|
||||
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
|
||||
v->s = Interpolate( z1, o2->s, z2, d2->s );
|
||||
}
|
||||
|
||||
/* Now repeat the process for t */
|
||||
|
||||
if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
|
||||
if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
|
||||
if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
|
||||
|
||||
if( ! TransLeq( o2, d1 )) {
|
||||
/* Technically, no intersection -- do our best */
|
||||
v->t = (o2->t + d1->t) / 2;
|
||||
} else if( TransLeq( d1, d2 )) {
|
||||
/* Interpolate between o2 and d1 */
|
||||
z1 = TransEval( o1, o2, d1 );
|
||||
z2 = TransEval( o2, d1, d2 );
|
||||
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
|
||||
v->t = Interpolate( z1, o2->t, z2, d1->t );
|
||||
} else {
|
||||
/* Interpolate between o2 and d2 */
|
||||
z1 = TransSign( o1, o2, d1 );
|
||||
z2 = -TransSign( o1, d2, d1 );
|
||||
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
|
||||
v->t = Interpolate( z1, o2->t, z2, d2->t );
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __geom_h_
|
||||
#define __geom_h_
|
||||
|
||||
#include "mesh.h"
|
||||
|
||||
#ifdef NO_BRANCH_CONDITIONS
|
||||
/* MIPS architecture has special instructions to evaluate boolean
|
||||
* conditions -- more efficient than branching, IF you can get the
|
||||
* compiler to generate the right instructions (SGI compiler doesn't)
|
||||
*/
|
||||
#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t))
|
||||
#define VertLeq(u,v) (((u)->s < (v)->s) | \
|
||||
((u)->s == (v)->s & (u)->t <= (v)->t))
|
||||
#else
|
||||
#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t)
|
||||
#define VertLeq(u,v) (((u)->s < (v)->s) || \
|
||||
((u)->s == (v)->s && (u)->t <= (v)->t))
|
||||
#endif
|
||||
|
||||
#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w)
|
||||
#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w)
|
||||
|
||||
/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
|
||||
|
||||
#define TransLeq(u,v) (((u)->t < (v)->t) || \
|
||||
((u)->t == (v)->t && (u)->s <= (v)->s))
|
||||
#define TransEval(u,v,w) __gl_transEval(u,v,w)
|
||||
#define TransSign(u,v,w) __gl_transSign(u,v,w)
|
||||
|
||||
|
||||
#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org )
|
||||
#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst )
|
||||
|
||||
#undef ABS
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t))
|
||||
|
||||
#define VertCCW(u,v,w) __gl_vertCCW(u,v,w)
|
||||
|
||||
int __gl_vertLeq( GLUvertex *u, GLUvertex *v );
|
||||
GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
|
||||
GLUvertex *o2, GLUvertex *d2,
|
||||
GLUvertex *v );
|
||||
|
||||
#endif
|
@ -1 +0,0 @@
|
||||
/* This is a stub header to avoid having to change tess.c */
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2010 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* This is a simple replacement for memalloc from the SGI tesselator
|
||||
code to force it to use glib's allocation instead */
|
||||
|
||||
#ifndef __MEMALLOC_H__
|
||||
#define __MEMALLOC_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define memRealloc g_realloc
|
||||
#define memAlloc g_malloc
|
||||
#define memFree g_free
|
||||
#define memInit(x) 1
|
||||
|
||||
/* tess.c defines TRUE and FALSE itself unconditionally so we need to
|
||||
undefine it from the glib headers */
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
|
||||
#endif /* __MEMALLOC_H__ */
|
@ -1,798 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include "mesh.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
static GLUvertex *allocVertex(void)
|
||||
{
|
||||
return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
|
||||
}
|
||||
|
||||
static GLUface *allocFace(void)
|
||||
{
|
||||
return (GLUface *)memAlloc( sizeof( GLUface ));
|
||||
}
|
||||
|
||||
/************************ Utility Routines ************************/
|
||||
|
||||
/* Allocate and free half-edges in pairs for efficiency.
|
||||
* The *only* place that should use this fact is allocation/free.
|
||||
*/
|
||||
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
|
||||
|
||||
/* MakeEdge creates a new pair of half-edges which form their own loop.
|
||||
* No vertex or face structures are allocated, but these must be assigned
|
||||
* before the current edge operation is completed.
|
||||
*/
|
||||
static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
|
||||
{
|
||||
GLUhalfEdge *e;
|
||||
GLUhalfEdge *eSym;
|
||||
GLUhalfEdge *ePrev;
|
||||
EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
|
||||
if (pair == NULL) return NULL;
|
||||
|
||||
e = &pair->e;
|
||||
eSym = &pair->eSym;
|
||||
|
||||
/* Make sure eNext points to the first edge of the edge pair */
|
||||
if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
|
||||
|
||||
/* Insert in circular doubly-linked list before eNext.
|
||||
* Note that the prev pointer is stored in Sym->next.
|
||||
*/
|
||||
ePrev = eNext->Sym->next;
|
||||
eSym->next = ePrev;
|
||||
ePrev->Sym->next = e;
|
||||
e->next = eNext;
|
||||
eNext->Sym->next = eSym;
|
||||
|
||||
e->Sym = eSym;
|
||||
e->Onext = e;
|
||||
e->Lnext = eSym;
|
||||
e->Org = NULL;
|
||||
e->Lface = NULL;
|
||||
e->winding = 0;
|
||||
e->activeRegion = NULL;
|
||||
|
||||
eSym->Sym = e;
|
||||
eSym->Onext = eSym;
|
||||
eSym->Lnext = e;
|
||||
eSym->Org = NULL;
|
||||
eSym->Lface = NULL;
|
||||
eSym->winding = 0;
|
||||
eSym->activeRegion = NULL;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
|
||||
* CS348a notes (see mesh.h). Basically it modifies the mesh so that
|
||||
* a->Onext and b->Onext are exchanged. This can have various effects
|
||||
* depending on whether a and b belong to different face or vertex rings.
|
||||
* For more explanation see __gl_meshSplice() below.
|
||||
*/
|
||||
static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
|
||||
{
|
||||
GLUhalfEdge *aOnext = a->Onext;
|
||||
GLUhalfEdge *bOnext = b->Onext;
|
||||
|
||||
aOnext->Sym->Lnext = b;
|
||||
bOnext->Sym->Lnext = a;
|
||||
a->Onext = bOnext;
|
||||
b->Onext = aOnext;
|
||||
}
|
||||
|
||||
/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
|
||||
* origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
|
||||
* a place to insert the new vertex in the global vertex list. We insert
|
||||
* the new vertex *before* vNext so that algorithms which walk the vertex
|
||||
* list will not see the newly created vertices.
|
||||
*/
|
||||
static void MakeVertex( GLUvertex *newVertex,
|
||||
GLUhalfEdge *eOrig, GLUvertex *vNext )
|
||||
{
|
||||
GLUhalfEdge *e;
|
||||
GLUvertex *vPrev;
|
||||
GLUvertex *vNew = newVertex;
|
||||
|
||||
assert(vNew != NULL);
|
||||
|
||||
/* insert in circular doubly-linked list before vNext */
|
||||
vPrev = vNext->prev;
|
||||
vNew->prev = vPrev;
|
||||
vPrev->next = vNew;
|
||||
vNew->next = vNext;
|
||||
vNext->prev = vNew;
|
||||
|
||||
vNew->anEdge = eOrig;
|
||||
vNew->data = NULL;
|
||||
/* leave coords, s, t undefined */
|
||||
|
||||
/* fix other edges on this vertex loop */
|
||||
e = eOrig;
|
||||
do {
|
||||
e->Org = vNew;
|
||||
e = e->Onext;
|
||||
} while( e != eOrig );
|
||||
}
|
||||
|
||||
/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
|
||||
* face of all edges in the face loop to which eOrig belongs. "fNext" gives
|
||||
* a place to insert the new face in the global face list. We insert
|
||||
* the new face *before* fNext so that algorithms which walk the face
|
||||
* list will not see the newly created faces.
|
||||
*/
|
||||
static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
|
||||
{
|
||||
GLUhalfEdge *e;
|
||||
GLUface *fPrev;
|
||||
GLUface *fNew = newFace;
|
||||
|
||||
assert(fNew != NULL);
|
||||
|
||||
/* insert in circular doubly-linked list before fNext */
|
||||
fPrev = fNext->prev;
|
||||
fNew->prev = fPrev;
|
||||
fPrev->next = fNew;
|
||||
fNew->next = fNext;
|
||||
fNext->prev = fNew;
|
||||
|
||||
fNew->anEdge = eOrig;
|
||||
fNew->data = NULL;
|
||||
fNew->trail = NULL;
|
||||
fNew->marked = FALSE;
|
||||
|
||||
/* The new face is marked "inside" if the old one was. This is a
|
||||
* convenience for the common case where a face has been split in two.
|
||||
*/
|
||||
fNew->inside = fNext->inside;
|
||||
|
||||
/* fix other edges on this face loop */
|
||||
e = eOrig;
|
||||
do {
|
||||
e->Lface = fNew;
|
||||
e = e->Lnext;
|
||||
} while( e != eOrig );
|
||||
}
|
||||
|
||||
/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
|
||||
* and removes from the global edge list.
|
||||
*/
|
||||
static void KillEdge( GLUhalfEdge *eDel )
|
||||
{
|
||||
GLUhalfEdge *ePrev, *eNext;
|
||||
|
||||
/* Half-edges are allocated in pairs, see EdgePair above */
|
||||
if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
|
||||
|
||||
/* delete from circular doubly-linked list */
|
||||
eNext = eDel->next;
|
||||
ePrev = eDel->Sym->next;
|
||||
eNext->Sym->next = ePrev;
|
||||
ePrev->Sym->next = eNext;
|
||||
|
||||
memFree( eDel );
|
||||
}
|
||||
|
||||
|
||||
/* KillVertex( vDel ) destroys a vertex and removes it from the global
|
||||
* vertex list. It updates the vertex loop to point to a given new vertex.
|
||||
*/
|
||||
static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
|
||||
{
|
||||
GLUhalfEdge *e, *eStart = vDel->anEdge;
|
||||
GLUvertex *vPrev, *vNext;
|
||||
|
||||
/* change the origin of all affected edges */
|
||||
e = eStart;
|
||||
do {
|
||||
e->Org = newOrg;
|
||||
e = e->Onext;
|
||||
} while( e != eStart );
|
||||
|
||||
/* delete from circular doubly-linked list */
|
||||
vPrev = vDel->prev;
|
||||
vNext = vDel->next;
|
||||
vNext->prev = vPrev;
|
||||
vPrev->next = vNext;
|
||||
|
||||
memFree( vDel );
|
||||
}
|
||||
|
||||
/* KillFace( fDel ) destroys a face and removes it from the global face
|
||||
* list. It updates the face loop to point to a given new face.
|
||||
*/
|
||||
static void KillFace( GLUface *fDel, GLUface *newLface )
|
||||
{
|
||||
GLUhalfEdge *e, *eStart = fDel->anEdge;
|
||||
GLUface *fPrev, *fNext;
|
||||
|
||||
/* change the left face of all affected edges */
|
||||
e = eStart;
|
||||
do {
|
||||
e->Lface = newLface;
|
||||
e = e->Lnext;
|
||||
} while( e != eStart );
|
||||
|
||||
/* delete from circular doubly-linked list */
|
||||
fPrev = fDel->prev;
|
||||
fNext = fDel->next;
|
||||
fNext->prev = fPrev;
|
||||
fPrev->next = fNext;
|
||||
|
||||
memFree( fDel );
|
||||
}
|
||||
|
||||
|
||||
/****************** Basic Edge Operations **********************/
|
||||
|
||||
/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
|
||||
* The loop consists of the two new half-edges.
|
||||
*/
|
||||
GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
|
||||
{
|
||||
GLUvertex *newVertex1= allocVertex();
|
||||
GLUvertex *newVertex2= allocVertex();
|
||||
GLUface *newFace= allocFace();
|
||||
GLUhalfEdge *e;
|
||||
|
||||
/* if any one is null then all get freed */
|
||||
if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
|
||||
if (newVertex1 != NULL) memFree(newVertex1);
|
||||
if (newVertex2 != NULL) memFree(newVertex2);
|
||||
if (newFace != NULL) memFree(newFace);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
e = MakeEdge( &mesh->eHead );
|
||||
if (e == NULL) {
|
||||
memFree(newVertex1);
|
||||
memFree(newVertex2);
|
||||
memFree(newFace);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MakeVertex( newVertex1, e, &mesh->vHead );
|
||||
MakeVertex( newVertex2, e->Sym, &mesh->vHead );
|
||||
MakeFace( newFace, e, &mesh->fHead );
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
|
||||
* mesh connectivity and topology. It changes the mesh so that
|
||||
* eOrg->Onext <- OLD( eDst->Onext )
|
||||
* eDst->Onext <- OLD( eOrg->Onext )
|
||||
* where OLD(...) means the value before the meshSplice operation.
|
||||
*
|
||||
* This can have two effects on the vertex structure:
|
||||
* - if eOrg->Org != eDst->Org, the two vertices are merged together
|
||||
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
|
||||
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
|
||||
*
|
||||
* Similarly (and independently) for the face structure,
|
||||
* - if eOrg->Lface == eDst->Lface, one loop is split into two
|
||||
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
|
||||
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
|
||||
*
|
||||
* Some special cases:
|
||||
* If eDst == eOrg, the operation has no effect.
|
||||
* If eDst == eOrg->Lnext, the new face will have a single edge.
|
||||
* If eDst == eOrg->Lprev, the old face will have a single edge.
|
||||
* If eDst == eOrg->Onext, the new vertex will have a single edge.
|
||||
* If eDst == eOrg->Oprev, the old vertex will have a single edge.
|
||||
*/
|
||||
int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
|
||||
{
|
||||
int joiningLoops = FALSE;
|
||||
int joiningVertices = FALSE;
|
||||
|
||||
if( eOrg == eDst ) return 1;
|
||||
|
||||
if( eDst->Org != eOrg->Org ) {
|
||||
/* We are merging two disjoint vertices -- destroy eDst->Org */
|
||||
joiningVertices = TRUE;
|
||||
KillVertex( eDst->Org, eOrg->Org );
|
||||
}
|
||||
if( eDst->Lface != eOrg->Lface ) {
|
||||
/* We are connecting two disjoint loops -- destroy eDst->Lface */
|
||||
joiningLoops = TRUE;
|
||||
KillFace( eDst->Lface, eOrg->Lface );
|
||||
}
|
||||
|
||||
/* Change the edge structure */
|
||||
Splice( eDst, eOrg );
|
||||
|
||||
if( ! joiningVertices ) {
|
||||
GLUvertex *newVertex= allocVertex();
|
||||
if (newVertex == NULL) return 0;
|
||||
|
||||
/* We split one vertex into two -- the new vertex is eDst->Org.
|
||||
* Make sure the old vertex points to a valid half-edge.
|
||||
*/
|
||||
MakeVertex( newVertex, eDst, eOrg->Org );
|
||||
eOrg->Org->anEdge = eOrg;
|
||||
}
|
||||
if( ! joiningLoops ) {
|
||||
GLUface *newFace= allocFace();
|
||||
if (newFace == NULL) return 0;
|
||||
|
||||
/* We split one loop into two -- the new loop is eDst->Lface.
|
||||
* Make sure the old face points to a valid half-edge.
|
||||
*/
|
||||
MakeFace( newFace, eDst, eOrg->Lface );
|
||||
eOrg->Lface->anEdge = eOrg;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
|
||||
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
|
||||
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
|
||||
* the newly created loop will contain eDel->Dst. If the deletion of eDel
|
||||
* would create isolated vertices, those are deleted as well.
|
||||
*
|
||||
* This function could be implemented as two calls to __gl_meshSplice
|
||||
* plus a few calls to memFree, but this would allocate and delete
|
||||
* unnecessary vertices and faces.
|
||||
*/
|
||||
int __gl_meshDelete( GLUhalfEdge *eDel )
|
||||
{
|
||||
GLUhalfEdge *eDelSym = eDel->Sym;
|
||||
int joiningLoops = FALSE;
|
||||
|
||||
/* First step: disconnect the origin vertex eDel->Org. We make all
|
||||
* changes to get a consistent mesh in this "intermediate" state.
|
||||
*/
|
||||
if( eDel->Lface != eDel->Rface ) {
|
||||
/* We are joining two loops into one -- remove the left face */
|
||||
joiningLoops = TRUE;
|
||||
KillFace( eDel->Lface, eDel->Rface );
|
||||
}
|
||||
|
||||
if( eDel->Onext == eDel ) {
|
||||
KillVertex( eDel->Org, NULL );
|
||||
} else {
|
||||
/* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
|
||||
eDel->Rface->anEdge = eDel->Oprev;
|
||||
eDel->Org->anEdge = eDel->Onext;
|
||||
|
||||
Splice( eDel, eDel->Oprev );
|
||||
if( ! joiningLoops ) {
|
||||
GLUface *newFace= allocFace();
|
||||
if (newFace == NULL) return 0;
|
||||
|
||||
/* We are splitting one loop into two -- create a new loop for eDel. */
|
||||
MakeFace( newFace, eDel, eDel->Lface );
|
||||
}
|
||||
}
|
||||
|
||||
/* Claim: the mesh is now in a consistent state, except that eDel->Org
|
||||
* may have been deleted. Now we disconnect eDel->Dst.
|
||||
*/
|
||||
if( eDelSym->Onext == eDelSym ) {
|
||||
KillVertex( eDelSym->Org, NULL );
|
||||
KillFace( eDelSym->Lface, NULL );
|
||||
} else {
|
||||
/* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
|
||||
eDel->Lface->anEdge = eDelSym->Oprev;
|
||||
eDelSym->Org->anEdge = eDelSym->Onext;
|
||||
Splice( eDelSym, eDelSym->Oprev );
|
||||
}
|
||||
|
||||
/* Any isolated vertices or faces have already been freed. */
|
||||
KillEdge( eDel );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/******************** Other Edge Operations **********************/
|
||||
|
||||
/* All these routines can be implemented with the basic edge
|
||||
* operations above. They are provided for convenience and efficiency.
|
||||
*/
|
||||
|
||||
|
||||
/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
|
||||
* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*/
|
||||
GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
|
||||
{
|
||||
GLUhalfEdge *eNewSym;
|
||||
GLUhalfEdge *eNew = MakeEdge( eOrg );
|
||||
if (eNew == NULL) return NULL;
|
||||
|
||||
eNewSym = eNew->Sym;
|
||||
|
||||
/* Connect the new edge appropriately */
|
||||
Splice( eNew, eOrg->Lnext );
|
||||
|
||||
/* Set the vertex and face information */
|
||||
eNew->Org = eOrg->Dst;
|
||||
{
|
||||
GLUvertex *newVertex= allocVertex();
|
||||
if (newVertex == NULL) return NULL;
|
||||
|
||||
MakeVertex( newVertex, eNewSym, eNew->Org );
|
||||
}
|
||||
eNew->Lface = eNewSym->Lface = eOrg->Lface;
|
||||
|
||||
return eNew;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
|
||||
* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*/
|
||||
GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
|
||||
{
|
||||
GLUhalfEdge *eNew;
|
||||
GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
|
||||
if (tempHalfEdge == NULL) return NULL;
|
||||
|
||||
eNew = tempHalfEdge->Sym;
|
||||
|
||||
/* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
|
||||
Splice( eOrg->Sym, eOrg->Sym->Oprev );
|
||||
Splice( eOrg->Sym, eNew );
|
||||
|
||||
/* Set the vertex and face information */
|
||||
eOrg->Dst = eNew->Org;
|
||||
eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
|
||||
eNew->Rface = eOrg->Rface;
|
||||
eNew->winding = eOrg->winding; /* copy old winding information */
|
||||
eNew->Sym->winding = eOrg->Sym->winding;
|
||||
|
||||
return eNew;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
|
||||
* to eDst->Org, and returns the corresponding half-edge eNew.
|
||||
* If eOrg->Lface == eDst->Lface, this splits one loop into two,
|
||||
* and the newly created loop is eNew->Lface. Otherwise, two disjoint
|
||||
* loops are merged into one, and the loop eDst->Lface is destroyed.
|
||||
*
|
||||
* If (eOrg == eDst), the new face will have only two edges.
|
||||
* If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
|
||||
* If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
|
||||
*/
|
||||
GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
|
||||
{
|
||||
GLUhalfEdge *eNewSym;
|
||||
int joiningLoops = FALSE;
|
||||
GLUhalfEdge *eNew = MakeEdge( eOrg );
|
||||
if (eNew == NULL) return NULL;
|
||||
|
||||
eNewSym = eNew->Sym;
|
||||
|
||||
if( eDst->Lface != eOrg->Lface ) {
|
||||
/* We are connecting two disjoint loops -- destroy eDst->Lface */
|
||||
joiningLoops = TRUE;
|
||||
KillFace( eDst->Lface, eOrg->Lface );
|
||||
}
|
||||
|
||||
/* Connect the new edge appropriately */
|
||||
Splice( eNew, eOrg->Lnext );
|
||||
Splice( eNewSym, eDst );
|
||||
|
||||
/* Set the vertex and face information */
|
||||
eNew->Org = eOrg->Dst;
|
||||
eNewSym->Org = eDst->Org;
|
||||
eNew->Lface = eNewSym->Lface = eOrg->Lface;
|
||||
|
||||
/* Make sure the old face points to a valid half-edge */
|
||||
eOrg->Lface->anEdge = eNewSym;
|
||||
|
||||
if( ! joiningLoops ) {
|
||||
GLUface *newFace= allocFace();
|
||||
if (newFace == NULL) return NULL;
|
||||
|
||||
/* We split one loop into two -- the new loop is eNew->Lface */
|
||||
MakeFace( newFace, eNew, eOrg->Lface );
|
||||
}
|
||||
return eNew;
|
||||
}
|
||||
|
||||
|
||||
/******************** Other Operations **********************/
|
||||
|
||||
/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
|
||||
* global face list. All edges of fZap will have a NULL pointer as their
|
||||
* left face. Any edges which also have a NULL pointer as their right face
|
||||
* are deleted entirely (along with any isolated vertices this produces).
|
||||
* An entire mesh can be deleted by zapping its faces, one at a time,
|
||||
* in any order. Zapped faces cannot be used in further mesh operations!
|
||||
*/
|
||||
void __gl_meshZapFace( GLUface *fZap )
|
||||
{
|
||||
GLUhalfEdge *eStart = fZap->anEdge;
|
||||
GLUhalfEdge *e, *eNext, *eSym;
|
||||
GLUface *fPrev, *fNext;
|
||||
|
||||
/* walk around face, deleting edges whose right face is also NULL */
|
||||
eNext = eStart->Lnext;
|
||||
do {
|
||||
e = eNext;
|
||||
eNext = e->Lnext;
|
||||
|
||||
e->Lface = NULL;
|
||||
if( e->Rface == NULL ) {
|
||||
/* delete the edge -- see __gl_MeshDelete above */
|
||||
|
||||
if( e->Onext == e ) {
|
||||
KillVertex( e->Org, NULL );
|
||||
} else {
|
||||
/* Make sure that e->Org points to a valid half-edge */
|
||||
e->Org->anEdge = e->Onext;
|
||||
Splice( e, e->Oprev );
|
||||
}
|
||||
eSym = e->Sym;
|
||||
if( eSym->Onext == eSym ) {
|
||||
KillVertex( eSym->Org, NULL );
|
||||
} else {
|
||||
/* Make sure that eSym->Org points to a valid half-edge */
|
||||
eSym->Org->anEdge = eSym->Onext;
|
||||
Splice( eSym, eSym->Oprev );
|
||||
}
|
||||
KillEdge( e );
|
||||
}
|
||||
} while( e != eStart );
|
||||
|
||||
/* delete from circular doubly-linked list */
|
||||
fPrev = fZap->prev;
|
||||
fNext = fZap->next;
|
||||
fNext->prev = fPrev;
|
||||
fPrev->next = fNext;
|
||||
|
||||
memFree( fZap );
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
|
||||
* and no loops (what we usually call a "face").
|
||||
*/
|
||||
GLUmesh *__gl_meshNewMesh( void )
|
||||
{
|
||||
GLUvertex *v;
|
||||
GLUface *f;
|
||||
GLUhalfEdge *e;
|
||||
GLUhalfEdge *eSym;
|
||||
GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
|
||||
if (mesh == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v = &mesh->vHead;
|
||||
f = &mesh->fHead;
|
||||
e = &mesh->eHead;
|
||||
eSym = &mesh->eHeadSym;
|
||||
|
||||
v->next = v->prev = v;
|
||||
v->anEdge = NULL;
|
||||
v->data = NULL;
|
||||
|
||||
f->next = f->prev = f;
|
||||
f->anEdge = NULL;
|
||||
f->data = NULL;
|
||||
f->trail = NULL;
|
||||
f->marked = FALSE;
|
||||
f->inside = FALSE;
|
||||
|
||||
e->next = e;
|
||||
e->Sym = eSym;
|
||||
e->Onext = NULL;
|
||||
e->Lnext = NULL;
|
||||
e->Org = NULL;
|
||||
e->Lface = NULL;
|
||||
e->winding = 0;
|
||||
e->activeRegion = NULL;
|
||||
|
||||
eSym->next = eSym;
|
||||
eSym->Sym = e;
|
||||
eSym->Onext = NULL;
|
||||
eSym->Lnext = NULL;
|
||||
eSym->Org = NULL;
|
||||
eSym->Lface = NULL;
|
||||
eSym->winding = 0;
|
||||
eSym->activeRegion = NULL;
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
|
||||
* both meshes, and returns the new mesh (the old meshes are destroyed).
|
||||
*/
|
||||
GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
|
||||
{
|
||||
GLUface *f1 = &mesh1->fHead;
|
||||
GLUvertex *v1 = &mesh1->vHead;
|
||||
GLUhalfEdge *e1 = &mesh1->eHead;
|
||||
GLUface *f2 = &mesh2->fHead;
|
||||
GLUvertex *v2 = &mesh2->vHead;
|
||||
GLUhalfEdge *e2 = &mesh2->eHead;
|
||||
|
||||
/* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
|
||||
if( f2->next != f2 ) {
|
||||
f1->prev->next = f2->next;
|
||||
f2->next->prev = f1->prev;
|
||||
f2->prev->next = f1;
|
||||
f1->prev = f2->prev;
|
||||
}
|
||||
|
||||
if( v2->next != v2 ) {
|
||||
v1->prev->next = v2->next;
|
||||
v2->next->prev = v1->prev;
|
||||
v2->prev->next = v1;
|
||||
v1->prev = v2->prev;
|
||||
}
|
||||
|
||||
if( e2->next != e2 ) {
|
||||
e1->Sym->next->Sym->next = e2->next;
|
||||
e2->next->Sym->next = e1->Sym->next;
|
||||
e2->Sym->next->Sym->next = e1;
|
||||
e1->Sym->next = e2->Sym->next;
|
||||
}
|
||||
|
||||
memFree( mesh2 );
|
||||
return mesh1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DELETE_BY_ZAPPING
|
||||
|
||||
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
|
||||
*/
|
||||
void __gl_meshDeleteMesh( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *fHead = &mesh->fHead;
|
||||
|
||||
while( fHead->next != fHead ) {
|
||||
__gl_meshZapFace( fHead->next );
|
||||
}
|
||||
assert( mesh->vHead.next == &mesh->vHead );
|
||||
|
||||
memFree( mesh );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
|
||||
*/
|
||||
void __gl_meshDeleteMesh( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f, *fNext;
|
||||
GLUvertex *v, *vNext;
|
||||
GLUhalfEdge *e, *eNext;
|
||||
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
|
||||
fNext = f->next;
|
||||
memFree( f );
|
||||
}
|
||||
|
||||
for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
|
||||
vNext = v->next;
|
||||
memFree( v );
|
||||
}
|
||||
|
||||
for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
|
||||
/* One call frees both e and e->Sym (see EdgePair above) */
|
||||
eNext = e->next;
|
||||
memFree( e );
|
||||
}
|
||||
|
||||
memFree( mesh );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
|
||||
*/
|
||||
void __gl_meshCheckMesh( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *fHead = &mesh->fHead;
|
||||
GLUvertex *vHead = &mesh->vHead;
|
||||
GLUhalfEdge *eHead = &mesh->eHead;
|
||||
GLUface *f, *fPrev;
|
||||
GLUvertex *v, *vPrev;
|
||||
GLUhalfEdge *e, *ePrev;
|
||||
|
||||
fPrev = fHead;
|
||||
for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
|
||||
assert( f->prev == fPrev );
|
||||
e = f->anEdge;
|
||||
do {
|
||||
assert( e->Sym != e );
|
||||
assert( e->Sym->Sym == e );
|
||||
assert( e->Lnext->Onext->Sym == e );
|
||||
assert( e->Onext->Sym->Lnext == e );
|
||||
assert( e->Lface == f );
|
||||
e = e->Lnext;
|
||||
} while( e != f->anEdge );
|
||||
}
|
||||
assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
|
||||
|
||||
vPrev = vHead;
|
||||
for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
|
||||
assert( v->prev == vPrev );
|
||||
e = v->anEdge;
|
||||
do {
|
||||
assert( e->Sym != e );
|
||||
assert( e->Sym->Sym == e );
|
||||
assert( e->Lnext->Onext->Sym == e );
|
||||
assert( e->Onext->Sym->Lnext == e );
|
||||
assert( e->Org == v );
|
||||
e = e->Onext;
|
||||
} while( e != v->anEdge );
|
||||
}
|
||||
assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
|
||||
|
||||
ePrev = eHead;
|
||||
for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
|
||||
assert( e->Sym->next == ePrev->Sym );
|
||||
assert( e->Sym != e );
|
||||
assert( e->Sym->Sym == e );
|
||||
assert( e->Org != NULL );
|
||||
assert( e->Dst != NULL );
|
||||
assert( e->Lnext->Onext->Sym == e );
|
||||
assert( e->Onext->Sym->Lnext == e );
|
||||
}
|
||||
assert( e->Sym->next == ePrev->Sym
|
||||
&& e->Sym == &mesh->eHeadSym
|
||||
&& e->Sym->Sym == e
|
||||
&& e->Org == NULL && e->Dst == NULL
|
||||
&& e->Lface == NULL && e->Rface == NULL );
|
||||
}
|
||||
|
||||
#endif
|
@ -1,266 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __mesh_h_
|
||||
#define __mesh_h_
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
typedef struct GLUmesh GLUmesh;
|
||||
|
||||
typedef struct GLUvertex GLUvertex;
|
||||
typedef struct GLUface GLUface;
|
||||
typedef struct GLUhalfEdge GLUhalfEdge;
|
||||
|
||||
typedef struct ActiveRegion ActiveRegion; /* Internal data */
|
||||
|
||||
/* The mesh structure is similar in spirit, notation, and operations
|
||||
* to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
|
||||
* for the manipulation of general subdivisions and the computation of
|
||||
* Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
|
||||
* For a simplified description, see the course notes for CS348a,
|
||||
* "Mathematical Foundations of Computer Graphics", available at the
|
||||
* Stanford bookstore (and taught during the fall quarter).
|
||||
* The implementation also borrows a tiny subset of the graph-based approach
|
||||
* use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
|
||||
* to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
|
||||
*
|
||||
* The fundamental data structure is the "half-edge". Two half-edges
|
||||
* go together to make an edge, but they point in opposite directions.
|
||||
* Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
|
||||
* its origin vertex (Org), the face on its left side (Lface), and the
|
||||
* adjacent half-edges in the CCW direction around the origin vertex
|
||||
* (Onext) and around the left face (Lnext). There is also a "next"
|
||||
* pointer for the global edge list (see below).
|
||||
*
|
||||
* The notation used for mesh navigation:
|
||||
* Sym = the mate of a half-edge (same edge, but opposite direction)
|
||||
* Onext = edge CCW around origin vertex (keep same origin)
|
||||
* Dnext = edge CCW around destination vertex (keep same dest)
|
||||
* Lnext = edge CCW around left face (dest becomes new origin)
|
||||
* Rnext = edge CCW around right face (origin becomes new dest)
|
||||
*
|
||||
* "prev" means to substitute CW for CCW in the definitions above.
|
||||
*
|
||||
* The mesh keeps global lists of all vertices, faces, and edges,
|
||||
* stored as doubly-linked circular lists with a dummy header node.
|
||||
* The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
|
||||
*
|
||||
* The circular edge list is special; since half-edges always occur
|
||||
* in pairs (e and e->Sym), each half-edge stores a pointer in only
|
||||
* one direction. Starting at eHead and following the e->next pointers
|
||||
* will visit each *edge* once (ie. e or e->Sym, but not both).
|
||||
* e->Sym stores a pointer in the opposite direction, thus it is
|
||||
* always true that e->Sym->next->Sym->next == e.
|
||||
*
|
||||
* Each vertex has a pointer to next and previous vertices in the
|
||||
* circular list, and a pointer to a half-edge with this vertex as
|
||||
* the origin (NULL if this is the dummy header). There is also a
|
||||
* field "data" for client data.
|
||||
*
|
||||
* Each face has a pointer to the next and previous faces in the
|
||||
* circular list, and a pointer to a half-edge with this face as
|
||||
* the left face (NULL if this is the dummy header). There is also
|
||||
* a field "data" for client data.
|
||||
*
|
||||
* Note that what we call a "face" is really a loop; faces may consist
|
||||
* of more than one loop (ie. not simply connected), but there is no
|
||||
* record of this in the data structure. The mesh may consist of
|
||||
* several disconnected regions, so it may not be possible to visit
|
||||
* the entire mesh by starting at a half-edge and traversing the edge
|
||||
* structure.
|
||||
*
|
||||
* The mesh does NOT support isolated vertices; a vertex is deleted along
|
||||
* with its last edge. Similarly when two faces are merged, one of the
|
||||
* faces is deleted (see __gl_meshDelete below). For mesh operations,
|
||||
* all face (loop) and vertex pointers must not be NULL. However, once
|
||||
* mesh manipulation is finished, __gl_MeshZapFace can be used to delete
|
||||
* faces of the mesh, one at a time. All external faces can be "zapped"
|
||||
* before the mesh is returned to the client; then a NULL face indicates
|
||||
* a region which is not part of the output polygon.
|
||||
*/
|
||||
|
||||
struct GLUvertex {
|
||||
GLUvertex *next; /* next vertex (never NULL) */
|
||||
GLUvertex *prev; /* previous vertex (never NULL) */
|
||||
GLUhalfEdge *anEdge; /* a half-edge with this origin */
|
||||
void *data; /* client's data */
|
||||
|
||||
/* Internal data (keep hidden) */
|
||||
GLdouble coords[3]; /* vertex location in 3D */
|
||||
GLdouble s, t; /* projection onto the sweep plane */
|
||||
long pqHandle; /* to allow deletion from priority queue */
|
||||
};
|
||||
|
||||
struct GLUface {
|
||||
GLUface *next; /* next face (never NULL) */
|
||||
GLUface *prev; /* previous face (never NULL) */
|
||||
GLUhalfEdge *anEdge; /* a half edge with this left face */
|
||||
void *data; /* room for client's data */
|
||||
|
||||
/* Internal data (keep hidden) */
|
||||
GLUface *trail; /* "stack" for conversion to strips */
|
||||
GLboolean marked; /* flag for conversion to strips */
|
||||
GLboolean inside; /* this face is in the polygon interior */
|
||||
};
|
||||
|
||||
struct GLUhalfEdge {
|
||||
GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
|
||||
GLUhalfEdge *Sym; /* same edge, opposite direction */
|
||||
GLUhalfEdge *Onext; /* next edge CCW around origin */
|
||||
GLUhalfEdge *Lnext; /* next edge CCW around left face */
|
||||
GLUvertex *Org; /* origin vertex (Overtex too long) */
|
||||
GLUface *Lface; /* left face */
|
||||
|
||||
/* Internal data (keep hidden) */
|
||||
ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
|
||||
int winding; /* change in winding number when crossing
|
||||
from the right face to the left face */
|
||||
};
|
||||
|
||||
#define Rface Sym->Lface
|
||||
#define Dst Sym->Org
|
||||
|
||||
#define Oprev Sym->Lnext
|
||||
#define Lprev Onext->Sym
|
||||
#define Dprev Lnext->Sym
|
||||
#define Rprev Sym->Onext
|
||||
#define Dnext Rprev->Sym /* 3 pointers */
|
||||
#define Rnext Oprev->Sym /* 3 pointers */
|
||||
|
||||
|
||||
struct GLUmesh {
|
||||
GLUvertex vHead; /* dummy header for vertex list */
|
||||
GLUface fHead; /* dummy header for face list */
|
||||
GLUhalfEdge eHead; /* dummy header for edge list */
|
||||
GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
|
||||
};
|
||||
|
||||
/* The mesh operations below have three motivations: completeness,
|
||||
* convenience, and efficiency. The basic mesh operations are MakeEdge,
|
||||
* Splice, and Delete. All the other edge operations can be implemented
|
||||
* in terms of these. The other operations are provided for convenience
|
||||
* and/or efficiency.
|
||||
*
|
||||
* When a face is split or a vertex is added, they are inserted into the
|
||||
* global list *before* the existing vertex or face (ie. e->Org or e->Lface).
|
||||
* This makes it easier to process all vertices or faces in the global lists
|
||||
* without worrying about processing the same data twice. As a convenience,
|
||||
* when a face is split, the "inside" flag is copied from the old face.
|
||||
* Other internal data (v->data, v->activeRegion, f->data, f->marked,
|
||||
* f->trail, e->winding) is set to zero.
|
||||
*
|
||||
* ********************** Basic Edge Operations **************************
|
||||
*
|
||||
* __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
|
||||
* The loop (face) consists of the two new half-edges.
|
||||
*
|
||||
* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
|
||||
* mesh connectivity and topology. It changes the mesh so that
|
||||
* eOrg->Onext <- OLD( eDst->Onext )
|
||||
* eDst->Onext <- OLD( eOrg->Onext )
|
||||
* where OLD(...) means the value before the meshSplice operation.
|
||||
*
|
||||
* This can have two effects on the vertex structure:
|
||||
* - if eOrg->Org != eDst->Org, the two vertices are merged together
|
||||
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
|
||||
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
|
||||
*
|
||||
* Similarly (and independently) for the face structure,
|
||||
* - if eOrg->Lface == eDst->Lface, one loop is split into two
|
||||
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
|
||||
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
|
||||
*
|
||||
* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
|
||||
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
|
||||
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
|
||||
* the newly created loop will contain eDel->Dst. If the deletion of eDel
|
||||
* would create isolated vertices, those are deleted as well.
|
||||
*
|
||||
* ********************** Other Edge Operations **************************
|
||||
*
|
||||
* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
|
||||
* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*
|
||||
* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
|
||||
* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*
|
||||
* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
|
||||
* to eDst->Org, and returns the corresponding half-edge eNew.
|
||||
* If eOrg->Lface == eDst->Lface, this splits one loop into two,
|
||||
* and the newly created loop is eNew->Lface. Otherwise, two disjoint
|
||||
* loops are merged into one, and the loop eDst->Lface is destroyed.
|
||||
*
|
||||
* ************************ Other Operations *****************************
|
||||
*
|
||||
* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
|
||||
* and no loops (what we usually call a "face").
|
||||
*
|
||||
* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
|
||||
* both meshes, and returns the new mesh (the old meshes are destroyed).
|
||||
*
|
||||
* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
|
||||
*
|
||||
* __gl_meshZapFace( fZap ) destroys a face and removes it from the
|
||||
* global face list. All edges of fZap will have a NULL pointer as their
|
||||
* left face. Any edges which also have a NULL pointer as their right face
|
||||
* are deleted entirely (along with any isolated vertices this produces).
|
||||
* An entire mesh can be deleted by zapping its faces, one at a time,
|
||||
* in any order. Zapped faces cannot be used in further mesh operations!
|
||||
*
|
||||
* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
|
||||
*/
|
||||
|
||||
GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh );
|
||||
int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
|
||||
int __gl_meshDelete( GLUhalfEdge *eDel );
|
||||
|
||||
GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg );
|
||||
GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg );
|
||||
GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
|
||||
|
||||
GLUmesh *__gl_meshNewMesh( void );
|
||||
GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 );
|
||||
void __gl_meshDeleteMesh( GLUmesh *mesh );
|
||||
void __gl_meshZapFace( GLUface *fZap );
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define __gl_meshCheckMesh( mesh )
|
||||
#else
|
||||
void __gl_meshCheckMesh( GLUmesh *mesh );
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,257 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include "mesh.h"
|
||||
#include "tess.h"
|
||||
#include "normal.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
|
||||
|
||||
#if 0
|
||||
static void Normalize( GLdouble v[3] )
|
||||
{
|
||||
GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||
|
||||
assert( len > 0 );
|
||||
len = sqrt( len );
|
||||
v[0] /= len;
|
||||
v[1] /= len;
|
||||
v[2] /= len;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef ABS
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
static int LongAxis( GLdouble v[3] )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
|
||||
if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
|
||||
return i;
|
||||
}
|
||||
|
||||
static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
|
||||
{
|
||||
GLUvertex *v, *v1, *v2;
|
||||
GLdouble c, tLen2, maxLen2;
|
||||
GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
|
||||
GLUvertex *maxVert[3], *minVert[3];
|
||||
GLUvertex *vHead = &tess->mesh->vHead;
|
||||
int i;
|
||||
|
||||
maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
|
||||
minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
|
||||
|
||||
for( v = vHead->next; v != vHead; v = v->next ) {
|
||||
for( i = 0; i < 3; ++i ) {
|
||||
c = v->coords[i];
|
||||
if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
|
||||
if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Find two vertices separated by at least 1/sqrt(3) of the maximum
|
||||
* distance between any two vertices
|
||||
*/
|
||||
i = 0;
|
||||
if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
|
||||
if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
|
||||
if( minVal[i] >= maxVal[i] ) {
|
||||
/* All vertices are the same -- normal doesn't matter */
|
||||
norm[0] = 0; norm[1] = 0; norm[2] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Look for a third vertex which forms the triangle with maximum area
|
||||
* (Length of normal == twice the triangle area)
|
||||
*/
|
||||
maxLen2 = 0;
|
||||
v1 = minVert[i];
|
||||
v2 = maxVert[i];
|
||||
d1[0] = v1->coords[0] - v2->coords[0];
|
||||
d1[1] = v1->coords[1] - v2->coords[1];
|
||||
d1[2] = v1->coords[2] - v2->coords[2];
|
||||
for( v = vHead->next; v != vHead; v = v->next ) {
|
||||
d2[0] = v->coords[0] - v2->coords[0];
|
||||
d2[1] = v->coords[1] - v2->coords[1];
|
||||
d2[2] = v->coords[2] - v2->coords[2];
|
||||
tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
|
||||
tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
|
||||
tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
|
||||
tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
|
||||
if( tLen2 > maxLen2 ) {
|
||||
maxLen2 = tLen2;
|
||||
norm[0] = tNorm[0];
|
||||
norm[1] = tNorm[1];
|
||||
norm[2] = tNorm[2];
|
||||
}
|
||||
}
|
||||
|
||||
if( maxLen2 <= 0 ) {
|
||||
/* All points lie on a single line -- any decent normal will do */
|
||||
norm[0] = norm[1] = norm[2] = 0;
|
||||
norm[LongAxis(d1)] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void CheckOrientation( GLUtesselator *tess )
|
||||
{
|
||||
GLdouble area;
|
||||
GLUface *f, *fHead = &tess->mesh->fHead;
|
||||
GLUvertex *v, *vHead = &tess->mesh->vHead;
|
||||
GLUhalfEdge *e;
|
||||
|
||||
/* When we compute the normal automatically, we choose the orientation
|
||||
* so that the sum of the signed areas of all contours is non-negative.
|
||||
*/
|
||||
area = 0;
|
||||
for( f = fHead->next; f != fHead; f = f->next ) {
|
||||
e = f->anEdge;
|
||||
if( e->winding <= 0 ) continue;
|
||||
do {
|
||||
area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
|
||||
e = e->Lnext;
|
||||
} while( e != f->anEdge );
|
||||
}
|
||||
if( area < 0 ) {
|
||||
/* Reverse the orientation by flipping all the t-coordinates */
|
||||
for( v = vHead->next; v != vHead; v = v->next ) {
|
||||
v->t = - v->t;
|
||||
}
|
||||
tess->tUnit[0] = - tess->tUnit[0];
|
||||
tess->tUnit[1] = - tess->tUnit[1];
|
||||
tess->tUnit[2] = - tess->tUnit[2];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FOR_TRITE_TEST_PROGRAM
|
||||
#include <stdlib.h>
|
||||
extern int RandomSweep;
|
||||
#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
|
||||
#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
|
||||
#else
|
||||
#if defined(SLANTED_SWEEP)
|
||||
/* The "feature merging" is not intended to be complete. There are
|
||||
* special cases where edges are nearly parallel to the sweep line
|
||||
* which are not implemented. The algorithm should still behave
|
||||
* robustly (ie. produce a reasonable tesselation) in the presence
|
||||
* of such edges, however it may miss features which could have been
|
||||
* merged. We could minimize this effect by choosing the sweep line
|
||||
* direction to be something unusual (ie. not parallel to one of the
|
||||
* coordinate axes).
|
||||
*/
|
||||
#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
|
||||
#define S_UNIT_Y 0.86052074622010633
|
||||
#else
|
||||
#define S_UNIT_X 1.0
|
||||
#define S_UNIT_Y 0.0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Determine the polygon normal and project vertices onto the plane
|
||||
* of the polygon.
|
||||
*/
|
||||
void __gl_projectPolygon( GLUtesselator *tess )
|
||||
{
|
||||
GLUvertex *v, *vHead = &tess->mesh->vHead;
|
||||
GLdouble norm[3];
|
||||
GLdouble *sUnit, *tUnit;
|
||||
int i, computedNormal = FALSE;
|
||||
|
||||
norm[0] = tess->normal[0];
|
||||
norm[1] = tess->normal[1];
|
||||
norm[2] = tess->normal[2];
|
||||
if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
|
||||
ComputeNormal( tess, norm );
|
||||
computedNormal = TRUE;
|
||||
}
|
||||
sUnit = tess->sUnit;
|
||||
tUnit = tess->tUnit;
|
||||
i = LongAxis( norm );
|
||||
|
||||
#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
|
||||
/* Choose the initial sUnit vector to be approximately perpendicular
|
||||
* to the normal.
|
||||
*/
|
||||
Normalize( norm );
|
||||
|
||||
sUnit[i] = 0;
|
||||
sUnit[(i+1)%3] = S_UNIT_X;
|
||||
sUnit[(i+2)%3] = S_UNIT_Y;
|
||||
|
||||
/* Now make it exactly perpendicular */
|
||||
w = Dot( sUnit, norm );
|
||||
sUnit[0] -= w * norm[0];
|
||||
sUnit[1] -= w * norm[1];
|
||||
sUnit[2] -= w * norm[2];
|
||||
Normalize( sUnit );
|
||||
|
||||
/* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
|
||||
tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
|
||||
tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
|
||||
tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
|
||||
Normalize( tUnit );
|
||||
#else
|
||||
/* Project perpendicular to a coordinate axis -- better numerically */
|
||||
sUnit[i] = 0;
|
||||
sUnit[(i+1)%3] = S_UNIT_X;
|
||||
sUnit[(i+2)%3] = S_UNIT_Y;
|
||||
|
||||
tUnit[i] = 0;
|
||||
tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
|
||||
tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
|
||||
#endif
|
||||
|
||||
/* Project the vertices onto the sweep plane */
|
||||
for( v = vHead->next; v != vHead; v = v->next ) {
|
||||
v->s = Dot( v->coords, sUnit );
|
||||
v->t = Dot( v->coords, tUnit );
|
||||
}
|
||||
if( computedNormal ) {
|
||||
CheckOrientation( tess );
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __normal_h_
|
||||
#define __normal_h_
|
||||
|
||||
#include "tess.h"
|
||||
#include "tesselator.h"
|
||||
|
||||
/* __gl_projectPolygon( tess ) determines the polygon normal
|
||||
* and project vertices onto the plane of the polygon.
|
||||
*/
|
||||
void __gl_projectPolygon( GLUtesselator *tess );
|
||||
|
||||
#endif
|
@ -1,256 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include "priorityq-heap.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
#define INIT_SIZE 32
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifdef FOR_TRITE_TEST_PROGRAM
|
||||
#define LEQ(x,y) (*pq->leq)(x,y)
|
||||
#else
|
||||
/* Violates modularity, but a little faster */
|
||||
#include "geom.h"
|
||||
#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y)
|
||||
#endif
|
||||
|
||||
/* really __gl_pqHeapNewPriorityQ */
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
|
||||
{
|
||||
PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
|
||||
if (pq == NULL) return NULL;
|
||||
|
||||
pq->size = 0;
|
||||
pq->max = INIT_SIZE;
|
||||
pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) );
|
||||
if (pq->nodes == NULL) {
|
||||
memFree(pq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) );
|
||||
if (pq->handles == NULL) {
|
||||
memFree(pq->nodes);
|
||||
memFree(pq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pq->initialized = FALSE;
|
||||
pq->freeList = 0;
|
||||
pq->leq = leq;
|
||||
|
||||
pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */
|
||||
pq->handles[1].key = NULL;
|
||||
return pq;
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapDeletePriorityQ */
|
||||
void pqDeletePriorityQ( PriorityQ *pq )
|
||||
{
|
||||
memFree( pq->handles );
|
||||
memFree( pq->nodes );
|
||||
memFree( pq );
|
||||
}
|
||||
|
||||
|
||||
static void FloatDown( PriorityQ *pq, long curr )
|
||||
{
|
||||
PQnode *n = pq->nodes;
|
||||
PQhandleElem *h = pq->handles;
|
||||
PQhandle hCurr, hChild;
|
||||
long child;
|
||||
|
||||
hCurr = n[curr].handle;
|
||||
for( ;; ) {
|
||||
child = curr << 1;
|
||||
if( child < pq->size && LEQ( h[n[child+1].handle].key,
|
||||
h[n[child].handle].key )) {
|
||||
++child;
|
||||
}
|
||||
|
||||
assert(child <= pq->max);
|
||||
|
||||
hChild = n[child].handle;
|
||||
if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
|
||||
n[curr].handle = hCurr;
|
||||
h[hCurr].node = curr;
|
||||
break;
|
||||
}
|
||||
n[curr].handle = hChild;
|
||||
h[hChild].node = curr;
|
||||
curr = child;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void FloatUp( PriorityQ *pq, long curr )
|
||||
{
|
||||
PQnode *n = pq->nodes;
|
||||
PQhandleElem *h = pq->handles;
|
||||
PQhandle hCurr, hParent;
|
||||
long parent;
|
||||
|
||||
hCurr = n[curr].handle;
|
||||
for( ;; ) {
|
||||
parent = curr >> 1;
|
||||
hParent = n[parent].handle;
|
||||
if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
|
||||
n[curr].handle = hCurr;
|
||||
h[hCurr].node = curr;
|
||||
break;
|
||||
}
|
||||
n[curr].handle = hParent;
|
||||
h[hParent].node = curr;
|
||||
curr = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapInit */
|
||||
void pqInit( PriorityQ *pq )
|
||||
{
|
||||
long i;
|
||||
|
||||
/* This method of building a heap is O(n), rather than O(n lg n). */
|
||||
|
||||
for( i = pq->size; i >= 1; --i ) {
|
||||
FloatDown( pq, i );
|
||||
}
|
||||
pq->initialized = TRUE;
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapInsert */
|
||||
/* returns LONG_MAX iff out of memory */
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
|
||||
{
|
||||
long curr;
|
||||
PQhandle free_handle;
|
||||
|
||||
curr = ++ pq->size;
|
||||
if( (curr*2) > pq->max ) {
|
||||
PQnode *saveNodes= pq->nodes;
|
||||
PQhandleElem *saveHandles= pq->handles;
|
||||
|
||||
/* If the heap overflows, double its size. */
|
||||
pq->max <<= 1;
|
||||
pq->nodes = (PQnode *)memRealloc( pq->nodes,
|
||||
(size_t)
|
||||
((pq->max + 1) * sizeof( pq->nodes[0] )));
|
||||
if (pq->nodes == NULL) {
|
||||
pq->nodes = saveNodes; /* restore ptr to free upon return */
|
||||
return LONG_MAX;
|
||||
}
|
||||
pq->handles = (PQhandleElem *)memRealloc( pq->handles,
|
||||
(size_t)
|
||||
((pq->max + 1) *
|
||||
sizeof( pq->handles[0] )));
|
||||
if (pq->handles == NULL) {
|
||||
pq->handles = saveHandles; /* restore ptr to free upon return */
|
||||
return LONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
if( pq->freeList == 0 ) {
|
||||
free_handle = curr;
|
||||
} else {
|
||||
free_handle = pq->freeList;
|
||||
pq->freeList = pq->handles[free_handle].node;
|
||||
}
|
||||
|
||||
pq->nodes[curr].handle = free_handle;
|
||||
pq->handles[free_handle].node = curr;
|
||||
pq->handles[free_handle].key = keyNew;
|
||||
|
||||
if( pq->initialized ) {
|
||||
FloatUp( pq, curr );
|
||||
}
|
||||
assert(free_handle != LONG_MAX);
|
||||
return free_handle;
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapExtractMin */
|
||||
PQkey pqExtractMin( PriorityQ *pq )
|
||||
{
|
||||
PQnode *n = pq->nodes;
|
||||
PQhandleElem *h = pq->handles;
|
||||
PQhandle hMin = n[1].handle;
|
||||
PQkey min = h[hMin].key;
|
||||
|
||||
if( pq->size > 0 ) {
|
||||
n[1].handle = n[pq->size].handle;
|
||||
h[n[1].handle].node = 1;
|
||||
|
||||
h[hMin].key = NULL;
|
||||
h[hMin].node = pq->freeList;
|
||||
pq->freeList = hMin;
|
||||
|
||||
if( -- pq->size > 0 ) {
|
||||
FloatDown( pq, 1 );
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapDelete */
|
||||
void pqDelete( PriorityQ *pq, PQhandle hCurr )
|
||||
{
|
||||
PQnode *n = pq->nodes;
|
||||
PQhandleElem *h = pq->handles;
|
||||
long curr;
|
||||
|
||||
assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
|
||||
|
||||
curr = h[hCurr].node;
|
||||
n[curr].handle = n[pq->size].handle;
|
||||
h[n[curr].handle].node = curr;
|
||||
|
||||
if( curr <= -- pq->size ) {
|
||||
if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
|
||||
FloatDown( pq, curr );
|
||||
} else {
|
||||
FloatUp( pq, curr );
|
||||
}
|
||||
}
|
||||
h[hCurr].key = NULL;
|
||||
h[hCurr].node = pq->freeList;
|
||||
pq->freeList = hCurr;
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __priorityq_heap_h_
|
||||
#define __priorityq_heap_h_
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define PQkey PQHeapKey
|
||||
#define PQhandle PQHeapHandle
|
||||
#define PriorityQ PriorityQHeap
|
||||
|
||||
#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq)
|
||||
#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq)
|
||||
|
||||
/* The basic operations are insertion of a new key (pqInsert),
|
||||
* and examination/extraction of a key whose value is minimum
|
||||
* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
|
||||
* for this purpose pqInsert returns a "handle" which is supplied
|
||||
* as the argument.
|
||||
*
|
||||
* An initial heap may be created efficiently by calling pqInsert
|
||||
* repeatedly, then calling pqInit. In any case pqInit must be called
|
||||
* before any operations other than pqInsert are used.
|
||||
*
|
||||
* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
|
||||
* This may also be tested with pqIsEmpty.
|
||||
*/
|
||||
#define pqInit(pq) __gl_pqHeapInit(pq)
|
||||
#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key)
|
||||
#define pqMinimum(pq) __gl_pqHeapMinimum(pq)
|
||||
#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq)
|
||||
#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle)
|
||||
#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq)
|
||||
|
||||
|
||||
/* Since we support deletion the data structure is a little more
|
||||
* complicated than an ordinary heap. "nodes" is the heap itself;
|
||||
* active nodes are stored in the range 1..pq->size. When the
|
||||
* heap exceeds its allocated size (pq->max), its size doubles.
|
||||
* The children of node i are nodes 2i and 2i+1.
|
||||
*
|
||||
* Each node stores an index into an array "handles". Each handle
|
||||
* stores a key, plus a pointer back to the node which currently
|
||||
* represents that key (ie. nodes[handles[i].node].handle == i).
|
||||
*/
|
||||
|
||||
typedef void *PQkey;
|
||||
typedef long PQhandle;
|
||||
typedef struct PriorityQ PriorityQ;
|
||||
|
||||
typedef struct { PQhandle handle; } PQnode;
|
||||
typedef struct { PQkey key; PQhandle node; } PQhandleElem;
|
||||
|
||||
struct PriorityQ {
|
||||
PQnode *nodes;
|
||||
PQhandleElem *handles;
|
||||
long size, max;
|
||||
PQhandle freeList;
|
||||
int initialized;
|
||||
int (*leq)(PQkey key1, PQkey key2);
|
||||
};
|
||||
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
|
||||
void pqDeletePriorityQ( PriorityQ *pq );
|
||||
|
||||
void pqInit( PriorityQ *pq );
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey key );
|
||||
PQkey pqExtractMin( PriorityQ *pq );
|
||||
void pqDelete( PriorityQ *pq, PQhandle handle );
|
||||
|
||||
|
||||
#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key)
|
||||
#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0)
|
||||
|
||||
#endif
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __priorityq_sort_h_
|
||||
#define __priorityq_sort_h_
|
||||
|
||||
#include "priorityq-heap.h"
|
||||
|
||||
#undef PQkey
|
||||
#undef PQhandle
|
||||
#undef PriorityQ
|
||||
#undef pqNewPriorityQ
|
||||
#undef pqDeletePriorityQ
|
||||
#undef pqInit
|
||||
#undef pqInsert
|
||||
#undef pqMinimum
|
||||
#undef pqExtractMin
|
||||
#undef pqDelete
|
||||
#undef pqIsEmpty
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define PQkey PQSortKey
|
||||
#define PQhandle PQSortHandle
|
||||
#define PriorityQ PriorityQSort
|
||||
|
||||
#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
|
||||
#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
|
||||
|
||||
/* The basic operations are insertion of a new key (pqInsert),
|
||||
* and examination/extraction of a key whose value is minimum
|
||||
* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
|
||||
* for this purpose pqInsert returns a "handle" which is supplied
|
||||
* as the argument.
|
||||
*
|
||||
* An initial heap may be created efficiently by calling pqInsert
|
||||
* repeatedly, then calling pqInit. In any case pqInit must be called
|
||||
* before any operations other than pqInsert are used.
|
||||
*
|
||||
* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
|
||||
* This may also be tested with pqIsEmpty.
|
||||
*/
|
||||
#define pqInit(pq) __gl_pqSortInit(pq)
|
||||
#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
|
||||
#define pqMinimum(pq) __gl_pqSortMinimum(pq)
|
||||
#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
|
||||
#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
|
||||
#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
|
||||
|
||||
|
||||
/* Since we support deletion the data structure is a little more
|
||||
* complicated than an ordinary heap. "nodes" is the heap itself;
|
||||
* active nodes are stored in the range 1..pq->size. When the
|
||||
* heap exceeds its allocated size (pq->max), its size doubles.
|
||||
* The children of node i are nodes 2i and 2i+1.
|
||||
*
|
||||
* Each node stores an index into an array "handles". Each handle
|
||||
* stores a key, plus a pointer back to the node which currently
|
||||
* represents that key (ie. nodes[handles[i].node].handle == i).
|
||||
*/
|
||||
|
||||
typedef PQHeapKey PQkey;
|
||||
typedef PQHeapHandle PQhandle;
|
||||
typedef struct PriorityQ PriorityQ;
|
||||
|
||||
struct PriorityQ {
|
||||
PriorityQHeap *heap;
|
||||
PQkey *keys;
|
||||
PQkey **order;
|
||||
PQhandle size, max;
|
||||
int initialized;
|
||||
int (*leq)(PQkey key1, PQkey key2);
|
||||
};
|
||||
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
|
||||
void pqDeletePriorityQ( PriorityQ *pq );
|
||||
|
||||
int pqInit( PriorityQ *pq );
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey key );
|
||||
PQkey pqExtractMin( PriorityQ *pq );
|
||||
void pqDelete( PriorityQ *pq, PQhandle handle );
|
||||
|
||||
PQkey pqMinimum( PriorityQ *pq );
|
||||
int pqIsEmpty( PriorityQ *pq );
|
||||
|
||||
#endif
|
@ -1,261 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h> /* LONG_MAX */
|
||||
#include "memalloc.h"
|
||||
|
||||
/* Include all the code for the regular heap-based queue here. */
|
||||
|
||||
#include "priorityq-heap.c"
|
||||
|
||||
/* Now redefine all the function names to map to their "Sort" versions. */
|
||||
|
||||
#include "priorityq-sort.h"
|
||||
|
||||
/* really __gl_pqSortNewPriorityQ */
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
|
||||
{
|
||||
PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
|
||||
if (pq == NULL) return NULL;
|
||||
|
||||
pq->heap = __gl_pqHeapNewPriorityQ( leq );
|
||||
if (pq->heap == NULL) {
|
||||
memFree(pq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) );
|
||||
if (pq->keys == NULL) {
|
||||
__gl_pqHeapDeletePriorityQ(pq->heap);
|
||||
memFree(pq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pq->order = NULL;
|
||||
pq->size = 0;
|
||||
pq->max = INIT_SIZE;
|
||||
pq->initialized = FALSE;
|
||||
pq->leq = leq;
|
||||
return pq;
|
||||
}
|
||||
|
||||
/* really __gl_pqSortDeletePriorityQ */
|
||||
void pqDeletePriorityQ( PriorityQ *pq )
|
||||
{
|
||||
assert(pq != NULL);
|
||||
if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
|
||||
if (pq->order != NULL) memFree( pq->order );
|
||||
if (pq->keys != NULL) memFree( pq->keys );
|
||||
memFree( pq );
|
||||
}
|
||||
|
||||
|
||||
#define LT(x,y) (! LEQ(y,x))
|
||||
#define GT(x,y) (! LEQ(x,y))
|
||||
#define Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0)
|
||||
|
||||
/* really __gl_pqSortInit */
|
||||
int pqInit( PriorityQ *pq )
|
||||
{
|
||||
PQkey **p, **r, **i, **j, *piv;
|
||||
struct { PQkey **p, **r; } Stack[50], *top = Stack;
|
||||
unsigned long seed = 2016473283;
|
||||
|
||||
/* Create an array of indirect pointers to the keys, so that we
|
||||
* the handles we have returned are still valid.
|
||||
*/
|
||||
/*
|
||||
pq->order = (PQHeapKey **)memAlloc( (size_t)
|
||||
(pq->size * sizeof(pq->order[0])) );
|
||||
*/
|
||||
pq->order = (PQHeapKey **)memAlloc( (size_t)
|
||||
((pq->size+1) * sizeof(pq->order[0])) );
|
||||
/* the previous line is a patch to compensate for the fact that IBM */
|
||||
/* machines return a null on a malloc of zero bytes (unlike SGI), */
|
||||
/* so we have to put in this defense to guard against a memory */
|
||||
/* fault four lines down. from fossum@austin.ibm.com. */
|
||||
if (pq->order == NULL) return 0;
|
||||
|
||||
p = pq->order;
|
||||
r = p + pq->size - 1;
|
||||
for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
|
||||
*i = piv;
|
||||
}
|
||||
|
||||
/* Sort the indirect pointers in descending order,
|
||||
* using randomized Quicksort
|
||||
*/
|
||||
top->p = p; top->r = r; ++top;
|
||||
while( --top >= Stack ) {
|
||||
p = top->p;
|
||||
r = top->r;
|
||||
while( r > p + 10 ) {
|
||||
seed = seed * 1539415821 + 1;
|
||||
i = p + seed % (r - p + 1);
|
||||
piv = *i;
|
||||
*i = *p;
|
||||
*p = piv;
|
||||
i = p - 1;
|
||||
j = r + 1;
|
||||
do {
|
||||
do { ++i; } while( GT( **i, *piv ));
|
||||
do { --j; } while( LT( **j, *piv ));
|
||||
Swap( i, j );
|
||||
} while( i < j );
|
||||
Swap( i, j ); /* Undo last swap */
|
||||
if( i - p < r - j ) {
|
||||
top->p = j+1; top->r = r; ++top;
|
||||
r = i-1;
|
||||
} else {
|
||||
top->p = p; top->r = i-1; ++top;
|
||||
p = j+1;
|
||||
}
|
||||
}
|
||||
/* Insertion sort small lists */
|
||||
for( i = p+1; i <= r; ++i ) {
|
||||
piv = *i;
|
||||
for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
|
||||
*j = *(j-1);
|
||||
}
|
||||
*j = piv;
|
||||
}
|
||||
}
|
||||
pq->max = pq->size;
|
||||
pq->initialized = TRUE;
|
||||
__gl_pqHeapInit( pq->heap ); /* always succeeds */
|
||||
|
||||
#ifndef NDEBUG
|
||||
p = pq->order;
|
||||
r = p + pq->size - 1;
|
||||
for( i = p; i < r; ++i ) {
|
||||
assert( LEQ( **(i+1), **i ));
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* really __gl_pqSortInsert */
|
||||
/* returns LONG_MAX iff out of memory */
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
|
||||
{
|
||||
long curr;
|
||||
|
||||
if( pq->initialized ) {
|
||||
return __gl_pqHeapInsert( pq->heap, keyNew );
|
||||
}
|
||||
curr = pq->size;
|
||||
if( ++ pq->size >= pq->max ) {
|
||||
PQkey *saveKey= pq->keys;
|
||||
|
||||
/* If the heap overflows, double its size. */
|
||||
pq->max <<= 1;
|
||||
pq->keys = (PQHeapKey *)memRealloc( pq->keys,
|
||||
(size_t)
|
||||
(pq->max * sizeof( pq->keys[0] )));
|
||||
if (pq->keys == NULL) {
|
||||
pq->keys = saveKey; /* restore ptr to free upon return */
|
||||
return LONG_MAX;
|
||||
}
|
||||
}
|
||||
assert(curr != LONG_MAX);
|
||||
pq->keys[curr] = keyNew;
|
||||
|
||||
/* Negative handles index the sorted array. */
|
||||
return -(curr+1);
|
||||
}
|
||||
|
||||
/* really __gl_pqSortExtractMin */
|
||||
PQkey pqExtractMin( PriorityQ *pq )
|
||||
{
|
||||
PQkey sortMin, heapMin;
|
||||
|
||||
if( pq->size == 0 ) {
|
||||
return __gl_pqHeapExtractMin( pq->heap );
|
||||
}
|
||||
sortMin = *(pq->order[pq->size-1]);
|
||||
if( ! __gl_pqHeapIsEmpty( pq->heap )) {
|
||||
heapMin = __gl_pqHeapMinimum( pq->heap );
|
||||
if( LEQ( heapMin, sortMin )) {
|
||||
return __gl_pqHeapExtractMin( pq->heap );
|
||||
}
|
||||
}
|
||||
do {
|
||||
-- pq->size;
|
||||
} while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
|
||||
return sortMin;
|
||||
}
|
||||
|
||||
/* really __gl_pqSortMinimum */
|
||||
PQkey pqMinimum( PriorityQ *pq )
|
||||
{
|
||||
PQkey sortMin, heapMin;
|
||||
|
||||
if( pq->size == 0 ) {
|
||||
return __gl_pqHeapMinimum( pq->heap );
|
||||
}
|
||||
sortMin = *(pq->order[pq->size-1]);
|
||||
if( ! __gl_pqHeapIsEmpty( pq->heap )) {
|
||||
heapMin = __gl_pqHeapMinimum( pq->heap );
|
||||
if( LEQ( heapMin, sortMin )) {
|
||||
return heapMin;
|
||||
}
|
||||
}
|
||||
return sortMin;
|
||||
}
|
||||
|
||||
/* really __gl_pqSortIsEmpty */
|
||||
int pqIsEmpty( PriorityQ *pq )
|
||||
{
|
||||
return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
|
||||
}
|
||||
|
||||
/* really __gl_pqSortDelete */
|
||||
void pqDelete( PriorityQ *pq, PQhandle curr )
|
||||
{
|
||||
if( curr >= 0 ) {
|
||||
__gl_pqHeapDelete( pq->heap, curr );
|
||||
return;
|
||||
}
|
||||
curr = -(curr+1);
|
||||
assert( curr < pq->max && pq->keys[curr] != NULL );
|
||||
|
||||
pq->keys[curr] = NULL;
|
||||
while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
|
||||
-- pq->size;
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __priorityq_sort_h_
|
||||
#define __priorityq_sort_h_
|
||||
|
||||
#include "priorityq-heap.h"
|
||||
|
||||
#undef PQkey
|
||||
#undef PQhandle
|
||||
#undef PriorityQ
|
||||
#undef pqNewPriorityQ
|
||||
#undef pqDeletePriorityQ
|
||||
#undef pqInit
|
||||
#undef pqInsert
|
||||
#undef pqMinimum
|
||||
#undef pqExtractMin
|
||||
#undef pqDelete
|
||||
#undef pqIsEmpty
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define PQkey PQSortKey
|
||||
#define PQhandle PQSortHandle
|
||||
#define PriorityQ PriorityQSort
|
||||
|
||||
#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
|
||||
#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
|
||||
|
||||
/* The basic operations are insertion of a new key (pqInsert),
|
||||
* and examination/extraction of a key whose value is minimum
|
||||
* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
|
||||
* for this purpose pqInsert returns a "handle" which is supplied
|
||||
* as the argument.
|
||||
*
|
||||
* An initial heap may be created efficiently by calling pqInsert
|
||||
* repeatedly, then calling pqInit. In any case pqInit must be called
|
||||
* before any operations other than pqInsert are used.
|
||||
*
|
||||
* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
|
||||
* This may also be tested with pqIsEmpty.
|
||||
*/
|
||||
#define pqInit(pq) __gl_pqSortInit(pq)
|
||||
#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
|
||||
#define pqMinimum(pq) __gl_pqSortMinimum(pq)
|
||||
#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
|
||||
#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
|
||||
#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
|
||||
|
||||
|
||||
/* Since we support deletion the data structure is a little more
|
||||
* complicated than an ordinary heap. "nodes" is the heap itself;
|
||||
* active nodes are stored in the range 1..pq->size. When the
|
||||
* heap exceeds its allocated size (pq->max), its size doubles.
|
||||
* The children of node i are nodes 2i and 2i+1.
|
||||
*
|
||||
* Each node stores an index into an array "handles". Each handle
|
||||
* stores a key, plus a pointer back to the node which currently
|
||||
* represents that key (ie. nodes[handles[i].node].handle == i).
|
||||
*/
|
||||
|
||||
typedef PQHeapKey PQkey;
|
||||
typedef PQHeapHandle PQhandle;
|
||||
typedef struct PriorityQ PriorityQ;
|
||||
|
||||
struct PriorityQ {
|
||||
PriorityQHeap *heap;
|
||||
PQkey *keys;
|
||||
PQkey **order;
|
||||
PQhandle size, max;
|
||||
int initialized;
|
||||
int (*leq)(PQkey key1, PQkey key2);
|
||||
};
|
||||
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
|
||||
void pqDeletePriorityQ( PriorityQ *pq );
|
||||
|
||||
int pqInit( PriorityQ *pq );
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey key );
|
||||
PQkey pqExtractMin( PriorityQ *pq );
|
||||
void pqDelete( PriorityQ *pq, PQhandle handle );
|
||||
|
||||
PQkey pqMinimum( PriorityQ *pq );
|
||||
int pqIsEmpty( PriorityQ *pq );
|
||||
|
||||
#endif
|
@ -1,502 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include "mesh.h"
|
||||
#include "tess.h"
|
||||
#include "render.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* This structure remembers the information we need about a primitive
|
||||
* to be able to render it later, once we have determined which
|
||||
* primitive is able to use the most triangles.
|
||||
*/
|
||||
struct FaceCount {
|
||||
long size; /* number of triangles used */
|
||||
GLUhalfEdge *eStart; /* edge where this primitive starts */
|
||||
void (*render)(GLUtesselator *, GLUhalfEdge *, long);
|
||||
/* routine to render this primitive */
|
||||
};
|
||||
|
||||
static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
|
||||
static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
|
||||
|
||||
static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
|
||||
static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
|
||||
static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
|
||||
long size );
|
||||
|
||||
static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
|
||||
static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
|
||||
|
||||
|
||||
|
||||
/************************ Strips and Fans decomposition ******************/
|
||||
|
||||
/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
|
||||
* fans, strips, and separate triangles. A substantial effort is made
|
||||
* to use as few rendering primitives as possible (ie. to make the fans
|
||||
* and strips as large as possible).
|
||||
*
|
||||
* The rendering output is provided as callbacks (see the api).
|
||||
*/
|
||||
void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f;
|
||||
|
||||
/* Make a list of separate triangles so we can render them all at once */
|
||||
tess->lonelyTriList = NULL;
|
||||
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
|
||||
f->marked = FALSE;
|
||||
}
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
|
||||
|
||||
/* We examine all faces in an arbitrary order. Whenever we find
|
||||
* an unprocessed face F, we output a group of faces including F
|
||||
* whose size is maximum.
|
||||
*/
|
||||
if( f->inside && ! f->marked ) {
|
||||
RenderMaximumFaceGroup( tess, f );
|
||||
assert( f->marked );
|
||||
}
|
||||
}
|
||||
if( tess->lonelyTriList != NULL ) {
|
||||
RenderLonelyTriangles( tess, tess->lonelyTriList );
|
||||
tess->lonelyTriList = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
|
||||
{
|
||||
/* We want to find the largest triangle fan or strip of unmarked faces
|
||||
* which includes the given face fOrig. There are 3 possible fans
|
||||
* passing through fOrig (one centered at each vertex), and 3 possible
|
||||
* strips (one for each CCW permutation of the vertices). Our strategy
|
||||
* is to try all of these, and take the primitive which uses the most
|
||||
* triangles (a greedy approach).
|
||||
*/
|
||||
GLUhalfEdge *e = fOrig->anEdge;
|
||||
struct FaceCount max, newFace;
|
||||
|
||||
max.size = 1;
|
||||
max.eStart = e;
|
||||
max.render = &RenderTriangle;
|
||||
|
||||
if( ! tess->flagBoundary ) {
|
||||
newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
|
||||
newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
|
||||
newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
|
||||
|
||||
newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
|
||||
newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
|
||||
newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
|
||||
}
|
||||
(*(max.render))( tess, max.eStart, max.size );
|
||||
}
|
||||
|
||||
|
||||
/* Macros which keep track of faces we have marked temporarily, and allow
|
||||
* us to backtrack when necessary. With triangle fans, this is not
|
||||
* really necessary, since the only awkward case is a loop of triangles
|
||||
* around a single origin vertex. However with strips the situation is
|
||||
* more complicated, and we need a general tracking method like the
|
||||
* one here.
|
||||
*/
|
||||
#define Marked(f) (! (f)->inside || (f)->marked)
|
||||
|
||||
#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
|
||||
|
||||
#define FreeTrail(t) do { \
|
||||
while( (t) != NULL ) { \
|
||||
(t)->marked = FALSE; t = (t)->trail; \
|
||||
} \
|
||||
} while(0) /* absorb trailing semicolon */
|
||||
|
||||
|
||||
|
||||
static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
|
||||
{
|
||||
/* eOrig->Lface is the face we want to render. We want to find the size
|
||||
* of a maximal fan around eOrig->Org. To do this we just walk around
|
||||
* the origin vertex as far as possible in both directions.
|
||||
*/
|
||||
struct FaceCount newFace = { 0, NULL, &RenderFan };
|
||||
GLUface *trail = NULL;
|
||||
GLUhalfEdge *e;
|
||||
|
||||
for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
|
||||
AddToTrail( e->Lface, trail );
|
||||
++newFace.size;
|
||||
}
|
||||
for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
|
||||
AddToTrail( e->Rface, trail );
|
||||
++newFace.size;
|
||||
}
|
||||
newFace.eStart = e;
|
||||
/*LINTED*/
|
||||
FreeTrail( trail );
|
||||
return newFace;
|
||||
}
|
||||
|
||||
|
||||
#define IsEven(n) (((n) & 1) == 0)
|
||||
|
||||
static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
|
||||
{
|
||||
/* Here we are looking for a maximal strip that contains the vertices
|
||||
* eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
|
||||
* reverse, such that all triangles are oriented CCW).
|
||||
*
|
||||
* Again we walk forward and backward as far as possible. However for
|
||||
* strips there is a twist: to get CCW orientations, there must be
|
||||
* an *even* number of triangles in the strip on one side of eOrig.
|
||||
* We walk the strip starting on a side with an even number of triangles;
|
||||
* if both side have an odd number, we are forced to shorten one side.
|
||||
*/
|
||||
struct FaceCount newFace = { 0, NULL, &RenderStrip };
|
||||
long headSize = 0, tailSize = 0;
|
||||
GLUface *trail = NULL;
|
||||
GLUhalfEdge *e, *eTail, *eHead;
|
||||
|
||||
for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
|
||||
AddToTrail( e->Lface, trail );
|
||||
++tailSize;
|
||||
e = e->Dprev;
|
||||
if( Marked( e->Lface )) break;
|
||||
AddToTrail( e->Lface, trail );
|
||||
}
|
||||
eTail = e;
|
||||
|
||||
for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
|
||||
AddToTrail( e->Rface, trail );
|
||||
++headSize;
|
||||
e = e->Oprev;
|
||||
if( Marked( e->Rface )) break;
|
||||
AddToTrail( e->Rface, trail );
|
||||
}
|
||||
eHead = e;
|
||||
|
||||
newFace.size = tailSize + headSize;
|
||||
if( IsEven( tailSize )) {
|
||||
newFace.eStart = eTail->Sym;
|
||||
} else if( IsEven( headSize )) {
|
||||
newFace.eStart = eHead;
|
||||
} else {
|
||||
/* Both sides have odd length, we must shorten one of them. In fact,
|
||||
* we must start from eHead to guarantee inclusion of eOrig->Lface.
|
||||
*/
|
||||
--newFace.size;
|
||||
newFace.eStart = eHead->Onext;
|
||||
}
|
||||
/*LINTED*/
|
||||
FreeTrail( trail );
|
||||
return newFace;
|
||||
}
|
||||
|
||||
|
||||
static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
|
||||
{
|
||||
/* Just add the triangle to a triangle list, so we can render all
|
||||
* the separate triangles at once.
|
||||
*/
|
||||
assert( size == 1 );
|
||||
AddToTrail( e->Lface, tess->lonelyTriList );
|
||||
}
|
||||
|
||||
|
||||
static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
|
||||
{
|
||||
/* Now we render all the separate triangles which could not be
|
||||
* grouped into a triangle fan or strip.
|
||||
*/
|
||||
GLUhalfEdge *e;
|
||||
int newState;
|
||||
int edgeState = -1; /* force edge state output for first vertex */
|
||||
|
||||
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
|
||||
|
||||
for( ; f != NULL; f = f->trail ) {
|
||||
/* Loop once for each edge (there will always be 3 edges) */
|
||||
|
||||
e = f->anEdge;
|
||||
do {
|
||||
if( tess->flagBoundary ) {
|
||||
/* Set the "edge state" to TRUE just before we output the
|
||||
* first vertex of each edge on the polygon boundary.
|
||||
*/
|
||||
newState = ! e->Rface->inside;
|
||||
if( edgeState != newState ) {
|
||||
edgeState = newState;
|
||||
CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
|
||||
}
|
||||
}
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
|
||||
e = e->Lnext;
|
||||
} while( e != f->anEdge );
|
||||
}
|
||||
CALL_END_OR_END_DATA();
|
||||
}
|
||||
|
||||
|
||||
static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
|
||||
{
|
||||
/* Render as many CCW triangles as possible in a fan starting from
|
||||
* edge "e". The fan *should* contain exactly "size" triangles
|
||||
* (otherwise we've goofed up somewhere).
|
||||
*/
|
||||
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
|
||||
|
||||
while( ! Marked( e->Lface )) {
|
||||
e->Lface->marked = TRUE;
|
||||
--size;
|
||||
e = e->Onext;
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
|
||||
}
|
||||
|
||||
assert( size == 0 );
|
||||
CALL_END_OR_END_DATA();
|
||||
}
|
||||
|
||||
|
||||
static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
|
||||
{
|
||||
/* Render as many CCW triangles as possible in a strip starting from
|
||||
* edge "e". The strip *should* contain exactly "size" triangles
|
||||
* (otherwise we've goofed up somewhere).
|
||||
*/
|
||||
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
|
||||
|
||||
while( ! Marked( e->Lface )) {
|
||||
e->Lface->marked = TRUE;
|
||||
--size;
|
||||
e = e->Dprev;
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
if( Marked( e->Lface )) break;
|
||||
|
||||
e->Lface->marked = TRUE;
|
||||
--size;
|
||||
e = e->Onext;
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
|
||||
}
|
||||
|
||||
assert( size == 0 );
|
||||
CALL_END_OR_END_DATA();
|
||||
}
|
||||
|
||||
|
||||
/************************ Boundary contour decomposition ******************/
|
||||
|
||||
/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
|
||||
* contour for each face marked "inside". The rendering output is
|
||||
* provided as callbacks (see the api).
|
||||
*/
|
||||
void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f;
|
||||
GLUhalfEdge *e;
|
||||
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
|
||||
if( f->inside ) {
|
||||
CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
|
||||
e = f->anEdge;
|
||||
do {
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
e = e->Lnext;
|
||||
} while( e != f->anEdge );
|
||||
CALL_END_OR_END_DATA();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************ Quick-and-dirty decomposition ******************/
|
||||
|
||||
#define SIGN_INCONSISTENT 2
|
||||
|
||||
static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
|
||||
/*
|
||||
* If check==FALSE, we compute the polygon normal and place it in norm[].
|
||||
* If check==TRUE, we check that each triangle in the fan from v0 has a
|
||||
* consistent orientation with respect to norm[]. If triangles are
|
||||
* consistently oriented CCW, return 1; if CW, return -1; if all triangles
|
||||
* are degenerate return 0; otherwise (no consistent orientation) return
|
||||
* SIGN_INCONSISTENT.
|
||||
*/
|
||||
{
|
||||
CachedVertex *v0 = tess->cache;
|
||||
CachedVertex *vn = v0 + tess->cacheCount;
|
||||
CachedVertex *vc;
|
||||
GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
|
||||
int sign = 0;
|
||||
|
||||
/* Find the polygon normal. It is important to get a reasonable
|
||||
* normal even when the polygon is self-intersecting (eg. a bowtie).
|
||||
* Otherwise, the computed normal could be very tiny, but perpendicular
|
||||
* to the true plane of the polygon due to numerical noise. Then all
|
||||
* the triangles would appear to be degenerate and we would incorrectly
|
||||
* decompose the polygon as a fan (or simply not render it at all).
|
||||
*
|
||||
* We use a sum-of-triangles normal algorithm rather than the more
|
||||
* efficient sum-of-trapezoids method (used in CheckOrientation()
|
||||
* in normal.c). This lets us explicitly reverse the signed area
|
||||
* of some triangles to get a reasonable normal in the self-intersecting
|
||||
* case.
|
||||
*/
|
||||
if( ! check ) {
|
||||
norm[0] = norm[1] = norm[2] = 0.0;
|
||||
}
|
||||
|
||||
vc = v0 + 1;
|
||||
xc = vc->coords[0] - v0->coords[0];
|
||||
yc = vc->coords[1] - v0->coords[1];
|
||||
zc = vc->coords[2] - v0->coords[2];
|
||||
while( ++vc < vn ) {
|
||||
xp = xc; yp = yc; zp = zc;
|
||||
xc = vc->coords[0] - v0->coords[0];
|
||||
yc = vc->coords[1] - v0->coords[1];
|
||||
zc = vc->coords[2] - v0->coords[2];
|
||||
|
||||
/* Compute (vp - v0) cross (vc - v0) */
|
||||
n[0] = yp*zc - zp*yc;
|
||||
n[1] = zp*xc - xp*zc;
|
||||
n[2] = xp*yc - yp*xc;
|
||||
|
||||
dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
|
||||
if( ! check ) {
|
||||
/* Reverse the contribution of back-facing triangles to get
|
||||
* a reasonable normal for self-intersecting polygons (see above)
|
||||
*/
|
||||
if( dot >= 0 ) {
|
||||
norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
|
||||
} else {
|
||||
norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
|
||||
}
|
||||
} else if( dot != 0 ) {
|
||||
/* Check the new orientation for consistency with previous triangles */
|
||||
if( dot > 0 ) {
|
||||
if( sign < 0 ) return SIGN_INCONSISTENT;
|
||||
sign = 1;
|
||||
} else {
|
||||
if( sign > 0 ) return SIGN_INCONSISTENT;
|
||||
sign = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sign;
|
||||
}
|
||||
|
||||
/* __gl_renderCache( tess ) takes a single contour and tries to render it
|
||||
* as a triangle fan. This handles convex polygons, as well as some
|
||||
* non-convex polygons if we get lucky.
|
||||
*
|
||||
* Returns TRUE if the polygon was successfully rendered. The rendering
|
||||
* output is provided as callbacks (see the api).
|
||||
*/
|
||||
GLboolean __gl_renderCache( GLUtesselator *tess )
|
||||
{
|
||||
CachedVertex *v0 = tess->cache;
|
||||
CachedVertex *vn = v0 + tess->cacheCount;
|
||||
CachedVertex *vc;
|
||||
GLdouble norm[3];
|
||||
int sign;
|
||||
|
||||
if( tess->cacheCount < 3 ) {
|
||||
/* Degenerate contour -- no output */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
norm[0] = tess->normal[0];
|
||||
norm[1] = tess->normal[1];
|
||||
norm[2] = tess->normal[2];
|
||||
if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
|
||||
ComputeNormal( tess, norm, FALSE );
|
||||
}
|
||||
|
||||
sign = ComputeNormal( tess, norm, TRUE );
|
||||
if( sign == SIGN_INCONSISTENT ) {
|
||||
/* Fan triangles did not have a consistent orientation */
|
||||
return FALSE;
|
||||
}
|
||||
if( sign == 0 ) {
|
||||
/* All triangles were degenerate */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Make sure we do the right thing for each winding rule */
|
||||
switch( tess->windingRule ) {
|
||||
case GLU_TESS_WINDING_ODD:
|
||||
case GLU_TESS_WINDING_NONZERO:
|
||||
break;
|
||||
case GLU_TESS_WINDING_POSITIVE:
|
||||
if( sign < 0 ) return TRUE;
|
||||
break;
|
||||
case GLU_TESS_WINDING_NEGATIVE:
|
||||
if( sign > 0 ) return TRUE;
|
||||
break;
|
||||
case GLU_TESS_WINDING_ABS_GEQ_TWO:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
|
||||
: (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
|
||||
: GL_TRIANGLES );
|
||||
|
||||
CALL_VERTEX_OR_VERTEX_DATA( v0->data );
|
||||
if( sign > 0 ) {
|
||||
for( vc = v0+1; vc < vn; ++vc ) {
|
||||
CALL_VERTEX_OR_VERTEX_DATA( vc->data );
|
||||
}
|
||||
} else {
|
||||
for( vc = vn-1; vc > v0; --vc ) {
|
||||
CALL_VERTEX_OR_VERTEX_DATA( vc->data );
|
||||
}
|
||||
}
|
||||
CALL_END_OR_END_DATA();
|
||||
return TRUE;
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __render_h_
|
||||
#define __render_h_
|
||||
|
||||
#include "mesh.h"
|
||||
#include "tesselator.h"
|
||||
|
||||
/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
|
||||
* fans, strips, and separate triangles. A substantial effort is made
|
||||
* to use as few rendering primitives as possible (ie. to make the fans
|
||||
* and strips as large as possible).
|
||||
*
|
||||
* The rendering output is provided as callbacks (see the api).
|
||||
*/
|
||||
void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
|
||||
void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
|
||||
|
||||
GLboolean __gl_renderCache( GLUtesselator *tess );
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __sweep_h_
|
||||
#define __sweep_h_
|
||||
|
||||
#include "mesh.h"
|
||||
#include "tesselator.h"
|
||||
|
||||
/* __gl_computeInterior( tess ) computes the planar arrangement specified
|
||||
* by the given contours, and further subdivides this arrangement
|
||||
* into regions. Each region is marked "inside" if it belongs
|
||||
* to the polygon, according to the rule given by tess->windingRule.
|
||||
* Each interior region is guaranteed be monotone.
|
||||
*/
|
||||
int __gl_computeInterior( GLUtesselator *tess );
|
||||
|
||||
|
||||
/* The following is here *only* for access by debugging routines */
|
||||
|
||||
#include "dict.h"
|
||||
|
||||
/* For each pair of adjacent edges crossing the sweep line, there is
|
||||
* an ActiveRegion to represent the region between them. The active
|
||||
* regions are kept in sorted order in a dynamic dictionary. As the
|
||||
* sweep line crosses each vertex, we update the affected regions.
|
||||
*/
|
||||
|
||||
struct ActiveRegion {
|
||||
GLUhalfEdge *eUp; /* upper edge, directed right to left */
|
||||
DictNode *nodeUp; /* dictionary node corresponding to eUp */
|
||||
int windingNumber; /* used to determine which regions are
|
||||
* inside the polygon */
|
||||
GLboolean inside; /* is this region inside the polygon? */
|
||||
GLboolean sentinel; /* marks fake edges at t = +/-infinity */
|
||||
GLboolean dirty; /* marks regions where the upper or lower
|
||||
* edge has changed, but we haven't checked
|
||||
* whether they intersect yet */
|
||||
GLboolean fixUpperEdge; /* marks temporary edges introduced when
|
||||
* we process a "right vertex" (one without
|
||||
* any edges leaving to the right) */
|
||||
};
|
||||
|
||||
#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp)))
|
||||
#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp)))
|
||||
|
||||
#endif
|
@ -1,632 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
#include "memalloc.h"
|
||||
#include "tess.h"
|
||||
#include "mesh.h"
|
||||
#include "normal.h"
|
||||
#include "sweep.h"
|
||||
#include "tessmono.h"
|
||||
#include "render.h"
|
||||
|
||||
#define GLU_TESS_DEFAULT_TOLERANCE 0.0
|
||||
#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
|
||||
GLfloat weight[4], void **dataOut ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
|
||||
|
||||
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
|
||||
void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
|
||||
void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
|
||||
void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
|
||||
void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
|
||||
void *data[4],
|
||||
GLfloat weight[4],
|
||||
void **outData,
|
||||
void *polygonData ) {}
|
||||
|
||||
/* Half-edges are allocated in pairs (see mesh.c) */
|
||||
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
|
||||
|
||||
#undef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
|
||||
MAX(sizeof(GLUvertex),sizeof(GLUface))))
|
||||
|
||||
|
||||
GLUtesselator * GLAPIENTRY
|
||||
gluNewTess( void )
|
||||
{
|
||||
GLUtesselator *tess;
|
||||
|
||||
/* Only initialize fields which can be changed by the api. Other fields
|
||||
* are initialized where they are used.
|
||||
*/
|
||||
|
||||
if (memInit( MAX_FAST_ALLOC ) == 0) {
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
|
||||
if (tess == NULL) {
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
|
||||
tess->state = T_DORMANT;
|
||||
|
||||
tess->normal[0] = 0;
|
||||
tess->normal[1] = 0;
|
||||
tess->normal[2] = 0;
|
||||
|
||||
tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
|
||||
tess->windingRule = GLU_TESS_WINDING_ODD;
|
||||
tess->flagBoundary = FALSE;
|
||||
tess->boundaryOnly = FALSE;
|
||||
|
||||
tess->callBegin = &noBegin;
|
||||
tess->callEdgeFlag = &noEdgeFlag;
|
||||
tess->callVertex = &noVertex;
|
||||
tess->callEnd = &noEnd;
|
||||
|
||||
tess->callError = &noError;
|
||||
tess->callCombine = &noCombine;
|
||||
tess->callMesh = &noMesh;
|
||||
|
||||
tess->callBeginData= &__gl_noBeginData;
|
||||
tess->callEdgeFlagData= &__gl_noEdgeFlagData;
|
||||
tess->callVertexData= &__gl_noVertexData;
|
||||
tess->callEndData= &__gl_noEndData;
|
||||
tess->callErrorData= &__gl_noErrorData;
|
||||
tess->callCombineData= &__gl_noCombineData;
|
||||
|
||||
tess->polygonData= NULL;
|
||||
|
||||
return tess;
|
||||
}
|
||||
|
||||
static void MakeDormant( GLUtesselator *tess )
|
||||
{
|
||||
/* Return the tessellator to its original dormant state. */
|
||||
|
||||
if( tess->mesh != NULL ) {
|
||||
__gl_meshDeleteMesh( tess->mesh );
|
||||
}
|
||||
tess->state = T_DORMANT;
|
||||
tess->lastEdge = NULL;
|
||||
tess->mesh = NULL;
|
||||
}
|
||||
|
||||
#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
|
||||
|
||||
static void GotoState( GLUtesselator *tess, enum TessState newState )
|
||||
{
|
||||
while( tess->state != newState ) {
|
||||
/* We change the current state one level at a time, to get to
|
||||
* the desired state.
|
||||
*/
|
||||
if( tess->state < newState ) {
|
||||
switch( tess->state ) {
|
||||
case T_DORMANT:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
|
||||
gluTessBeginPolygon( tess, NULL );
|
||||
break;
|
||||
case T_IN_POLYGON:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
|
||||
gluTessBeginContour( tess );
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
} else {
|
||||
switch( tess->state ) {
|
||||
case T_IN_CONTOUR:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
|
||||
gluTessEndContour( tess );
|
||||
break;
|
||||
case T_IN_POLYGON:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
|
||||
/* gluTessEndPolygon( tess ) is too much work! */
|
||||
MakeDormant( tess );
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluDeleteTess( GLUtesselator *tess )
|
||||
{
|
||||
RequireState( tess, T_DORMANT );
|
||||
memFree( tess );
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
|
||||
{
|
||||
GLenum windingRule;
|
||||
|
||||
switch( which ) {
|
||||
case GLU_TESS_TOLERANCE:
|
||||
if( value < 0.0 || value > 1.0 ) break;
|
||||
tess->relTolerance = value;
|
||||
return;
|
||||
|
||||
case GLU_TESS_WINDING_RULE:
|
||||
windingRule = (GLenum) value;
|
||||
if( windingRule != value ) break; /* not an integer */
|
||||
|
||||
switch( windingRule ) {
|
||||
case GLU_TESS_WINDING_ODD:
|
||||
case GLU_TESS_WINDING_NONZERO:
|
||||
case GLU_TESS_WINDING_POSITIVE:
|
||||
case GLU_TESS_WINDING_NEGATIVE:
|
||||
case GLU_TESS_WINDING_ABS_GEQ_TWO:
|
||||
tess->windingRule = windingRule;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case GLU_TESS_BOUNDARY_ONLY:
|
||||
tess->boundaryOnly = (value != 0);
|
||||
return;
|
||||
|
||||
default:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
|
||||
return;
|
||||
}
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
|
||||
}
|
||||
|
||||
/* Returns tessellator property */
|
||||
void GLAPIENTRY
|
||||
gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
|
||||
{
|
||||
switch (which) {
|
||||
case GLU_TESS_TOLERANCE:
|
||||
/* tolerance should be in range [0..1] */
|
||||
assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
|
||||
*value= tess->relTolerance;
|
||||
break;
|
||||
case GLU_TESS_WINDING_RULE:
|
||||
assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
|
||||
tess->windingRule == GLU_TESS_WINDING_NONZERO ||
|
||||
tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
|
||||
tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
|
||||
tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
|
||||
*value= tess->windingRule;
|
||||
break;
|
||||
case GLU_TESS_BOUNDARY_ONLY:
|
||||
assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
|
||||
*value= tess->boundaryOnly;
|
||||
break;
|
||||
default:
|
||||
*value= 0.0;
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
|
||||
break;
|
||||
}
|
||||
} /* gluGetTessProperty() */
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
|
||||
{
|
||||
tess->normal[0] = x;
|
||||
tess->normal[1] = y;
|
||||
tess->normal[2] = z;
|
||||
}
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
|
||||
{
|
||||
switch( which ) {
|
||||
case GLU_TESS_BEGIN:
|
||||
tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
|
||||
return;
|
||||
case GLU_TESS_BEGIN_DATA:
|
||||
tess->callBeginData = (fn == NULL) ?
|
||||
&__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_EDGE_FLAG:
|
||||
tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
|
||||
(void (GLAPIENTRY *)(GLboolean)) fn;
|
||||
/* If the client wants boundary edges to be flagged,
|
||||
* we render everything as separate triangles (no strips or fans).
|
||||
*/
|
||||
tess->flagBoundary = (fn != NULL);
|
||||
return;
|
||||
case GLU_TESS_EDGE_FLAG_DATA:
|
||||
tess->callEdgeFlagData= (fn == NULL) ?
|
||||
&__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
|
||||
/* If the client wants boundary edges to be flagged,
|
||||
* we render everything as separate triangles (no strips or fans).
|
||||
*/
|
||||
tess->flagBoundary = (fn != NULL);
|
||||
return;
|
||||
case GLU_TESS_VERTEX:
|
||||
tess->callVertex = (fn == NULL) ? &noVertex :
|
||||
(void (GLAPIENTRY *)(void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_VERTEX_DATA:
|
||||
tess->callVertexData = (fn == NULL) ?
|
||||
&__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_END:
|
||||
tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
|
||||
return;
|
||||
case GLU_TESS_END_DATA:
|
||||
tess->callEndData = (fn == NULL) ? &__gl_noEndData :
|
||||
(void (GLAPIENTRY *)(void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_ERROR:
|
||||
tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
|
||||
return;
|
||||
case GLU_TESS_ERROR_DATA:
|
||||
tess->callErrorData = (fn == NULL) ?
|
||||
&__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_COMBINE:
|
||||
tess->callCombine = (fn == NULL) ? &noCombine :
|
||||
(void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
|
||||
return;
|
||||
case GLU_TESS_COMBINE_DATA:
|
||||
tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
|
||||
(void (GLAPIENTRY *)(GLdouble [3],
|
||||
void *[4],
|
||||
GLfloat [4],
|
||||
void **,
|
||||
void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_MESH:
|
||||
tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
|
||||
return;
|
||||
default:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
|
||||
{
|
||||
GLUhalfEdge *e;
|
||||
|
||||
e = tess->lastEdge;
|
||||
if( e == NULL ) {
|
||||
/* Make a self-loop (one vertex, one edge). */
|
||||
|
||||
e = __gl_meshMakeEdge( tess->mesh );
|
||||
if (e == NULL) return 0;
|
||||
if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
|
||||
} else {
|
||||
/* Create a new vertex and edge which immediately follow e
|
||||
* in the ordering around the left face.
|
||||
*/
|
||||
if (__gl_meshSplitEdge( e ) == NULL) return 0;
|
||||
e = e->Lnext;
|
||||
}
|
||||
|
||||
/* The new vertex is now e->Org. */
|
||||
e->Org->data = data;
|
||||
e->Org->coords[0] = coords[0];
|
||||
e->Org->coords[1] = coords[1];
|
||||
e->Org->coords[2] = coords[2];
|
||||
|
||||
/* The winding of an edge says how the winding number changes as we
|
||||
* cross from the edge''s right face to its left face. We add the
|
||||
* vertices in such an order that a CCW contour will add +1 to
|
||||
* the winding number of the region inside the contour.
|
||||
*/
|
||||
e->winding = 1;
|
||||
e->Sym->winding = -1;
|
||||
|
||||
tess->lastEdge = e;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
|
||||
{
|
||||
CachedVertex *v = &tess->cache[tess->cacheCount];
|
||||
|
||||
v->data = data;
|
||||
v->coords[0] = coords[0];
|
||||
v->coords[1] = coords[1];
|
||||
v->coords[2] = coords[2];
|
||||
++tess->cacheCount;
|
||||
}
|
||||
|
||||
|
||||
static int EmptyCache( GLUtesselator *tess )
|
||||
{
|
||||
CachedVertex *v = tess->cache;
|
||||
CachedVertex *vLast;
|
||||
|
||||
tess->mesh = __gl_meshNewMesh();
|
||||
if (tess->mesh == NULL) return 0;
|
||||
|
||||
for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
|
||||
if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
|
||||
}
|
||||
tess->cacheCount = 0;
|
||||
tess->emptyCache = FALSE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
|
||||
{
|
||||
int i, tooLarge = FALSE;
|
||||
GLdouble x, clamped[3];
|
||||
|
||||
RequireState( tess, T_IN_CONTOUR );
|
||||
|
||||
if( tess->emptyCache ) {
|
||||
if ( !EmptyCache( tess ) ) {
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
|
||||
return;
|
||||
}
|
||||
tess->lastEdge = NULL;
|
||||
}
|
||||
for( i = 0; i < 3; ++i ) {
|
||||
x = coords[i];
|
||||
if( x < - GLU_TESS_MAX_COORD ) {
|
||||
x = - GLU_TESS_MAX_COORD;
|
||||
tooLarge = TRUE;
|
||||
}
|
||||
if( x > GLU_TESS_MAX_COORD ) {
|
||||
x = GLU_TESS_MAX_COORD;
|
||||
tooLarge = TRUE;
|
||||
}
|
||||
clamped[i] = x;
|
||||
}
|
||||
if( tooLarge ) {
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
|
||||
}
|
||||
|
||||
if( tess->mesh == NULL ) {
|
||||
if( tess->cacheCount < TESS_MAX_CACHE ) {
|
||||
CacheVertex( tess, clamped, data );
|
||||
return;
|
||||
}
|
||||
if ( !EmptyCache( tess ) ) {
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( !AddVertex( tess, clamped, data ) ) {
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessBeginPolygon( GLUtesselator *tess, void *data )
|
||||
{
|
||||
RequireState( tess, T_DORMANT );
|
||||
|
||||
tess->state = T_IN_POLYGON;
|
||||
tess->cacheCount = 0;
|
||||
tess->emptyCache = FALSE;
|
||||
tess->mesh = NULL;
|
||||
|
||||
tess->polygonData= data;
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessBeginContour( GLUtesselator *tess )
|
||||
{
|
||||
RequireState( tess, T_IN_POLYGON );
|
||||
|
||||
tess->state = T_IN_CONTOUR;
|
||||
tess->lastEdge = NULL;
|
||||
if( tess->cacheCount > 0 ) {
|
||||
/* Just set a flag so we don't get confused by empty contours
|
||||
* -- these can be generated accidentally with the obsolete
|
||||
* NextContour() interface.
|
||||
*/
|
||||
tess->emptyCache = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessEndContour( GLUtesselator *tess )
|
||||
{
|
||||
RequireState( tess, T_IN_CONTOUR );
|
||||
tess->state = T_IN_POLYGON;
|
||||
}
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessEndPolygon( GLUtesselator *tess )
|
||||
{
|
||||
GLUmesh *mesh;
|
||||
|
||||
if (setjmp(tess->env) != 0) {
|
||||
/* come back here if out of memory */
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
|
||||
return;
|
||||
}
|
||||
|
||||
RequireState( tess, T_IN_POLYGON );
|
||||
tess->state = T_DORMANT;
|
||||
|
||||
if( tess->mesh == NULL ) {
|
||||
if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
|
||||
|
||||
/* Try some special code to make the easy cases go quickly
|
||||
* (eg. convex polygons). This code does NOT handle multiple contours,
|
||||
* intersections, edge flags, and of course it does not generate
|
||||
* an explicit mesh either.
|
||||
*/
|
||||
if( __gl_renderCache( tess )) {
|
||||
tess->polygonData= NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
|
||||
}
|
||||
|
||||
/* Determine the polygon normal and project vertices onto the plane
|
||||
* of the polygon.
|
||||
*/
|
||||
__gl_projectPolygon( tess );
|
||||
|
||||
/* __gl_computeInterior( tess ) computes the planar arrangement specified
|
||||
* by the given contours, and further subdivides this arrangement
|
||||
* into regions. Each region is marked "inside" if it belongs
|
||||
* to the polygon, according to the rule given by tess->windingRule.
|
||||
* Each interior region is guaranteed be monotone.
|
||||
*/
|
||||
if ( !__gl_computeInterior( tess ) ) {
|
||||
longjmp(tess->env,1); /* could've used a label */
|
||||
}
|
||||
|
||||
mesh = tess->mesh;
|
||||
if( ! tess->fatalError ) {
|
||||
int rc = 1;
|
||||
|
||||
/* If the user wants only the boundary contours, we throw away all edges
|
||||
* except those which separate the interior from the exterior.
|
||||
* Otherwise we tessellate all the regions marked "inside".
|
||||
*/
|
||||
if( tess->boundaryOnly ) {
|
||||
rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
|
||||
} else {
|
||||
rc = __gl_meshTessellateInterior( mesh );
|
||||
}
|
||||
if (rc == 0) longjmp(tess->env,1); /* could've used a label */
|
||||
|
||||
__gl_meshCheckMesh( mesh );
|
||||
|
||||
if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
|
||||
|| tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
|
||||
|| tess->callBeginData != &__gl_noBeginData
|
||||
|| tess->callEndData != &__gl_noEndData
|
||||
|| tess->callVertexData != &__gl_noVertexData
|
||||
|| tess->callEdgeFlagData != &__gl_noEdgeFlagData )
|
||||
{
|
||||
if( tess->boundaryOnly ) {
|
||||
__gl_renderBoundary( tess, mesh ); /* output boundary contours */
|
||||
} else {
|
||||
__gl_renderMesh( tess, mesh ); /* output strips and fans */
|
||||
}
|
||||
}
|
||||
if( tess->callMesh != &noMesh ) {
|
||||
|
||||
/* Throw away the exterior faces, so that all faces are interior.
|
||||
* This way the user doesn't have to check the "inside" flag,
|
||||
* and we don't need to even reveal its existence. It also leaves
|
||||
* the freedom for an implementation to not generate the exterior
|
||||
* faces in the first place.
|
||||
*/
|
||||
__gl_meshDiscardExterior( mesh );
|
||||
(*tess->callMesh)( mesh ); /* user wants the mesh itself */
|
||||
tess->mesh = NULL;
|
||||
tess->polygonData= NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
__gl_meshDeleteMesh( mesh );
|
||||
tess->polygonData= NULL;
|
||||
tess->mesh = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*XXXblythe unused function*/
|
||||
#if 0
|
||||
void GLAPIENTRY
|
||||
gluDeleteMesh( GLUmesh *mesh )
|
||||
{
|
||||
__gl_meshDeleteMesh( mesh );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
/* Obsolete calls -- for backward compatibility */
|
||||
|
||||
void GLAPIENTRY
|
||||
gluBeginPolygon( GLUtesselator *tess )
|
||||
{
|
||||
gluTessBeginPolygon( tess, NULL );
|
||||
gluTessBeginContour( tess );
|
||||
}
|
||||
|
||||
|
||||
/*ARGSUSED*/
|
||||
void GLAPIENTRY
|
||||
gluNextContour( GLUtesselator *tess, GLenum type )
|
||||
{
|
||||
gluTessEndContour( tess );
|
||||
gluTessBeginContour( tess );
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluEndPolygon( GLUtesselator *tess )
|
||||
{
|
||||
gluTessEndContour( tess );
|
||||
gluTessEndPolygon( tess );
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __tess_h_
|
||||
#define __tess_h_
|
||||
|
||||
#include <setjmp.h>
|
||||
#include "mesh.h"
|
||||
#include "dict.h"
|
||||
#include "priorityq.h"
|
||||
|
||||
/* The begin/end calls must be properly nested. We keep track of
|
||||
* the current state to enforce the ordering.
|
||||
*/
|
||||
enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
|
||||
|
||||
/* We cache vertex data for single-contour polygons so that we can
|
||||
* try a quick-and-dirty decomposition first.
|
||||
*/
|
||||
#define TESS_MAX_CACHE 100
|
||||
|
||||
typedef struct CachedVertex {
|
||||
GLdouble coords[3];
|
||||
void *data;
|
||||
} CachedVertex;
|
||||
|
||||
struct GLUtesselator {
|
||||
|
||||
/*** state needed for collecting the input data ***/
|
||||
|
||||
enum TessState state; /* what begin/end calls have we seen? */
|
||||
|
||||
GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */
|
||||
GLUmesh *mesh; /* stores the input contours, and eventually
|
||||
the tessellation itself */
|
||||
|
||||
void (GLAPIENTRY *callError)( GLenum errnum );
|
||||
|
||||
/*** state needed for projecting onto the sweep plane ***/
|
||||
|
||||
GLdouble normal[3]; /* user-specified normal (if provided) */
|
||||
GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */
|
||||
GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */
|
||||
|
||||
/*** state needed for the line sweep ***/
|
||||
|
||||
GLdouble relTolerance; /* tolerance for merging features */
|
||||
GLenum windingRule; /* rule for determining polygon interior */
|
||||
GLboolean fatalError; /* fatal error: needed combine callback */
|
||||
|
||||
Dict *dict; /* edge dictionary for sweep line */
|
||||
PriorityQ *pq; /* priority queue of vertex events */
|
||||
GLUvertex *event; /* current sweep event being processed */
|
||||
|
||||
void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4],
|
||||
GLfloat weight[4], void **outData );
|
||||
|
||||
/*** state needed for rendering callbacks (see render.c) ***/
|
||||
|
||||
GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
|
||||
GLboolean boundaryOnly; /* Extract contours, not triangles */
|
||||
GLUface *lonelyTriList;
|
||||
/* list of triangles which could not be rendered as strips or fans */
|
||||
|
||||
void (GLAPIENTRY *callBegin)( GLenum type );
|
||||
void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge );
|
||||
void (GLAPIENTRY *callVertex)( void *data );
|
||||
void (GLAPIENTRY *callEnd)( void );
|
||||
void (GLAPIENTRY *callMesh)( GLUmesh *mesh );
|
||||
|
||||
|
||||
/*** state needed to cache single-contour polygons for renderCache() */
|
||||
|
||||
GLboolean emptyCache; /* empty cache on next vertex() call */
|
||||
int cacheCount; /* number of cached vertices */
|
||||
CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */
|
||||
|
||||
/*** rendering callbacks that also pass polygon data ***/
|
||||
void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData );
|
||||
void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge,
|
||||
void *polygonData );
|
||||
void (GLAPIENTRY *callVertexData)( void *data, void *polygonData );
|
||||
void (GLAPIENTRY *callEndData)( void *polygonData );
|
||||
void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData );
|
||||
void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4],
|
||||
GLfloat weight[4], void **outData,
|
||||
void *polygonData );
|
||||
|
||||
jmp_buf env; /* place to jump to when memAllocs fail */
|
||||
|
||||
void *polygonData; /* client data for current polygon */
|
||||
};
|
||||
|
||||
void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData );
|
||||
void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData );
|
||||
void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData );
|
||||
void GLAPIENTRY __gl_noEndData( void *polygonData );
|
||||
void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData );
|
||||
void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4],
|
||||
GLfloat weight[4], void **outData,
|
||||
void *polygonData );
|
||||
|
||||
#define CALL_BEGIN_OR_BEGIN_DATA(a) \
|
||||
if (tess->callBeginData != &__gl_noBeginData) \
|
||||
(*tess->callBeginData)((a),tess->polygonData); \
|
||||
else (*tess->callBegin)((a));
|
||||
|
||||
#define CALL_VERTEX_OR_VERTEX_DATA(a) \
|
||||
if (tess->callVertexData != &__gl_noVertexData) \
|
||||
(*tess->callVertexData)((a),tess->polygonData); \
|
||||
else (*tess->callVertex)((a));
|
||||
|
||||
#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
|
||||
if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
|
||||
(*tess->callEdgeFlagData)((a),tess->polygonData); \
|
||||
else (*tess->callEdgeFlag)((a));
|
||||
|
||||
#define CALL_END_OR_END_DATA() \
|
||||
if (tess->callEndData != &__gl_noEndData) \
|
||||
(*tess->callEndData)(tess->polygonData); \
|
||||
else (*tess->callEnd)();
|
||||
|
||||
#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
|
||||
if (tess->callCombineData != &__gl_noCombineData) \
|
||||
(*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
|
||||
else (*tess->callCombine)((a),(b),(c),(d));
|
||||
|
||||
#define CALL_ERROR_OR_ERROR_DATA(a) \
|
||||
if (tess->callErrorData != &__gl_noErrorData) \
|
||||
(*tess->callErrorData)((a),tess->polygonData); \
|
||||
else (*tess->callError)((a));
|
||||
|
||||
#endif
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __TESSELATOR_H__
|
||||
#define __TESSELATOR_H__
|
||||
|
||||
/* This just includes the defines needed by the tesselator code */
|
||||
|
||||
#include "cogl/cogl-defines.h"
|
||||
#include "cogl/cogl-gl-header.h"
|
||||
|
||||
typedef struct GLUtesselator GLUtesselator;
|
||||
|
||||
#define GLU_TESS_MAX_COORD 1.0e150
|
||||
|
||||
void gluBeginPolygon (GLUtesselator* tess);
|
||||
void gluDeleteTess (GLUtesselator* tess);
|
||||
void gluEndPolygon (GLUtesselator* tess);
|
||||
|
||||
typedef void (_GLUfuncptr)(void);
|
||||
|
||||
void gluGetTessProperty (GLUtesselator* tess, GLenum which, double* data);
|
||||
|
||||
GLUtesselator *gluNewTess (void);
|
||||
void gluNextContour (GLUtesselator* tess, GLenum type);
|
||||
|
||||
void gluTessBeginContour (GLUtesselator* tess);
|
||||
void gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data);
|
||||
void gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
|
||||
void gluTessEndContour (GLUtesselator* tess);
|
||||
void gluTessEndPolygon (GLUtesselator* tess);
|
||||
void gluTessNormal (GLUtesselator* tess, double valueX, double valueY, double valueZ);
|
||||
void gluTessProperty (GLUtesselator* tess, GLenum which, double data);
|
||||
void gluTessVertex (GLUtesselator* tess, double *location, GLvoid* data);
|
||||
|
||||
/* ErrorCode */
|
||||
#define GLU_INVALID_ENUM 100900
|
||||
#define GLU_INVALID_VALUE 100901
|
||||
#define GLU_OUT_OF_MEMORY 100902
|
||||
|
||||
/* TessCallback */
|
||||
#define GLU_TESS_BEGIN 100100
|
||||
#define GLU_BEGIN 100100
|
||||
#define GLU_TESS_VERTEX 100101
|
||||
#define GLU_VERTEX 100101
|
||||
#define GLU_TESS_END 100102
|
||||
#define GLU_END 100102
|
||||
#define GLU_TESS_ERROR 100103
|
||||
#define GLU_TESS_EDGE_FLAG 100104
|
||||
#define GLU_EDGE_FLAG 100104
|
||||
#define GLU_TESS_COMBINE 100105
|
||||
#define GLU_TESS_BEGIN_DATA 100106
|
||||
#define GLU_TESS_VERTEX_DATA 100107
|
||||
#define GLU_TESS_END_DATA 100108
|
||||
#define GLU_TESS_ERROR_DATA 100109
|
||||
#define GLU_TESS_EDGE_FLAG_DATA 100110
|
||||
#define GLU_TESS_COMBINE_DATA 100111
|
||||
|
||||
/* TessContour */
|
||||
#define GLU_CW 100120
|
||||
#define GLU_CCW 100121
|
||||
#define GLU_INTERIOR 100122
|
||||
#define GLU_EXTERIOR 100123
|
||||
#define GLU_UNKNOWN 100124
|
||||
|
||||
/* TessProperty */
|
||||
#define GLU_TESS_WINDING_RULE 100140
|
||||
#define GLU_TESS_BOUNDARY_ONLY 100141
|
||||
#define GLU_TESS_TOLERANCE 100142
|
||||
|
||||
/* TessError */
|
||||
#define GLU_TESS_ERROR1 100151
|
||||
#define GLU_TESS_ERROR2 100152
|
||||
#define GLU_TESS_ERROR3 100153
|
||||
#define GLU_TESS_ERROR4 100154
|
||||
#define GLU_TESS_ERROR5 100155
|
||||
#define GLU_TESS_ERROR6 100156
|
||||
#define GLU_TESS_ERROR7 100157
|
||||
#define GLU_TESS_ERROR8 100158
|
||||
#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
|
||||
#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
|
||||
#define GLU_TESS_MISSING_END_POLYGON 100153
|
||||
#define GLU_TESS_MISSING_END_CONTOUR 100154
|
||||
#define GLU_TESS_COORD_TOO_LARGE 100155
|
||||
#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
|
||||
|
||||
/* TessWinding */
|
||||
#define GLU_TESS_WINDING_ODD 100130
|
||||
#define GLU_TESS_WINDING_NONZERO 100131
|
||||
#define GLU_TESS_WINDING_POSITIVE 100132
|
||||
#define GLU_TESS_WINDING_NEGATIVE 100133
|
||||
#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
|
||||
|
||||
#endif /* __TESSELATOR_H__ */
|
@ -1,201 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <stdlib.h>
|
||||
#include "geom.h"
|
||||
#include "mesh.h"
|
||||
#include "tessmono.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
|
||||
eDst->Sym->winding += eSrc->Sym->winding)
|
||||
|
||||
/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
|
||||
* (what else would it do??) The region must consist of a single
|
||||
* loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
|
||||
* case means that any vertical line intersects the interior of the
|
||||
* region in a single interval.
|
||||
*
|
||||
* Tessellation consists of adding interior edges (actually pairs of
|
||||
* half-edges), to split the region into non-overlapping triangles.
|
||||
*
|
||||
* The basic idea is explained in Preparata and Shamos (which I don''t
|
||||
* have handy right now), although their implementation is more
|
||||
* complicated than this one. The are two edge chains, an upper chain
|
||||
* and a lower chain. We process all vertices from both chains in order,
|
||||
* from right to left.
|
||||
*
|
||||
* The algorithm ensures that the following invariant holds after each
|
||||
* vertex is processed: the untessellated region consists of two
|
||||
* chains, where one chain (say the upper) is a single edge, and
|
||||
* the other chain is concave. The left vertex of the single edge
|
||||
* is always to the left of all vertices in the concave chain.
|
||||
*
|
||||
* Each step consists of adding the rightmost unprocessed vertex to one
|
||||
* of the two chains, and forming a fan of triangles from the rightmost
|
||||
* of two chain endpoints. Determining whether we can add each triangle
|
||||
* to the fan is a simple orientation test. By making the fan as large
|
||||
* as possible, we restore the invariant (check it yourself).
|
||||
*/
|
||||
int __gl_meshTessellateMonoRegion( GLUface *face )
|
||||
{
|
||||
GLUhalfEdge *up, *lo;
|
||||
|
||||
/* All edges are oriented CCW around the boundary of the region.
|
||||
* First, find the half-edge whose origin vertex is rightmost.
|
||||
* Since the sweep goes from left to right, face->anEdge should
|
||||
* be close to the edge we want.
|
||||
*/
|
||||
up = face->anEdge;
|
||||
assert( up->Lnext != up && up->Lnext->Lnext != up );
|
||||
|
||||
for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
|
||||
;
|
||||
for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
|
||||
;
|
||||
lo = up->Lprev;
|
||||
|
||||
while( up->Lnext != lo ) {
|
||||
if( VertLeq( up->Dst, lo->Org )) {
|
||||
/* up->Dst is on the left. It is safe to form triangles from lo->Org.
|
||||
* The EdgeGoesLeft test guarantees progress even when some triangles
|
||||
* are CW, given that the upper and lower chains are truly monotone.
|
||||
*/
|
||||
while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
|
||||
|| EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
|
||||
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
|
||||
if (tempHalfEdge == NULL) return 0;
|
||||
lo = tempHalfEdge->Sym;
|
||||
}
|
||||
lo = lo->Lprev;
|
||||
} else {
|
||||
/* lo->Org is on the left. We can make CCW triangles from up->Dst. */
|
||||
while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
|
||||
|| EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
|
||||
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
|
||||
if (tempHalfEdge == NULL) return 0;
|
||||
up = tempHalfEdge->Sym;
|
||||
}
|
||||
up = up->Lnext;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
|
||||
* can be tessellated in a fan from this leftmost vertex.
|
||||
*/
|
||||
assert( lo->Lnext != up );
|
||||
while( lo->Lnext->Lnext != up ) {
|
||||
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
|
||||
if (tempHalfEdge == NULL) return 0;
|
||||
lo = tempHalfEdge->Sym;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshTessellateInterior( mesh ) tessellates each region of
|
||||
* the mesh which is marked "inside" the polygon. Each such region
|
||||
* must be monotone.
|
||||
*/
|
||||
int __gl_meshTessellateInterior( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f, *next;
|
||||
|
||||
/*LINTED*/
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
|
||||
/* Make sure we don''t try to tessellate the new triangles. */
|
||||
next = f->next;
|
||||
if( f->inside ) {
|
||||
if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
|
||||
* which are not marked "inside" the polygon. Since further mesh operations
|
||||
* on NULL faces are not allowed, the main purpose is to clean up the
|
||||
* mesh so that exterior loops are not represented in the data structure.
|
||||
*/
|
||||
void __gl_meshDiscardExterior( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f, *next;
|
||||
|
||||
/*LINTED*/
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
|
||||
/* Since f will be destroyed, save its next pointer. */
|
||||
next = f->next;
|
||||
if( ! f->inside ) {
|
||||
__gl_meshZapFace( f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MARKED_FOR_DELETION 0x7fffffff
|
||||
|
||||
/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
|
||||
* winding numbers on all edges so that regions marked "inside" the
|
||||
* polygon have a winding number of "value", and regions outside
|
||||
* have a winding number of 0.
|
||||
*
|
||||
* If keepOnlyBoundary is TRUE, it also deletes all edges which do not
|
||||
* separate an interior region from an exterior one.
|
||||
*/
|
||||
int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
|
||||
GLboolean keepOnlyBoundary )
|
||||
{
|
||||
GLUhalfEdge *e, *eNext;
|
||||
|
||||
for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
|
||||
eNext = e->next;
|
||||
if( e->Rface->inside != e->Lface->inside ) {
|
||||
|
||||
/* This is a boundary edge (one side is interior, one is exterior). */
|
||||
e->winding = (e->Lface->inside) ? value : -value;
|
||||
} else {
|
||||
|
||||
/* Both regions are interior, or both are exterior. */
|
||||
if( ! keepOnlyBoundary ) {
|
||||
e->winding = 0;
|
||||
} else {
|
||||
if ( !__gl_meshDelete( e ) ) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __tessmono_h_
|
||||
#define __tessmono_h_
|
||||
|
||||
/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
|
||||
* (what else would it do??) The region must consist of a single
|
||||
* loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
|
||||
* case means that any vertical line intersects the interior of the
|
||||
* region in a single interval.
|
||||
*
|
||||
* Tessellation consists of adding interior edges (actually pairs of
|
||||
* half-edges), to split the region into non-overlapping triangles.
|
||||
*
|
||||
* __gl_meshTessellateInterior( mesh ) tessellates each region of
|
||||
* the mesh which is marked "inside" the polygon. Each such region
|
||||
* must be monotone.
|
||||
*
|
||||
* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
|
||||
* which are not marked "inside" the polygon. Since further mesh operations
|
||||
* on NULL faces are not allowed, the main purpose is to clean up the
|
||||
* mesh so that exterior loops are not represented in the data structure.
|
||||
*
|
||||
* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
|
||||
* winding numbers on all edges so that regions marked "inside" the
|
||||
* polygon have a winding number of "value", and regions outside
|
||||
* have a winding number of 0.
|
||||
*
|
||||
* If keepOnlyBoundary is TRUE, it also deletes all edges which do not
|
||||
* separate an interior region from an exterior one.
|
||||
*/
|
||||
|
||||
int __gl_meshTessellateMonoRegion( GLUface *face );
|
||||
int __gl_meshTessellateInterior( GLUmesh *mesh );
|
||||
void __gl_meshDiscardExterior( GLUmesh *mesh );
|
||||
int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
|
||||
GLboolean keepOnlyBoundary );
|
||||
|
||||
#endif
|
@ -52,7 +52,6 @@
|
||||
#include "cogl-onscreen-private.h"
|
||||
#include "cogl-fence-private.h"
|
||||
#include "cogl-poll-private.h"
|
||||
#include "cogl-path/cogl-path-types.h"
|
||||
#include "cogl-private.h"
|
||||
#include "winsys/cogl-winsys-private.h"
|
||||
|
||||
@ -125,11 +124,6 @@ struct _CoglContext
|
||||
|
||||
CoglMatrixEntry identity_entry;
|
||||
|
||||
/* A cache of the last (immutable) matrix stack entries that were
|
||||
* flushed to the GL matrix builtins */
|
||||
CoglMatrixEntryCache builtin_flushed_projection;
|
||||
CoglMatrixEntryCache builtin_flushed_modelview;
|
||||
|
||||
GArray *texture_units;
|
||||
int active_texture_unit;
|
||||
|
||||
@ -153,8 +147,6 @@ struct _CoglContext
|
||||
GArray *journal_flush_attributes_array;
|
||||
GArray *journal_clip_bounds;
|
||||
|
||||
GArray *polygon_vertices;
|
||||
|
||||
/* Some simple caching, to minimize state changes... */
|
||||
CoglPipeline *current_pipeline;
|
||||
unsigned long current_pipeline_changes_since_flush;
|
||||
@ -196,20 +188,12 @@ struct _CoglContext
|
||||
gboolean was_bound_to_onscreen;
|
||||
|
||||
/* Primitives */
|
||||
CoglPath *current_path;
|
||||
CoglPipeline *stencil_pipeline;
|
||||
|
||||
/* Pre-generated VBOs containing indices to generate GL_TRIANGLES
|
||||
out of a vertex array of quads */
|
||||
CoglIndices *quad_buffer_indices_byte;
|
||||
unsigned int quad_buffer_indices_len;
|
||||
CoglIndices *quad_buffer_indices;
|
||||
|
||||
CoglIndices *rectangle_byte_indices;
|
||||
CoglIndices *rectangle_short_indices;
|
||||
int rectangle_short_indices_len;
|
||||
|
||||
CoglPipeline *texture_download_pipeline;
|
||||
CoglPipeline *blit_texture_pipeline;
|
||||
|
||||
GSList *atlases;
|
||||
|
@ -276,8 +276,6 @@ cogl_context_new (CoglDisplay *display,
|
||||
g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
|
||||
context->journal_clip_bounds = NULL;
|
||||
|
||||
context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (float));
|
||||
|
||||
context->current_pipeline = NULL;
|
||||
context->current_pipeline_changes_since_flush = 0;
|
||||
context->current_pipeline_with_color_attrib = FALSE;
|
||||
@ -308,25 +306,17 @@ cogl_context_new (CoglDisplay *display,
|
||||
for (i = 0; i < COGL_BUFFER_BIND_TARGET_COUNT; i++)
|
||||
context->current_buffer[i] = NULL;
|
||||
|
||||
context->current_path = NULL;
|
||||
context->stencil_pipeline = cogl_pipeline_new (context);
|
||||
|
||||
context->quad_buffer_indices_byte = NULL;
|
||||
context->quad_buffer_indices = NULL;
|
||||
context->quad_buffer_indices_len = 0;
|
||||
|
||||
context->rectangle_byte_indices = NULL;
|
||||
context->rectangle_short_indices = NULL;
|
||||
context->rectangle_short_indices_len = 0;
|
||||
|
||||
context->texture_download_pipeline = NULL;
|
||||
context->blit_texture_pipeline = NULL;
|
||||
|
||||
context->current_modelview_entry = NULL;
|
||||
context->current_projection_entry = NULL;
|
||||
_cogl_matrix_entry_identity_init (&context->identity_entry);
|
||||
_cogl_matrix_entry_cache_init (&context->builtin_flushed_projection);
|
||||
_cogl_matrix_entry_cache_init (&context->builtin_flushed_modelview);
|
||||
|
||||
/* Create default textures used for fall backs */
|
||||
context->default_gl_texture_2d_tex =
|
||||
@ -356,9 +346,6 @@ _cogl_context_free (CoglContext *context)
|
||||
|
||||
winsys->context_deinit (context);
|
||||
|
||||
if (context->current_path)
|
||||
cogl_object_unref (context->current_path);
|
||||
|
||||
if (context->default_gl_texture_2d_tex)
|
||||
cogl_object_unref (context->default_gl_texture_2d_tex);
|
||||
|
||||
@ -376,14 +363,6 @@ _cogl_context_free (CoglContext *context)
|
||||
if (context->journal_clip_bounds)
|
||||
g_array_free (context->journal_clip_bounds, TRUE);
|
||||
|
||||
if (context->polygon_vertices)
|
||||
g_array_free (context->polygon_vertices, TRUE);
|
||||
|
||||
if (context->quad_buffer_indices_byte)
|
||||
cogl_object_unref (context->quad_buffer_indices_byte);
|
||||
if (context->quad_buffer_indices)
|
||||
cogl_object_unref (context->quad_buffer_indices);
|
||||
|
||||
if (context->rectangle_byte_indices)
|
||||
cogl_object_unref (context->rectangle_byte_indices);
|
||||
if (context->rectangle_short_indices)
|
||||
@ -413,8 +392,6 @@ _cogl_context_free (CoglContext *context)
|
||||
cogl_matrix_entry_unref (context->current_modelview_entry);
|
||||
if (context->current_projection_entry)
|
||||
cogl_matrix_entry_unref (context->current_projection_entry);
|
||||
_cogl_matrix_entry_cache_destroy (&context->builtin_flushed_projection);
|
||||
_cogl_matrix_entry_cache_destroy (&context->builtin_flushed_modelview);
|
||||
|
||||
_cogl_pipeline_cache_free (context->pipeline_cache);
|
||||
|
||||
|
@ -112,12 +112,12 @@ cogl_object_unref (void *object);
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* my_path_set_data (CoglPath *path, void *data)
|
||||
* my_path_set_data (CoglPipeline *pipeline, void *data)
|
||||
* {
|
||||
* cogl_object_set_user_data (COGL_OBJECT (path),
|
||||
* cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
* &private_key,
|
||||
* data,
|
||||
* destroy_path_private_cb);
|
||||
* destroy_pipeline_private_cb);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
|
@ -93,10 +93,12 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
|
||||
CoglOnscreen *
|
||||
_cogl_onscreen_new (void)
|
||||
{
|
||||
CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1);
|
||||
g_autofree CoglOnscreen *onscreen_ptr = g_new0 (CoglOnscreen, 1);
|
||||
CoglOnscreen *onscreen;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
onscreen = g_steal_pointer (&onscreen_ptr);
|
||||
_cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
|
||||
ctx,
|
||||
COGL_FRAMEBUFFER_TYPE_ONSCREEN,
|
||||
@ -403,6 +405,27 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen)
|
||||
return winsys->onscreen_get_buffer_age (onscreen);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
|
||||
CoglScanout *scanout)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
const CoglWinsysVtable *winsys;
|
||||
CoglFrameInfo *info;
|
||||
|
||||
g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
|
||||
g_return_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT));
|
||||
|
||||
info = _cogl_frame_info_new ();
|
||||
info->frame_counter = onscreen->frame_counter;
|
||||
g_queue_push_tail (&onscreen->pending_frame_infos, info);
|
||||
|
||||
winsys = _cogl_framebuffer_get_winsys (framebuffer);
|
||||
winsys->onscreen_direct_scanout (onscreen, scanout);
|
||||
|
||||
onscreen->frame_counter++;
|
||||
}
|
||||
|
||||
#ifdef COGL_HAS_X11_SUPPORT
|
||||
uint32_t
|
||||
cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen)
|
||||
|
@ -50,6 +50,8 @@ G_BEGIN_DECLS
|
||||
typedef struct _CoglOnscreen CoglOnscreen;
|
||||
#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
|
||||
|
||||
typedef struct _CoglScanout CoglScanout;
|
||||
|
||||
/**
|
||||
* cogl_onscreen_get_gtype:
|
||||
*
|
||||
@ -284,6 +286,13 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||
const int *rectangles,
|
||||
int n_rectangles);
|
||||
|
||||
/**
|
||||
* cogl_onscreen_direct_scanout: (skip)
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
|
||||
CoglScanout *scanout);
|
||||
|
||||
/**
|
||||
* cogl_onscreen_swap_region:
|
||||
* @onscreen: A #CoglOnscreen framebuffer
|
||||
|
@ -50,7 +50,7 @@ struct _CoglPipelineCache
|
||||
CoglPipelineCache *
|
||||
_cogl_pipeline_cache_new (void)
|
||||
{
|
||||
CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
|
||||
g_autofree CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
|
||||
unsigned long vertex_state;
|
||||
unsigned long layer_vertex_state;
|
||||
unsigned int fragment_state;
|
||||
@ -80,7 +80,7 @@ _cogl_pipeline_cache_new (void)
|
||||
layer_vertex_state | layer_fragment_state,
|
||||
"programs");
|
||||
|
||||
return cache;
|
||||
return g_steal_pointer (&cache);
|
||||
}
|
||||
|
||||
void
|
||||
|
27
cogl/cogl/cogl-scanout.c
Normal file
27
cogl/cogl/cogl-scanout.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cogl-config.h"
|
||||
|
||||
#include "cogl-scanout.h"
|
||||
|
||||
G_DEFINE_INTERFACE (CoglScanout, cogl_scanout, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
cogl_scanout_default_init (CoglScanoutInterface *iface)
|
||||
{
|
||||
}
|
35
cogl/cogl/cogl-scanout.h
Normal file
35
cogl/cogl/cogl-scanout.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef COGL_SCANOUT_H
|
||||
#define COGL_SCANOUT_H
|
||||
|
||||
#include "cogl/cogl-types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define COGL_TYPE_SCANOUT (cogl_scanout_get_type ())
|
||||
COGL_EXPORT
|
||||
G_DECLARE_INTERFACE (CoglScanout, cogl_scanout,
|
||||
COGL, SCANOUT, GObject)
|
||||
|
||||
struct _CoglScanoutInterface
|
||||
{
|
||||
GTypeInterface parent_iface;
|
||||
};
|
||||
|
||||
#endif /* COGL_SCANOUT_H */
|
@ -121,6 +121,9 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
|
||||
{
|
||||
CoglTextureLoader *loader;
|
||||
|
||||
g_return_val_if_fail (width >= 1, NULL);
|
||||
g_return_val_if_fail (height >= 1, NULL);
|
||||
|
||||
loader = _cogl_texture_create_loader ();
|
||||
loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
|
||||
loader->src.sized.width = width;
|
||||
|
@ -122,26 +122,11 @@
|
||||
#include <cogl/cogl-fence.h>
|
||||
#include <cogl/cogl-glib-source.h>
|
||||
#include <cogl/cogl-trace.h>
|
||||
#include <cogl/cogl-scanout.h>
|
||||
/* XXX: This will definitly go away once all the Clutter winsys
|
||||
* code has been migrated down into Cogl! */
|
||||
#include <cogl/deprecated/cogl-clutter.h>
|
||||
|
||||
/*
|
||||
* Cogl Path api compatability
|
||||
*
|
||||
* The cogl_path_ api used to be part of the core Cogl api so for
|
||||
* compatability we include cogl-path.h via cogl.h
|
||||
*
|
||||
* Note: we have to make sure not to include cogl-path.h while
|
||||
* building core cogl or generating the Cogl .gir data because
|
||||
* cogl-path now gets built after cogl and some cogl-path headers are
|
||||
* only generated at build time...
|
||||
*/
|
||||
#if !defined (COGL_COMPILATION) && \
|
||||
!defined (COGL_GIR_SCANNING)
|
||||
#include <cogl-path/cogl-path.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SECTION:cogl
|
||||
* @short_description: General purpose API
|
||||
|
@ -132,8 +132,8 @@ _cogl_framebuffer_gl_flush_viewport_state (CoglFramebuffer *framebuffer)
|
||||
{
|
||||
float gl_viewport_y;
|
||||
|
||||
g_assert (framebuffer->viewport_width >=0 &&
|
||||
framebuffer->viewport_height >=0);
|
||||
g_return_if_fail (framebuffer->viewport_width >= 0);
|
||||
g_return_if_fail (framebuffer->viewport_height >= 0);
|
||||
|
||||
/* Convert the Cogl viewport y offset to an OpenGL viewport y offset
|
||||
* NB: OpenGL defines its window and viewport origins to be bottom
|
||||
|
@ -122,6 +122,7 @@ cogl_nonintrospected_headers = [
|
||||
'cogl-version.h',
|
||||
'cogl-gtype-private.h',
|
||||
'cogl-glib-source.h',
|
||||
'cogl-scanout.h',
|
||||
]
|
||||
|
||||
cogl_nodist_headers = [
|
||||
@ -347,6 +348,7 @@ cogl_sources = [
|
||||
'cogl-closure-list.c',
|
||||
'cogl-fence.c',
|
||||
'cogl-fence-private.h',
|
||||
'cogl-scanout.c',
|
||||
'deprecated/cogl-material-compat.c',
|
||||
'deprecated/cogl-program.c',
|
||||
'deprecated/cogl-program-private.h',
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "cogl-renderer.h"
|
||||
#include "cogl-onscreen.h"
|
||||
#include "cogl-scanout.h"
|
||||
|
||||
#ifdef COGL_HAS_XLIB_SUPPORT
|
||||
#include "cogl-texture-pixmap-x11-private.h"
|
||||
@ -117,6 +118,10 @@ typedef struct _CoglWinsysVtable
|
||||
const int *rectangles,
|
||||
int n_rectangles);
|
||||
|
||||
void
|
||||
(*onscreen_direct_scanout) (CoglOnscreen *onscreen,
|
||||
CoglScanout *scanout);
|
||||
|
||||
void
|
||||
(*onscreen_set_visibility) (CoglOnscreen *onscreen,
|
||||
gboolean visibility);
|
||||
|
@ -116,7 +116,6 @@ if have_cogl_tests
|
||||
subdir('test-fixtures')
|
||||
endif
|
||||
subdir('cogl')
|
||||
subdir('cogl-path')
|
||||
subdir('cogl-pango')
|
||||
if have_cogl_tests
|
||||
subdir('tests')
|
||||
|
@ -40,8 +40,6 @@ cogl_test_conformance_sources = [
|
||||
'test-pipeline-shader-state.c',
|
||||
'test-texture-rg.c',
|
||||
'test-fence.c',
|
||||
'test-path.c',
|
||||
'test-path-clip.c',
|
||||
]
|
||||
|
||||
#unported = [
|
||||
@ -84,7 +82,6 @@ libmutter_cogl_test_conformance = executable('test-conformance',
|
||||
include_directories: cogl_test_conformance_includes,
|
||||
dependencies: [
|
||||
libmutter_cogl_dep,
|
||||
libmutter_cogl_path_dep,
|
||||
libmutter_cogl_test_fixtures_dep,
|
||||
],
|
||||
install: have_installed_tests,
|
||||
|
@ -57,8 +57,6 @@ main (int argc, char **argv)
|
||||
ADD_TEST (test_blend, 0, 0);
|
||||
ADD_TEST (test_premult, 0, TEST_KNOWN_FAILURE);
|
||||
UNPORTED_TEST (test_readpixels);
|
||||
ADD_TEST (test_path, 0, 0);
|
||||
ADD_TEST (test_path_clip, 0, 0);
|
||||
ADD_TEST (test_depth_test, 0, 0);
|
||||
ADD_TEST (test_backface_culling, 0, TEST_REQUIREMENT_NPOT);
|
||||
ADD_TEST (test_layer_remove, 0, 0);
|
||||
|
@ -42,39 +42,39 @@ void
|
||||
test_object (TestUtilsGTestFixture *fixture,
|
||||
void *data)
|
||||
{
|
||||
CoglPath *path;
|
||||
CoglPipeline *pipeline;
|
||||
|
||||
/* Assuming that COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES == 2
|
||||
* test associating 2 pointers to private data with an object */
|
||||
cogl_path_new ();
|
||||
path = cogl_get_path ();
|
||||
cogl_pipeline_new ();
|
||||
pipeline = cogl_pipeline_path ();
|
||||
|
||||
cogl_object_set_user_data (COGL_OBJECT (path),
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&private_key0,
|
||||
&user_data0,
|
||||
destroy0_cb);
|
||||
|
||||
cogl_object_set_user_data (COGL_OBJECT (path),
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&private_key1,
|
||||
&user_data1,
|
||||
destroy1_cb);
|
||||
|
||||
cogl_object_set_user_data (COGL_OBJECT (path),
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&private_key2,
|
||||
&user_data2,
|
||||
destroy2_cb);
|
||||
|
||||
cogl_object_set_user_data (COGL_OBJECT (path),
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&private_key1,
|
||||
NULL,
|
||||
destroy1_cb);
|
||||
|
||||
cogl_object_set_user_data (COGL_OBJECT (path),
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&private_key1,
|
||||
&user_data1,
|
||||
destroy1_cb);
|
||||
|
||||
cogl_object_unref (path);
|
||||
cogl_object_unref (pipeline);
|
||||
|
||||
g_assert_cmpint (destroy0_count, ==, 1);
|
||||
g_assert_cmpint (destroy1_count, ==, 2);
|
||||
|
@ -1,68 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl-path/cogl-path.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "test-declarations.h"
|
||||
#include "test-utils.h"
|
||||
|
||||
void
|
||||
test_path_clip (void)
|
||||
{
|
||||
CoglPath *path;
|
||||
CoglPipeline *pipeline;
|
||||
int fb_width, fb_height;
|
||||
|
||||
fb_width = cogl_framebuffer_get_width (test_fb);
|
||||
fb_height = cogl_framebuffer_get_height (test_fb);
|
||||
|
||||
cogl_framebuffer_orthographic (test_fb,
|
||||
0, 0, fb_width, fb_height, -1, 100);
|
||||
|
||||
path = cogl_path_new ();
|
||||
|
||||
cogl_framebuffer_clear4f (test_fb,
|
||||
COGL_BUFFER_BIT_COLOR,
|
||||
1.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
/* Make an L-shape with the top right corner left untouched */
|
||||
cogl_path_move_to (path, 0, fb_height);
|
||||
cogl_path_line_to (path, fb_width, fb_height);
|
||||
cogl_path_line_to (path, fb_width, fb_height / 2);
|
||||
cogl_path_line_to (path, fb_width / 2, fb_height / 2);
|
||||
cogl_path_line_to (path, fb_width / 2, 0);
|
||||
cogl_path_line_to (path, 0, 0);
|
||||
cogl_path_close (path);
|
||||
|
||||
cogl_framebuffer_push_path_clip (test_fb, path);
|
||||
|
||||
/* Try to fill the framebuffer with a blue rectangle. This should be
|
||||
* clipped to leave the top right quadrant as is */
|
||||
pipeline = cogl_pipeline_new (test_ctx);
|
||||
cogl_pipeline_set_color4ub (pipeline, 0, 0, 255, 255);
|
||||
cogl_framebuffer_draw_rectangle (test_fb,
|
||||
pipeline,
|
||||
0, 0, fb_width, fb_height);
|
||||
|
||||
cogl_framebuffer_pop_clip (test_fb);
|
||||
|
||||
cogl_object_unref (pipeline);
|
||||
cogl_object_unref (path);
|
||||
|
||||
/* Check each of the four quadrants */
|
||||
test_utils_check_pixel (test_fb,
|
||||
fb_width / 4, fb_height / 4,
|
||||
0x0000ffff);
|
||||
test_utils_check_pixel (test_fb,
|
||||
fb_width * 3 / 4, fb_height / 4,
|
||||
0xff0000ff);
|
||||
test_utils_check_pixel (test_fb,
|
||||
fb_width / 4, fb_height * 3 / 4,
|
||||
0x0000ffff);
|
||||
test_utils_check_pixel (test_fb,
|
||||
fb_width * 3 / 4, fb_height * 3 / 4,
|
||||
0x0000ffff);
|
||||
|
||||
if (cogl_test_verbose ())
|
||||
g_print ("OK\n");
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl-path/cogl-path.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "test-declarations.h"
|
||||
#include "test-utils.h"
|
||||
|
||||
#define BLOCK_SIZE 16
|
||||
|
||||
/* Number of pixels at the border of a block quadrant to skip when verifying */
|
||||
#define TEST_INSET 1
|
||||
|
||||
typedef struct _TestState
|
||||
{
|
||||
int dummy;
|
||||
} TestState;
|
||||
|
||||
static void
|
||||
draw_path_at (CoglPath *path, CoglPipeline *pipeline, int x, int y)
|
||||
{
|
||||
cogl_framebuffer_push_matrix (test_fb);
|
||||
cogl_framebuffer_translate (test_fb, x * BLOCK_SIZE, y * BLOCK_SIZE, 0.0f);
|
||||
|
||||
cogl_framebuffer_fill_path (test_fb, pipeline, path);
|
||||
|
||||
cogl_framebuffer_pop_matrix (test_fb);
|
||||
}
|
||||
|
||||
static void
|
||||
check_block (int block_x, int block_y, int block_mask)
|
||||
{
|
||||
uint32_t data[BLOCK_SIZE * BLOCK_SIZE];
|
||||
int qx, qy;
|
||||
|
||||
/* Block mask represents which quarters of the block should be
|
||||
filled. The bits from 0->3 represent the top left, top right,
|
||||
bottom left and bottom right respectively */
|
||||
|
||||
cogl_framebuffer_read_pixels (test_fb,
|
||||
block_x * BLOCK_SIZE,
|
||||
block_y * BLOCK_SIZE,
|
||||
BLOCK_SIZE, BLOCK_SIZE,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
||||
(uint8_t *)data);
|
||||
|
||||
for (qy = 0; qy < 2; qy++)
|
||||
for (qx = 0; qx < 2; qx++)
|
||||
{
|
||||
int bit = qx | (qy << 1);
|
||||
const char *intended_pixel = ((block_mask & (1 << bit)) ? "#ffffff" : "#000000");
|
||||
int x, y;
|
||||
|
||||
for (x = 0; x < BLOCK_SIZE / 2 - TEST_INSET * 2; x++)
|
||||
for (y = 0; y < BLOCK_SIZE / 2 - TEST_INSET * 2; y++)
|
||||
{
|
||||
const uint32_t *p = data + (qx * BLOCK_SIZE / 2 +
|
||||
qy * BLOCK_SIZE * BLOCK_SIZE / 2 +
|
||||
(x + TEST_INSET) +
|
||||
(y + TEST_INSET) * BLOCK_SIZE);
|
||||
char *screen_pixel = g_strdup_printf ("#%06x", GUINT32_FROM_BE (*p) >> 8);
|
||||
g_assert_cmpstr (screen_pixel, ==, intended_pixel);
|
||||
g_free (screen_pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
paint (TestState *state)
|
||||
{
|
||||
CoglPath *path_a, *path_b, *path_c;
|
||||
CoglPipeline *white = cogl_pipeline_new (test_ctx);
|
||||
|
||||
cogl_pipeline_set_color4f (white, 1, 1, 1, 1);
|
||||
|
||||
/* Create a path filling just a quarter of a block. It will use two
|
||||
rectangles so that we have a sub path in the path */
|
||||
path_a = cogl_path_new ();
|
||||
cogl_path_rectangle (path_a,
|
||||
BLOCK_SIZE * 3 / 4, BLOCK_SIZE / 2,
|
||||
BLOCK_SIZE, BLOCK_SIZE);
|
||||
cogl_path_rectangle (path_a,
|
||||
BLOCK_SIZE / 2, BLOCK_SIZE / 2,
|
||||
BLOCK_SIZE * 3 / 4, BLOCK_SIZE);
|
||||
draw_path_at (path_a, white, 0, 0);
|
||||
|
||||
/* Create another path filling the whole block */
|
||||
path_b = cogl_path_new ();
|
||||
cogl_path_rectangle (path_b, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
|
||||
draw_path_at (path_b, white, 1, 0);
|
||||
|
||||
/* Draw the first path again */
|
||||
draw_path_at (path_a, white, 2, 0);
|
||||
|
||||
/* Draw a copy of path a */
|
||||
path_c = cogl_path_copy (path_a);
|
||||
draw_path_at (path_c, white, 3, 0);
|
||||
|
||||
/* Add another rectangle to path a. We'll use line_to's instead of
|
||||
cogl_rectangle so that we don't create another sub-path because
|
||||
that is more likely to break the copy */
|
||||
cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2);
|
||||
cogl_path_line_to (path_a, 0, 0);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
|
||||
draw_path_at (path_a, white, 4, 0);
|
||||
|
||||
/* Draw the copy again. It should not have changed */
|
||||
draw_path_at (path_c, white, 5, 0);
|
||||
|
||||
/* Add another rectangle to path c. It will be added in two halves,
|
||||
one as an extension of the previous path and the other as a new
|
||||
sub path */
|
||||
cogl_path_line_to (path_c, BLOCK_SIZE / 2, 0);
|
||||
cogl_path_line_to (path_c, BLOCK_SIZE * 3 / 4, 0);
|
||||
cogl_path_line_to (path_c, BLOCK_SIZE * 3 / 4, BLOCK_SIZE / 2);
|
||||
cogl_path_line_to (path_c, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
|
||||
cogl_path_rectangle (path_c,
|
||||
BLOCK_SIZE * 3 / 4, 0, BLOCK_SIZE, BLOCK_SIZE / 2);
|
||||
draw_path_at (path_c, white, 6, 0);
|
||||
|
||||
/* Draw the original path again. It should not have changed */
|
||||
draw_path_at (path_a, white, 7, 0);
|
||||
|
||||
cogl_object_unref (path_a);
|
||||
cogl_object_unref (path_b);
|
||||
cogl_object_unref (path_c);
|
||||
|
||||
/* Draw a self-intersecting path. The part that intersects should be
|
||||
inverted */
|
||||
path_a = cogl_path_new ();
|
||||
cogl_path_rectangle (path_a, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
|
||||
cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0);
|
||||
cogl_path_close (path_a);
|
||||
draw_path_at (path_a, white, 8, 0);
|
||||
cogl_object_unref (path_a);
|
||||
|
||||
/* Draw two sub paths. Where the paths intersect it should be
|
||||
inverted */
|
||||
path_a = cogl_path_new ();
|
||||
cogl_path_rectangle (path_a, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
|
||||
cogl_path_rectangle (path_a,
|
||||
BLOCK_SIZE / 2, BLOCK_SIZE / 2, BLOCK_SIZE, BLOCK_SIZE);
|
||||
draw_path_at (path_a, white, 9, 0);
|
||||
cogl_object_unref (path_a);
|
||||
|
||||
/* Draw a clockwise outer path */
|
||||
path_a = cogl_path_new ();
|
||||
cogl_path_move_to (path_a, 0, 0);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE, 0);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE, BLOCK_SIZE);
|
||||
cogl_path_line_to (path_a, 0, BLOCK_SIZE);
|
||||
cogl_path_close (path_a);
|
||||
/* Add a clockwise sub path in the upper left quadrant */
|
||||
cogl_path_move_to (path_a, 0, 0);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
|
||||
cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2);
|
||||
cogl_path_close (path_a);
|
||||
/* Add a counter-clockwise sub path in the upper right quadrant */
|
||||
cogl_path_move_to (path_a, BLOCK_SIZE / 2, 0);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE, BLOCK_SIZE / 2);
|
||||
cogl_path_line_to (path_a, BLOCK_SIZE, 0);
|
||||
cogl_path_close (path_a);
|
||||
/* Retain the path for the next test */
|
||||
draw_path_at (path_a, white, 10, 0);
|
||||
|
||||
/* Draw the same path again with the other fill rule */
|
||||
cogl_path_set_fill_rule (path_a, COGL_PATH_FILL_RULE_NON_ZERO);
|
||||
draw_path_at (path_a, white, 11, 0);
|
||||
|
||||
cogl_object_unref (path_a);
|
||||
}
|
||||
|
||||
static void
|
||||
validate_result (void)
|
||||
{
|
||||
check_block (0, 0, 0x8 /* bottom right */);
|
||||
check_block (1, 0, 0xf /* all of them */);
|
||||
check_block (2, 0, 0x8 /* bottom right */);
|
||||
check_block (3, 0, 0x8 /* bottom right */);
|
||||
check_block (4, 0, 0x9 /* top left and bottom right */);
|
||||
check_block (5, 0, 0x8 /* bottom right */);
|
||||
check_block (6, 0, 0xa /* bottom right and top right */);
|
||||
check_block (7, 0, 0x9 /* top_left and bottom right */);
|
||||
check_block (8, 0, 0xe /* all but top left */);
|
||||
check_block (9, 0, 0x7 /* all but bottom right */);
|
||||
check_block (10, 0, 0xc /* bottom two */);
|
||||
check_block (11, 0, 0xd /* all but top right */);
|
||||
}
|
||||
|
||||
void
|
||||
test_path (void)
|
||||
{
|
||||
TestState state;
|
||||
|
||||
cogl_framebuffer_orthographic (test_fb,
|
||||
0, 0,
|
||||
cogl_framebuffer_get_width (test_fb),
|
||||
cogl_framebuffer_get_height (test_fb),
|
||||
-1,
|
||||
100);
|
||||
|
||||
paint (&state);
|
||||
validate_result ();
|
||||
|
||||
if (cogl_test_verbose ())
|
||||
g_print ("OK\n");
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ libmutter_cogl_test_unit = executable('test-unit',
|
||||
include_directories: cogl_test_unit_includes,
|
||||
dependencies: [
|
||||
libmutter_cogl_dep,
|
||||
libmutter_cogl_path_dep,
|
||||
libmutter_cogl_test_fixtures_dep,
|
||||
],
|
||||
install: false,
|
||||
|
@ -70,3 +70,12 @@
|
||||
|
||||
/* Whether Xwayland has -initfd option */
|
||||
#mesondefine HAVE_XWAYLAND_INITFD
|
||||
|
||||
/* Whether the mkostemp function exists */
|
||||
#mesondefine HAVE_MKOSTEMP
|
||||
|
||||
/* Whether the posix_fallocate function exists */
|
||||
#mesondefine HAVE_POSIX_FALLOCATE
|
||||
|
||||
/* Whether the memfd_create function exists */
|
||||
#mesondefine HAVE_MEMFD_CREATE
|
||||
|
16
meson.build
16
meson.build
@ -1,5 +1,5 @@
|
||||
project('mutter', 'c',
|
||||
version: '3.36.1',
|
||||
version: '3.37.1',
|
||||
meson_version: '>= 0.50.0',
|
||||
license: 'GPLv2+'
|
||||
)
|
||||
@ -408,6 +408,20 @@ if have_wayland
|
||||
endif
|
||||
endif
|
||||
|
||||
optional_functions = [
|
||||
'mkostemp',
|
||||
'posix_fallocate',
|
||||
'memfd_create',
|
||||
]
|
||||
|
||||
foreach function : optional_functions
|
||||
if cc.has_function(function)
|
||||
cdata.set('HAVE_' + function.to_upper(), 1)
|
||||
else
|
||||
message('Optional function ' + function + ' missing')
|
||||
endif
|
||||
endforeach
|
||||
|
||||
xwayland_grab_default_access_rules = get_option('xwayland_grab_default_access_rules')
|
||||
cdata.set_quoted('XWAYLAND_GRAB_DEFAULT_ACCESS_RULES',
|
||||
xwayland_grab_default_access_rules)
|
||||
|
85
po/de.po
85
po/de.po
@ -13,8 +13,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mutter master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
|
||||
"POT-Creation-Date: 2019-08-06 00:49+0000\n"
|
||||
"PO-Revision-Date: 2019-09-05 23:42+0200\n"
|
||||
"POT-Creation-Date: 2020-03-30 20:11+0000\n"
|
||||
"PO-Revision-Date: 2020-04-06 23:13+0200\n"
|
||||
"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
|
||||
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
|
||||
"Language: de\n"
|
||||
@ -22,7 +22,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 2.2.1\n"
|
||||
"X-Generator: Poedit 2.3\n"
|
||||
|
||||
#: data/50-mutter-navigation.xml:6
|
||||
msgid "Navigation"
|
||||
@ -435,20 +435,33 @@ msgstr "Zusatztaste zum Finden des Zeigers"
|
||||
msgid "This key will initiate the “locate pointer” action."
|
||||
msgstr "Diese Taste wird die Aktion »Zeiger finden« auslösen."
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:155
|
||||
#: data/org.gnome.mutter.gschema.xml.in:142
|
||||
msgid "Timeout for check-alive ping"
|
||||
msgstr "Reaktionsschwellwert bei Kontaktkontrolle"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:143
|
||||
msgid ""
|
||||
"Number of milliseconds a client has to respond to a ping request in order to "
|
||||
"not be detected as frozen. Using 0 will disable the alive check completely."
|
||||
msgstr ""
|
||||
"Zeit in Millisekunden, innerhalb welcher ein Client auf eine "
|
||||
"Kontaktkontrolle antworten muss, um nicht als abgestürzt zu gelten. »0« "
|
||||
"bedeutet, dass die Kontaktkontrolle ausgeschaltet wird."
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:165
|
||||
msgid "Select window from tab popup"
|
||||
msgstr "Fenster aus Tab-Anzeige auswählen"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:160
|
||||
#: data/org.gnome.mutter.gschema.xml.in:170
|
||||
msgid "Cancel tab popup"
|
||||
msgstr "Tab-Anzeige abbrechen"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:165
|
||||
#: data/org.gnome.mutter.gschema.xml.in:175
|
||||
msgid "Switch monitor configurations"
|
||||
msgstr "Bildschirmkonfigurationen wechseln"
|
||||
|
||||
# Ich denke nicht, dass »rotate« hier die Bildschirmdrehung meint, sondern eher eine Liste aus Konfigurationen rotiert (d.h. umgewälzt) wird.
|
||||
#: data/org.gnome.mutter.gschema.xml.in:170
|
||||
#: data/org.gnome.mutter.gschema.xml.in:180
|
||||
msgid "Rotates the built-in monitor configuration"
|
||||
msgstr "Wechselt die Konfiguration des eingebauten Bildschirms"
|
||||
|
||||
@ -569,7 +582,7 @@ msgstr ""
|
||||
#. TRANSLATORS: This string refers to a button that switches between
|
||||
#. * different modes.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2531
|
||||
#: src/backends/meta-input-settings.c:2631
|
||||
#, c-format
|
||||
msgid "Mode Switch (Group %d)"
|
||||
msgstr "Moduswechsel (Gruppe %d)"
|
||||
@ -577,34 +590,34 @@ msgstr "Moduswechsel (Gruppe %d)"
|
||||
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
|
||||
#. * mapping through the available outputs.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2554
|
||||
#: src/backends/meta-input-settings.c:2654
|
||||
msgid "Switch monitor"
|
||||
msgstr "Bildschirm wechseln"
|
||||
|
||||
#: src/backends/meta-input-settings.c:2556
|
||||
#: src/backends/meta-input-settings.c:2656
|
||||
msgid "Show on-screen help"
|
||||
msgstr "Bildschirmhilfe anzeigen"
|
||||
|
||||
#: src/backends/meta-monitor.c:223
|
||||
#: src/backends/meta-monitor.c:226
|
||||
msgid "Built-in display"
|
||||
msgstr "Eingebaute Anzeige"
|
||||
|
||||
#: src/backends/meta-monitor.c:252
|
||||
#: src/backends/meta-monitor.c:255
|
||||
msgid "Unknown"
|
||||
msgstr "Unbekannt"
|
||||
|
||||
#: src/backends/meta-monitor.c:254
|
||||
#: src/backends/meta-monitor.c:257
|
||||
msgid "Unknown Display"
|
||||
msgstr "Unbekannte Anzeige"
|
||||
|
||||
#: src/backends/meta-monitor.c:262
|
||||
#: src/backends/meta-monitor.c:265
|
||||
#, c-format
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
|
||||
msgid "%s %s"
|
||||
msgstr "%s %s"
|
||||
|
||||
#: src/backends/meta-monitor.c:270
|
||||
#: src/backends/meta-monitor.c:273
|
||||
#, c-format
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name followed by product/model name where size in "
|
||||
@ -614,13 +627,13 @@ msgstr "%s %s"
|
||||
|
||||
# https://de.wikipedia.org/wiki/Composition-Manager
|
||||
#. Translators: this string will appear in Sysprof
|
||||
#: src/backends/meta-profiler.c:82
|
||||
#: src/backends/meta-profiler.c:79
|
||||
msgid "Compositor"
|
||||
msgstr "Compositor"
|
||||
|
||||
#. This probably means that a non-WM compositor like xcompmgr is running;
|
||||
#. * we have no way to get it to exit
|
||||
#: src/compositor/compositor.c:510
|
||||
#: src/compositor/compositor.c:533
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Another compositing manager is already running on screen %i on display “%s”."
|
||||
@ -632,47 +645,47 @@ msgstr ""
|
||||
msgid "Bell event"
|
||||
msgstr "Klangereignis"
|
||||
|
||||
#: src/core/main.c:185
|
||||
#: src/core/main.c:190
|
||||
msgid "Disable connection to session manager"
|
||||
msgstr "Verbindung zur Sitzungsverwaltung deaktivieren"
|
||||
|
||||
#: src/core/main.c:191
|
||||
#: src/core/main.c:196
|
||||
msgid "Replace the running window manager"
|
||||
msgstr "Den aktuellen Fensterverwalter ersetzen"
|
||||
|
||||
#: src/core/main.c:197
|
||||
#: src/core/main.c:202
|
||||
msgid "Specify session management ID"
|
||||
msgstr "Kennung der Sitzungsverwaltung angeben"
|
||||
|
||||
#: src/core/main.c:202
|
||||
#: src/core/main.c:207
|
||||
msgid "X Display to use"
|
||||
msgstr "Zu verwendende X-Anzeige"
|
||||
|
||||
#: src/core/main.c:208
|
||||
#: src/core/main.c:213
|
||||
msgid "Initialize session from savefile"
|
||||
msgstr "Sitzung anhand gespeicherter Datei starten"
|
||||
|
||||
#: src/core/main.c:214
|
||||
#: src/core/main.c:219
|
||||
msgid "Make X calls synchronous"
|
||||
msgstr "X-Aufrufe abgleichen"
|
||||
|
||||
#: src/core/main.c:221
|
||||
#: src/core/main.c:226
|
||||
msgid "Run as a wayland compositor"
|
||||
msgstr "Als Wayland-Compositor ausführen"
|
||||
|
||||
#: src/core/main.c:227
|
||||
#: src/core/main.c:232
|
||||
msgid "Run as a nested compositor"
|
||||
msgstr "Als eingebetteten Compositor ausführen"
|
||||
|
||||
#: src/core/main.c:233
|
||||
#: src/core/main.c:238
|
||||
msgid "Run wayland compositor without starting Xwayland"
|
||||
msgstr "Wayland-Compositor ausführen, ohne Xwayland zu starten"
|
||||
|
||||
#: src/core/main.c:241
|
||||
#: src/core/main.c:246
|
||||
msgid "Run as a full display server, rather than nested"
|
||||
msgstr "Als vollwertigen Display-Server verwenden (nicht eingebettet)"
|
||||
|
||||
#: src/core/main.c:247
|
||||
#: src/core/main.c:252
|
||||
msgid "Run with X11 backend"
|
||||
msgstr "Mit X11-Backend ausführen"
|
||||
|
||||
@ -728,21 +741,21 @@ msgstr "Version ausgeben"
|
||||
msgid "Mutter plugin to use"
|
||||
msgstr "Zu benutzendes Mutter-Plugin"
|
||||
|
||||
#: src/core/prefs.c:1849
|
||||
#: src/core/prefs.c:1911
|
||||
#, c-format
|
||||
msgid "Workspace %d"
|
||||
msgstr "Arbeitsfläche %d"
|
||||
|
||||
#: src/core/util.c:121
|
||||
#: src/core/util.c:122
|
||||
msgid "Mutter was compiled without support for verbose mode\n"
|
||||
msgstr "Mutter wurde ohne Unterstützung für den redseligen Modus kompiliert\n"
|
||||
|
||||
#: src/wayland/meta-wayland-tablet-pad.c:567
|
||||
#: src/wayland/meta-wayland-tablet-pad.c:568
|
||||
#, c-format
|
||||
msgid "Mode Switch: Mode %d"
|
||||
msgstr "Moduswechsel: Modus %d"
|
||||
|
||||
#: src/x11/meta-x11-display.c:671
|
||||
#: src/x11/meta-x11-display.c:676
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Display “%s” already has a window manager; try using the --replace option to "
|
||||
@ -751,21 +764,21 @@ msgstr ""
|
||||
"Bildschirm »%s« hat bereits einen Fensterverwalter. Versuchen Sie die Option "
|
||||
"»--replace«, um den aktuellen Fensterverwalter zu ersetzen."
|
||||
|
||||
#: src/x11/meta-x11-display.c:1032
|
||||
#: src/x11/meta-x11-display.c:1089
|
||||
msgid "Failed to initialize GDK\n"
|
||||
msgstr "GDK konnte nicht initialisiert werden\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1056
|
||||
#: src/x11/meta-x11-display.c:1113
|
||||
#, c-format
|
||||
msgid "Failed to open X Window System display “%s”\n"
|
||||
msgstr "X-Window-Systemanzeige »%s« konnte nicht geöffnet werden\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1140
|
||||
#: src/x11/meta-x11-display.c:1196
|
||||
#, c-format
|
||||
msgid "Screen %d on display “%s” is invalid\n"
|
||||
msgstr "Bildschirm %d auf Anzeige »%s« ist ungültig\n"
|
||||
|
||||
#: src/x11/meta-x11-selection-input-stream.c:445
|
||||
#: src/x11/meta-x11-selection-input-stream.c:460
|
||||
#, c-format
|
||||
msgid "Format %s not supported"
|
||||
msgstr "Format %s wird nicht unterstützt"
|
||||
|
167
po/sk.po
167
po/sk.po
@ -13,8 +13,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mutter\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
|
||||
"POT-Creation-Date: 2018-02-06 04:14+0000\n"
|
||||
"PO-Revision-Date: 2018-03-17 21:52+0100\n"
|
||||
"POT-Creation-Date: 2020-03-30 20:11+0000\n"
|
||||
"PO-Revision-Date: 2020-04-05 22:21+0200\n"
|
||||
"Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
|
||||
"Language-Team: Slovak <gnome-sk-list@gnome.org>\n"
|
||||
"Language: sk\n"
|
||||
@ -22,7 +22,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
"X-Generator: Poedit 2.3\n"
|
||||
|
||||
#: data/50-mutter-navigation.xml:6
|
||||
msgid "Navigation"
|
||||
@ -468,29 +468,47 @@ msgid ""
|
||||
"proof. Currently possible keywords: • “scale-monitor-framebuffer” — makes "
|
||||
"mutter default to layout logical monitors in a logical pixel coordinate "
|
||||
"space, while scaling monitor framebuffers instead of window content, to "
|
||||
"manage HiDPI monitors. Does not require a restart. • “remote-desktop” — "
|
||||
"enables remote desktop support. To support remote desktop with screen "
|
||||
"sharing, “screen-cast” must also be enabled. • “screen-cast” — enables "
|
||||
"screen cast support."
|
||||
"manage HiDPI monitors. Does not require a restart. • “rt-scheduler” — makes "
|
||||
"mutter request a low priority real-time scheduling. The executable or user "
|
||||
"must have CAP_SYS_NICE. Requires a restart. • “autostart-xwayland” — "
|
||||
"initializes Xwayland lazily if there are X11 clients. Requires restart."
|
||||
msgstr ""
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:134
|
||||
msgid "Modifier to use to locate the pointer"
|
||||
msgstr "Modifikátor použitý na lokalizovanie ukazovateľa"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:135
|
||||
msgid "This key will initiate the “locate pointer” action."
|
||||
msgstr ""
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:142
|
||||
msgid "Timeout for check-alive ping"
|
||||
msgstr ""
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:143
|
||||
msgid ""
|
||||
"Number of milliseconds a client has to respond to a ping request in order to "
|
||||
"not be detected as frozen. Using 0 will disable the alive check completely."
|
||||
msgstr ""
|
||||
|
||||
# summary
|
||||
#: data/org.gnome.mutter.gschema.xml.in:145
|
||||
#: data/org.gnome.mutter.gschema.xml.in:165
|
||||
msgid "Select window from tab popup"
|
||||
msgstr "Vybrať okno z rozbaľovacej ponuky tabulátora"
|
||||
|
||||
# summary
|
||||
#: data/org.gnome.mutter.gschema.xml.in:150
|
||||
#: data/org.gnome.mutter.gschema.xml.in:170
|
||||
msgid "Cancel tab popup"
|
||||
msgstr "Zrušit rozbaľovaciu ponuku tabulátora"
|
||||
|
||||
# PK: predpokladam ze to prepisane medzi tlacidlami
|
||||
# description
|
||||
#: data/org.gnome.mutter.gschema.xml.in:155
|
||||
#: data/org.gnome.mutter.gschema.xml.in:175
|
||||
msgid "Switch monitor configurations"
|
||||
msgstr "Prepnúť nastavenia monitorov"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:160
|
||||
#: data/org.gnome.mutter.gschema.xml.in:180
|
||||
msgid "Rotates the built-in monitor configuration"
|
||||
msgstr "Otočí nastavenie vstavaného monitora"
|
||||
|
||||
@ -554,23 +572,27 @@ msgid "Re-enable shortcuts"
|
||||
msgstr "Znovu povoliť klávesové skratky"
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:64
|
||||
msgid "Allow grabs with Xwayland"
|
||||
msgid "Allow X11 grabs to lock keyboard focus with Xwayland"
|
||||
msgstr ""
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:65
|
||||
msgid ""
|
||||
"Allow keyboard grabs issued by X11 applications running in Xwayland to be "
|
||||
"taken into account. For a X11 grab to be taken into account under Wayland, "
|
||||
"the client must also either send a specific X11 ClientMessage to the root "
|
||||
"window or be among the applications white-listed in key “xwayland-grab-"
|
||||
"access-rules”."
|
||||
"Allow all keyboard events to be routed to X11 “override redirect” windows "
|
||||
"with a grab when running in Xwayland. This option is to support X11 clients "
|
||||
"which map an “override redirect” window (which do not receive keyboard "
|
||||
"focus) and issue a keyboard grab to force all keyboard events to that "
|
||||
"window. This option is seldom used and has no effect on regular X11 windows "
|
||||
"which can receive keyboard focus under normal circumstances. For a X11 grab "
|
||||
"to be taken into account under Wayland, the client must also either send a "
|
||||
"specific X11 ClientMessage to the root window or be among the applications "
|
||||
"white-listed in key “xwayland-grab-access-rules”."
|
||||
msgstr ""
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:77
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:84
|
||||
msgid "Xwayland applications allowed to issue keyboard grabs"
|
||||
msgstr ""
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:78
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:85
|
||||
msgid ""
|
||||
"List the resource names or resource class of X11 windows either allowed or "
|
||||
"not allowed to issue X11 keyboard grabs under Xwayland. The resource name or "
|
||||
@ -587,7 +609,7 @@ msgstr ""
|
||||
#. TRANSLATORS: This string refers to a button that switches between
|
||||
#. * different modes.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2260
|
||||
#: src/backends/meta-input-settings.c:2631
|
||||
#, c-format
|
||||
msgid "Mode Switch (Group %d)"
|
||||
msgstr "Prepínač režimu (skupina č. %d)"
|
||||
@ -597,53 +619,61 @@ msgstr "Prepínač režimu (skupina č. %d)"
|
||||
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
|
||||
#. * mapping through the available outputs.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2283
|
||||
#: src/backends/meta-input-settings.c:2654
|
||||
msgid "Switch monitor"
|
||||
msgstr "Prepnúť monitor"
|
||||
|
||||
#: src/backends/meta-input-settings.c:2285
|
||||
#: src/backends/meta-input-settings.c:2656
|
||||
msgid "Show on-screen help"
|
||||
msgstr "Zobraziť pomocníka na obrazovke"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:900
|
||||
#: src/backends/meta-monitor.c:226
|
||||
msgid "Built-in display"
|
||||
msgstr "Vstavaný displej"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:923
|
||||
#: src/backends/meta-monitor.c:255
|
||||
msgid "Unknown"
|
||||
msgstr "Neznámy"
|
||||
|
||||
#: src/backends/meta-monitor-manager.c:925
|
||||
#: src/backends/meta-monitor.c:257
|
||||
msgid "Unknown Display"
|
||||
msgstr "Neznámy displej"
|
||||
|
||||
#. TRANSLATORS: this is a monitor vendor name, followed by a
|
||||
#. * size in inches, like 'Dell 15"'
|
||||
#.
|
||||
#: src/backends/meta-monitor-manager.c:933
|
||||
#: src/backends/meta-monitor.c:265
|
||||
#, c-format
|
||||
#| msgid "%s %s"
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
|
||||
msgid "%s %s"
|
||||
msgstr "%s %s"
|
||||
|
||||
#: src/backends/meta-monitor.c:273
|
||||
#, c-format
|
||||
#| msgid "%s %s"
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name followed by product/model name where size in "
|
||||
"inches could not be calculated, e.g. Dell U2414H"
|
||||
msgid "%s %s"
|
||||
msgstr "%s %s"
|
||||
|
||||
#. Translators: this string will appear in Sysprof
|
||||
#: src/backends/meta-profiler.c:79
|
||||
msgid "Compositor"
|
||||
msgstr "Kompozítor"
|
||||
|
||||
#. This probably means that a non-WM compositor like xcompmgr is running;
|
||||
#. * we have no way to get it to exit
|
||||
#: src/compositor/compositor.c:481
|
||||
#: src/compositor/compositor.c:533
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Another compositing manager is already running on screen %i on display “%s”."
|
||||
msgstr ""
|
||||
"Pre obrazovku č. %i na displeji „%s“ je spustený už iný správca rozloženia."
|
||||
|
||||
#: src/core/bell.c:194
|
||||
#: src/core/bell.c:192
|
||||
msgid "Bell event"
|
||||
msgstr "Udalosť zvončeka"
|
||||
|
||||
# X window system preloz, napr. system na spravu okien X
|
||||
#: src/core/display.c:608
|
||||
#, c-format
|
||||
msgid "Failed to open X Window System display “%s”\n"
|
||||
msgstr "Zlyhalo otvorenie displeja systému na správu okien X „%s“\n"
|
||||
|
||||
# cmd desc
|
||||
#: src/core/main.c:190
|
||||
msgid "Disable connection to session manager"
|
||||
@ -683,41 +713,45 @@ msgstr "Spustí ako kompozitor protokolu wayland"
|
||||
msgid "Run as a nested compositor"
|
||||
msgstr "Spustí ako kompozitor s vnoreným režimom"
|
||||
|
||||
#: src/core/main.c:240
|
||||
#: src/core/main.c:238
|
||||
msgid "Run wayland compositor without starting Xwayland"
|
||||
msgstr ""
|
||||
|
||||
#: src/core/main.c:246
|
||||
msgid "Run as a full display server, rather than nested"
|
||||
msgstr "Spustí ako plnohodnotný zobrazovací server, namiesto vnoreného režimu"
|
||||
|
||||
#: src/core/main.c:246
|
||||
#: src/core/main.c:252
|
||||
msgid "Run with X11 backend"
|
||||
msgstr "Spustí s obslužným programom X11"
|
||||
|
||||
# %s is a window title
|
||||
#. Translators: %s is a window title
|
||||
#: src/core/meta-close-dialog-default.c:147
|
||||
#: src/core/meta-close-dialog-default.c:151
|
||||
#, c-format
|
||||
msgid "“%s” is not responding."
|
||||
msgstr "„%s“ neodpovedá."
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:149
|
||||
#: src/core/meta-close-dialog-default.c:153
|
||||
msgid "Application is not responding."
|
||||
msgstr "Aplikácia neodpovedá."
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:154
|
||||
#: src/core/meta-close-dialog-default.c:158
|
||||
msgid ""
|
||||
"You may choose to wait a short while for it to continue or force the "
|
||||
"application to quit entirely."
|
||||
msgstr ""
|
||||
"Môžete chvíľu počkať na pokračovanie aplikácie, alebo ju môžete ukončiť."
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:161
|
||||
#: src/core/meta-close-dialog-default.c:165
|
||||
msgid "_Force Quit"
|
||||
msgstr "_Vynútiť ukončenie"
|
||||
|
||||
#: src/core/meta-close-dialog-default.c:161
|
||||
#: src/core/meta-close-dialog-default.c:165
|
||||
msgid "_Wait"
|
||||
msgstr "_Počkať"
|
||||
|
||||
#: src/core/mutter.c:39
|
||||
#: src/core/mutter.c:38
|
||||
#, c-format
|
||||
msgid ""
|
||||
"mutter %s\n"
|
||||
@ -733,21 +767,30 @@ msgstr ""
|
||||
"Záruka sa NEPOSKYTUJE; ani na PREDAJNOSŤ alebo VHODNOSŤ PRE URČITÝ ÚČEL.\n"
|
||||
|
||||
# cmd desc
|
||||
#: src/core/mutter.c:53
|
||||
#: src/core/mutter.c:52
|
||||
msgid "Print version"
|
||||
msgstr "Zobrazí verziu"
|
||||
|
||||
# cmd desc
|
||||
#: src/core/mutter.c:59
|
||||
#: src/core/mutter.c:58
|
||||
msgid "Mutter plugin to use"
|
||||
msgstr "Použije zásuvný modul Mutter"
|
||||
|
||||
#: src/core/prefs.c:1997
|
||||
#: src/core/prefs.c:1911
|
||||
#, c-format
|
||||
msgid "Workspace %d"
|
||||
msgstr "Pracovný priestor č. %d"
|
||||
|
||||
#: src/core/screen.c:583
|
||||
#: src/core/util.c:122
|
||||
msgid "Mutter was compiled without support for verbose mode\n"
|
||||
msgstr "Mutter bol skompilovaný bez výpisu podrobností pri behu\n"
|
||||
|
||||
#: src/wayland/meta-wayland-tablet-pad.c:568
|
||||
#, c-format
|
||||
msgid "Mode Switch: Mode %d"
|
||||
msgstr "Prepínač režimu: Režim č. %d"
|
||||
|
||||
#: src/x11/meta-x11-display.c:676
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Display “%s” already has a window manager; try using the --replace option to "
|
||||
@ -756,21 +799,27 @@ msgstr ""
|
||||
"Displej „%s“ už má správcu okien. Skúste použiť prepínač --replace, aby sa "
|
||||
"aktuálny správca nahradil."
|
||||
|
||||
#: src/core/screen.c:668
|
||||
#: src/x11/meta-x11-display.c:1089
|
||||
msgid "Failed to initialize GDK\n"
|
||||
msgstr "Zlyhala inicializácia GDK\n"
|
||||
|
||||
# X window system preloz, napr. system na spravu okien X
|
||||
#: src/x11/meta-x11-display.c:1113
|
||||
#, c-format
|
||||
msgid "Failed to open X Window System display “%s”\n"
|
||||
msgstr "Zlyhalo otvorenie displeja systému na správu okien X „%s“\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1196
|
||||
#, c-format
|
||||
msgid "Screen %d on display “%s” is invalid\n"
|
||||
msgstr "Obrazovka č. %d na displeji „%s“ nie je platná\n"
|
||||
|
||||
#: src/core/util.c:120
|
||||
msgid "Mutter was compiled without support for verbose mode\n"
|
||||
msgstr "Mutter bol skompilovaný bez výpisu podrobností pri behu\n"
|
||||
|
||||
#: src/wayland/meta-wayland-tablet-pad.c:563
|
||||
#: src/x11/meta-x11-selection-input-stream.c:460
|
||||
#, c-format
|
||||
msgid "Mode Switch: Mode %d"
|
||||
msgstr "Prepínač režimu: Režim č. %d"
|
||||
msgid "Format %s not supported"
|
||||
msgstr "Formát %s nie je podporovaný"
|
||||
|
||||
#: src/x11/session.c:1818
|
||||
#: src/x11/session.c:1821
|
||||
msgid ""
|
||||
"These windows do not support “save current setup” and will have to be "
|
||||
"restarted manually next time you log in."
|
||||
@ -779,7 +828,7 @@ msgstr ""
|
||||
"prihlásení ich budete musieť znovu spustiť ručne."
|
||||
|
||||
# window title; wm_client_machine
|
||||
#: src/x11/window-props.c:559
|
||||
#: src/x11/window-props.c:569
|
||||
#, c-format
|
||||
msgid "%s (on %s)"
|
||||
msgstr "%s (na %s)"
|
||||
|
@ -49,6 +49,7 @@ typedef struct _MetaTileInfo MetaTileInfo;
|
||||
typedef struct _MetaRenderer MetaRenderer;
|
||||
typedef struct _MetaRendererView MetaRendererView;
|
||||
|
||||
typedef struct _MetaRemoteDesktop MetaRemoteDesktop;
|
||||
typedef struct _MetaScreenCast MetaScreenCast;
|
||||
typedef struct _MetaScreenCastSession MetaScreenCastSession;
|
||||
typedef struct _MetaScreenCastStream MetaScreenCastStream;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user