Compare commits
350 Commits
wip/cherge
...
wip/lantw/
Author | SHA1 | Date | |
---|---|---|---|
af0478ae1e | |||
aedf692e0c | |||
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 | |||
52e5d6fc94 | |||
09a6031c69 | |||
dbe919ef92 | |||
2907ee93cc | |||
aa136f4515 | |||
8748841094 | |||
86f2885e98 | |||
bb5ea0580f | |||
2cfdbbd730 | |||
9f31e7252c | |||
e8ea5ecd8a | |||
ed10aea44d | |||
fed5f4d9aa | |||
73250b8f4c | |||
f6700f19a7 | |||
ea34915df3 | |||
37742c5cde | |||
cdd27d0e53 | |||
82778f72a4 | |||
d846fabda2 | |||
2d94a34a14 | |||
92710d8f89 | |||
da600b8400 | |||
6aa546145f | |||
3956ffd5e8 | |||
05341221d4 | |||
95642d05a6 | |||
51cd8aed96 | |||
ac01e69a67 | |||
a68e6972a2 | |||
55cf1c1496 | |||
343de21af5 | |||
3c157242fa | |||
32c99513c8 | |||
40c345d6f3 | |||
8beef8ccd0 | |||
62d0dd907b | |||
0462208d4e | |||
6885c37784 | |||
238e41d493 | |||
8699482475 | |||
dcaa45fc0c | |||
3c4f5ddcb4 | |||
3aece84499 | |||
40fb06ca17 | |||
d4c070da88 | |||
d052f9c070 | |||
3b88af94e3 | |||
1f00aba92c | |||
ec1195e3ff | |||
18b661cc93 | |||
8592a8591b | |||
7fa7c2aeb7 | |||
41130b08eb | |||
1d20045247 | |||
c131a9b7fa | |||
2ecbf6d746 | |||
a13d60aae5 | |||
ed4b80cee5 | |||
0a6034ef3a | |||
c9a5b2b22f | |||
db9b60cc63 | |||
fa74da0039 | |||
b310e1d9d7 | |||
0053ef2e16 | |||
4133b73632 | |||
074f4974dd | |||
0700f3749f | |||
0487e6f11f | |||
23da6c2426 | |||
67dd0b4fec | |||
6989fea767 | |||
df33255162 | |||
5319949a45 | |||
aba0b9ef64 | |||
512bb7d1cd | |||
d2a12ee0fa | |||
531a195cf1 | |||
509e9ca5a0 | |||
0743381573 | |||
267f712068 | |||
0b102afb53 | |||
304a103659 | |||
2d09e95934 | |||
be11525b28 | |||
adc38f902a | |||
8abdf16a39 | |||
4cc29cfb61 | |||
121c5d2a92 | |||
50ff30bf2b | |||
26e1e495a0 | |||
480e7d44be | |||
1c1adb0036 | |||
6b852e6cb3 | |||
6e966e47f2 | |||
227eea1e31 | |||
79920d66d4 | |||
6cd0aa429f | |||
15d3de0099 | |||
38fb59a6a6 | |||
748f5bb3e6 | |||
3c55475391 | |||
dd6e371bac | |||
00d900e46d | |||
a4f11bef47 | |||
c4f76622a6 | |||
f80e5dd8e4 | |||
f484efaac1 | |||
f97804f4f4 | |||
5c37f5104e | |||
d08a8de265 | |||
6c82feb1b8 | |||
0dac91cffc | |||
ff381d1d52 | |||
05e9d6ab9e | |||
d22f947bf5 | |||
9b97e5ed58 | |||
7f9fac2ba2 | |||
64eaf70279 | |||
e3149e6021 | |||
166a464515 | |||
38e58b837b | |||
39a8c047d1 | |||
c979cd95aa | |||
6831f2edb4 | |||
372d73e275 | |||
0ada90024f | |||
46e38ff61a | |||
1e0b015ce8 | |||
72054332c5 | |||
d30ef0dd3b | |||
84275688f3 | |||
90a1eb4275 | |||
73e3207a85 | |||
8a6673bb55 | |||
35c16a9f4b | |||
390fd7ddcf | |||
4b513a31ae | |||
25c9e66c73 | |||
649911b6b3 | |||
8c332a4704 | |||
21994bb00d | |||
87a06c63ad | |||
09026e5f0e | |||
1f190a7cfe | |||
86168b945c | |||
680a54aff6 | |||
548073ec27 | |||
d366fb335d | |||
7fbb47b2bb | |||
3881c1f952 | |||
038a3170bf | |||
f27de9620a | |||
969ad54feb | |||
987ce5bec0 | |||
d600cd9aee | |||
1fc7935858 | |||
b5354fb3cd | |||
01aaced129 | |||
ff59b5d041 | |||
92f0eb9d14 | |||
e6913d1471 | |||
d495dc6c63 | |||
88bb24f66e | |||
6e7316ef11 | |||
9fa56176fd | |||
fb81199dec | |||
b7f47ea17f | |||
71101cab82 | |||
c4b28b0939 | |||
38954de11c | |||
964ea60090 | |||
159c83b914 | |||
b68c630329 | |||
fe1ccea1e1 | |||
c483b52d24 | |||
f3dcba27f5 | |||
86ccc28413 | |||
0d039c3ba3 | |||
adcbc2aa5f | |||
860906246e | |||
37d7df612b | |||
0baf4578c8 | |||
2d6665950c | |||
1c98f01a65 | |||
e3f30371aa | |||
1a14c4d3c9 | |||
292d2754ae | |||
fe42d56db3 | |||
a11f9bd513 | |||
7f6cafa847 | |||
1b67f49f7f | |||
c447d76cd4 | |||
d327cedb83 | |||
0c55e87d8f | |||
81d11ac0a8 | |||
84261d1db3 | |||
a0441ad666 | |||
67152916e1 | |||
b98ebe60b2 | |||
ad8ba69423 | |||
bf24b816c2 | |||
a9b1134dfb | |||
6fb6a23389 | |||
2da27720ca | |||
f9326cfa3d | |||
963108a9a6 | |||
b8355a6686 | |||
4c421959dc | |||
aedcfcd010 | |||
d7c7311ceb | |||
41d72e86e0 | |||
282b09c17e | |||
c5d2fc856a | |||
f5a28aa9e4 | |||
6206511846 | |||
a209a14898 | |||
3e6a55aff0 | |||
704fea6323 | |||
8c1e6ebde0 | |||
81512ad0dc | |||
d122b66abc |
@ -1,4 +1,4 @@
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||
|
||||
stages:
|
||||
- review
|
||||
@ -28,6 +28,20 @@ build-mutter:
|
||||
- merge_requests
|
||||
- /^.*$/
|
||||
|
||||
build-without-opengl-and-glx:
|
||||
stage: build
|
||||
script:
|
||||
- meson . build -Dbuildtype=debugoptimized -Dopengl=false -Dglx=false -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
|
||||
- ninja -C build
|
||||
- ninja -C build install
|
||||
artifacts:
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- build
|
||||
only:
|
||||
- merge_requests
|
||||
- /^.*$/
|
||||
|
||||
build-without-native-backend-and-wayland:
|
||||
stage: build
|
||||
script:
|
||||
|
@ -1,29 +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 -y update && dnf -y upgrade && \
|
||||
dnf copr enable -y jadahl/mutter-ci && \
|
||||
|
||||
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 clean all
|
||||
|
@ -19,7 +19,7 @@ fi
|
||||
function commit_message_has_url() {
|
||||
commit=$1
|
||||
commit_message=$(git show -s --format='format:%b' $commit)
|
||||
echo "$commit_message" | grep -qe "\($CI_MERGE_REQUEST_PROJECT_URL/\(issues\|merge_requests\)/[0-9]\+\|https://bugzilla.gnome.org/show_bug.cgi?id=[0-9]\+\)"
|
||||
echo "$commit_message" | grep -qe "\($CI_MERGE_REQUEST_PROJECT_URL/\(-/\)\?\(issues\|merge_requests\)/[0-9]\+\|https://bugzilla.gnome.org/show_bug.cgi?id=[0-9]\+\)"
|
||||
return $?
|
||||
}
|
||||
|
||||
|
85
NEWS
85
NEWS
@ -1,3 +1,88 @@
|
||||
3.37.1
|
||||
======
|
||||
* 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:
|
||||
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:
|
||||
Dušan Kazik [sk], Christian Kirbach [de]
|
||||
|
||||
3.36.0
|
||||
======
|
||||
* Fix placement of popup windows in multi-monitor setups [Jonas; !1110]
|
||||
* Fix invisible mouse cursor on some hardware [Jonas; !1079]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl
|
||||
|
||||
Translators:
|
||||
Aurimas Černius [lt], Goran Vidović [hr], Anders Jonsson [sv],
|
||||
Guillaume Bernard [fr], Milo Casagrande [it], Daniel Korostil [uk],
|
||||
Andre Klapper [cy], Aman Alam [pa], Nathan Follens [nl]
|
||||
|
||||
3.35.92
|
||||
=======
|
||||
* Fix visibility of initially hidden windows [Jonas Å.; !1066]
|
||||
* Avoid flicker when (un)redirecting windows [Sebastian; #997]
|
||||
* Let BindConstraints update the preferred size [Emmanuele; !1070]
|
||||
* Learn about GLES3 [Adam; !882]
|
||||
* Ping windows on every window focus [Jonas D.; !891]
|
||||
* Remove overhead from hot code paths [Christian;
|
||||
#1056, !1081, !1083, !1071, !1087]
|
||||
* Allow remote desktop services to inhibit animations [Jonas Å.; !838]
|
||||
* Update screen-cast code to PipeWire 0.3 API [Wim; !1062]
|
||||
* Make check-alive timeouts configurable [Jonas Å.; !1080]
|
||||
* Make each stage view correspond to a single CRTC [Jonas Å.; !1042]
|
||||
* Implement scaled/transformed hardware cursors [Robert; !526]
|
||||
* Use DMA buffers for screencasting if possible [Georges; !1086]
|
||||
* Make Xwayland startup asynchronous [Carlos; !944]
|
||||
* Fix clipping glitches in long text entries [Jonas D.; !1096]
|
||||
* Add side channel for starting required X11 services [Carlos; !945]
|
||||
* Support synchronized wayland popup moving [Jonas Å.; !705]
|
||||
* Fixed crashes [Olivier, Jonas Å.; !1073, !1093]
|
||||
* Plugged memory leaks [Sebastian, Jonas Å.; !1089, !1095]
|
||||
* Misc. bug fixes and cleanups [Jonas Å, Olivier, Florian, Daniel, Jonas D.,
|
||||
Robert, Sebastian, Christian, Arun, Carlos, worldofpeace; !1061, #1043,
|
||||
!1067, !1068, !1065, !835, !1058, !1069, !1075, #1060, !1077, !423, !1090,
|
||||
!1088, !1094, #1067, !1064, !1099, !957, !1000, !1082]
|
||||
|
||||
Contributors:
|
||||
Emmanuele Bassi, Jonas Dreßler, Olivier Fourdan, Carlos Garnacho,
|
||||
Christian Hergert, Adam Jackson, Sebastian Keller, Robert Mader,
|
||||
Florian Müllner, Georges Basile Stavracas Neto, Arun Raghavan, Wim Taymans,
|
||||
Daniel van Vugt, worldofpeace, Jonas Ådahl
|
||||
|
||||
Translators:
|
||||
Yi-Jyun Pan [zh_TW], Asier Sarasua Garmendia [eu], Rafael Fontenelle [pt_BR],
|
||||
Emin Tufan Çetin [tr], Daniel Mustieles [es], Balázs Úr [hu],
|
||||
Gwan-gyeong Mun [ko], Marek Černocký [cs], Fran Dieguez [gl],
|
||||
Kukuh Syafaat [id], Alan Mortensen [da], Piotr Drąg [pl], sicklylife [ja],
|
||||
Matej Urbančič [sl]
|
||||
|
||||
3.35.91
|
||||
=======
|
||||
* Honor accelerometer orientation on monitor config changes [Hans; !959]
|
||||
|
@ -600,10 +600,11 @@ cally_actor_real_remove_actor (ClutterActor *container,
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0);
|
||||
|
||||
atk_parent = ATK_OBJECT (data);
|
||||
atk_child = clutter_actor_get_accessible (actor);
|
||||
|
||||
if (atk_child)
|
||||
if (clutter_actor_has_accessible (actor))
|
||||
{
|
||||
atk_child = clutter_actor_get_accessible (actor);
|
||||
|
||||
g_value_init (&values.old_value, G_TYPE_POINTER);
|
||||
g_value_set_pointer (&values.old_value, atk_parent);
|
||||
|
||||
|
@ -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
|
||||
|
@ -631,7 +631,7 @@
|
||||
#include "clutter-color-static.h"
|
||||
#include "clutter-color.h"
|
||||
#include "clutter-constraint-private.h"
|
||||
#include "clutter-container.h"
|
||||
#include "clutter-container-private.h"
|
||||
#include "clutter-content-private.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-easing.h"
|
||||
@ -710,6 +710,7 @@ struct _ClutterActorPrivate
|
||||
|
||||
guint8 opacity;
|
||||
gint opacity_override;
|
||||
unsigned int inhibit_culling_counter;
|
||||
|
||||
ClutterOffscreenRedirect offscreen_redirect;
|
||||
|
||||
@ -1124,6 +1125,20 @@ static GQuark quark_actor_layout_info = 0;
|
||||
static GQuark quark_actor_transform_info = 0;
|
||||
static GQuark quark_actor_animation_info = 0;
|
||||
|
||||
static GQuark quark_key = 0;
|
||||
static GQuark quark_motion = 0;
|
||||
static GQuark quark_pointer_focus = 0;
|
||||
static GQuark quark_button = 0;
|
||||
static GQuark quark_scroll = 0;
|
||||
static GQuark quark_stage = 0;
|
||||
static GQuark quark_destroy = 0;
|
||||
static GQuark quark_client = 0;
|
||||
static GQuark quark_delete = 0;
|
||||
static GQuark quark_touch = 0;
|
||||
static GQuark quark_touchpad = 0;
|
||||
static GQuark quark_proximity = 0;
|
||||
static GQuark quark_pad = 0;
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (ClutterActor,
|
||||
clutter_actor,
|
||||
G_TYPE_INITIALLY_UNOWNED,
|
||||
@ -2395,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;
|
||||
@ -3474,8 +3490,8 @@ _clutter_actor_draw_paint_volume_full (ClutterActor *self,
|
||||
cogl_pipeline_set_color (outline, &cogl_color);
|
||||
|
||||
pipeline_node = clutter_pipeline_node_new (outline);
|
||||
clutter_paint_node_set_name (pipeline_node,
|
||||
"ClutterActor (paint volume outline)");
|
||||
clutter_paint_node_set_static_name (pipeline_node,
|
||||
"ClutterActor (paint volume outline)");
|
||||
clutter_paint_node_add_primitive (pipeline_node, prim);
|
||||
clutter_paint_node_add_child (node, pipeline_node);
|
||||
cogl_object_unref (prim);
|
||||
@ -3489,8 +3505,8 @@ _clutter_actor_draw_paint_volume_full (ClutterActor *self,
|
||||
pango_layout_set_text (layout, label, -1);
|
||||
|
||||
text_node = clutter_text_node_new (layout, color);
|
||||
clutter_paint_node_set_name (text_node,
|
||||
"ClutterActor (paint volume label)");
|
||||
clutter_paint_node_set_static_name (text_node,
|
||||
"ClutterActor (paint volume label)");
|
||||
clutter_paint_node_add_rectangle (text_node,
|
||||
&(ClutterActorBox) {
|
||||
.x1 = pv->vertices[0].x,
|
||||
@ -3586,8 +3602,8 @@ _clutter_actor_paint_cull_result (ClutterActor *self,
|
||||
pango_layout_set_text (layout, label, -1);
|
||||
|
||||
text_node = clutter_text_node_new (layout, &color);
|
||||
clutter_paint_node_set_name (text_node,
|
||||
"ClutterActor (paint volume text)");
|
||||
clutter_paint_node_set_static_name (text_node,
|
||||
"ClutterActor (paint volume text)");
|
||||
clutter_paint_node_add_rectangle (text_node,
|
||||
&(ClutterActorBox) {
|
||||
.x1 = 0.f,
|
||||
@ -3743,7 +3759,13 @@ needs_flatten_effect (ClutterActor *self)
|
||||
CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
|
||||
return FALSE;
|
||||
|
||||
if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
|
||||
/* We need to enable the effect immediately even in ON_IDLE because that can
|
||||
* only be implemented efficiently within the effect itself.
|
||||
* If it was implemented here using just priv->is_dirty then we would lose
|
||||
* the ability to animate opacity without repaints.
|
||||
*/
|
||||
if ((priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS) ||
|
||||
(priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE))
|
||||
return TRUE;
|
||||
else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
|
||||
{
|
||||
@ -3844,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,
|
||||
@ -3862,7 +3877,7 @@ clutter_actor_paint_node (ClutterActor *actor,
|
||||
clear_flags = COGL_BUFFER_BIT_DEPTH;
|
||||
|
||||
node = clutter_root_node_new (fb, &bg_color, clear_flags);
|
||||
clutter_paint_node_set_name (node, "stageClear");
|
||||
clutter_paint_node_set_static_name (node, "stageClear");
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
clutter_paint_node_add_child (root, node);
|
||||
clutter_paint_node_unref (node);
|
||||
@ -3877,7 +3892,7 @@ clutter_actor_paint_node (ClutterActor *actor,
|
||||
/ 255;
|
||||
|
||||
node = clutter_color_node_new (&bg_color);
|
||||
clutter_paint_node_set_name (node, "backgroundColor");
|
||||
clutter_paint_node_set_static_name (node, "backgroundColor");
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
clutter_paint_node_add_child (root, node);
|
||||
clutter_paint_node_unref (node);
|
||||
@ -3931,6 +3946,7 @@ clutter_actor_paint (ClutterActor *self,
|
||||
g_autoptr (ClutterPaintNode) root_node = NULL;
|
||||
ClutterActorPrivate *priv;
|
||||
ClutterActorBox clip;
|
||||
gboolean culling_inhibited;
|
||||
gboolean clip_set = FALSE;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
||||
@ -3997,11 +4013,14 @@ clutter_actor_paint (ClutterActor *self,
|
||||
|
||||
clutter_actor_get_transform (self, &transform);
|
||||
|
||||
transform_node = clutter_transform_node_new (&transform);
|
||||
clutter_paint_node_add_child (transform_node, root_node);
|
||||
clutter_paint_node_unref (root_node);
|
||||
if (!cogl_matrix_is_identity (&transform))
|
||||
{
|
||||
transform_node = clutter_transform_node_new (&transform);
|
||||
clutter_paint_node_add_child (transform_node, root_node);
|
||||
clutter_paint_node_unref (root_node);
|
||||
|
||||
root_node = g_steal_pointer (&transform_node);
|
||||
root_node = g_steal_pointer (&transform_node);
|
||||
}
|
||||
|
||||
#ifdef CLUTTER_ENABLE_DEBUG
|
||||
/* Catch when out-of-band transforms have been made by actors not as part
|
||||
@ -4076,7 +4095,8 @@ clutter_actor_paint (ClutterActor *self,
|
||||
* paint then the last-paint-volume would likely represent the new
|
||||
* actor position not the old.
|
||||
*/
|
||||
if (!in_clone_paint ())
|
||||
culling_inhibited = priv->inhibit_culling_counter > 0;
|
||||
if (!culling_inhibited && !in_clone_paint ())
|
||||
{
|
||||
gboolean success;
|
||||
/* annoyingly gcc warns if uninitialized even though
|
||||
@ -4158,7 +4178,7 @@ clutter_actor_continue_paint (ClutterActor *self,
|
||||
*/
|
||||
framebuffer = clutter_paint_context_get_base_framebuffer (paint_context);
|
||||
dummy = _clutter_dummy_node_new (self, framebuffer);
|
||||
clutter_paint_node_set_name (dummy, "Root");
|
||||
clutter_paint_node_set_static_name (dummy, "Root");
|
||||
|
||||
/* XXX - for 1.12, we use the return value of paint_node() to
|
||||
* decide whether we should emit the ::paint signal.
|
||||
@ -4198,6 +4218,11 @@ clutter_actor_continue_paint (ClutterActor *self,
|
||||
run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
|
||||
}
|
||||
|
||||
if (priv->current_effect == priv->flatten_effect &&
|
||||
priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE &&
|
||||
run_flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY)
|
||||
run_flags |= CLUTTER_EFFECT_PAINT_BYPASS_EFFECT;
|
||||
|
||||
_clutter_effect_paint (priv->current_effect, paint_context, run_flags);
|
||||
|
||||
priv->current_effect = old_current_effect;
|
||||
@ -4568,7 +4593,7 @@ clutter_actor_remove_child_internal (ClutterActor *self,
|
||||
|
||||
/* we need to emit the signal before dropping the reference */
|
||||
if (emit_actor_removed)
|
||||
g_signal_emit_by_name (self, "actor-removed", child);
|
||||
_clutter_container_emit_actor_removed (CLUTTER_CONTAINER (self), child);
|
||||
|
||||
if (notify_first_last)
|
||||
{
|
||||
@ -6531,6 +6556,20 @@ clutter_actor_class_init (ClutterActorClass *klass)
|
||||
quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
|
||||
quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
|
||||
|
||||
quark_key = g_quark_from_static_string ("key");
|
||||
quark_motion = g_quark_from_static_string ("motion");
|
||||
quark_pointer_focus = g_quark_from_static_string ("pointer-focus");
|
||||
quark_button = g_quark_from_static_string ("button");
|
||||
quark_scroll = g_quark_from_static_string ("scroll");
|
||||
quark_stage = g_quark_from_static_string ("stage");
|
||||
quark_destroy = g_quark_from_static_string ("destroy");
|
||||
quark_client = g_quark_from_static_string ("client");
|
||||
quark_delete = g_quark_from_static_string ("delete");
|
||||
quark_touch = g_quark_from_static_string ("touch");
|
||||
quark_touchpad = g_quark_from_static_string ("touchpad");
|
||||
quark_proximity = g_quark_from_static_string ("proximity");
|
||||
quark_pad = g_quark_from_static_string ("pad");
|
||||
|
||||
object_class->constructor = clutter_actor_constructor;
|
||||
object_class->set_property = clutter_actor_set_property;
|
||||
object_class->get_property = clutter_actor_get_property;
|
||||
@ -8566,7 +8605,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
|
||||
actor_signals[CAPTURED_EVENT] =
|
||||
g_signal_new (I_("captured-event"),
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
||||
G_STRUCT_OFFSET (ClutterActorClass, captured_event),
|
||||
_clutter_boolean_handled_accumulator, NULL,
|
||||
_clutter_marshal_BOOLEAN__BOXED,
|
||||
@ -13212,7 +13251,7 @@ clutter_actor_add_child_internal (ClutterActor *self,
|
||||
}
|
||||
|
||||
if (emit_actor_added)
|
||||
g_signal_emit_by_name (self, "actor-added", child);
|
||||
_clutter_container_emit_actor_added (CLUTTER_CONTAINER (self), child);
|
||||
|
||||
if (notify_first_last)
|
||||
{
|
||||
@ -13876,8 +13915,70 @@ clutter_actor_event (ClutterActor *actor,
|
||||
|
||||
if (capture)
|
||||
{
|
||||
g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
|
||||
event,
|
||||
GQuark detail = 0;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_NOTHING:
|
||||
break;
|
||||
case CLUTTER_KEY_PRESS:
|
||||
case CLUTTER_KEY_RELEASE:
|
||||
detail = quark_key;
|
||||
break;
|
||||
case CLUTTER_MOTION:
|
||||
detail = quark_motion;
|
||||
break;
|
||||
case CLUTTER_ENTER:
|
||||
case CLUTTER_LEAVE:
|
||||
detail = quark_pointer_focus;
|
||||
break;
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
detail = quark_button;
|
||||
break;
|
||||
case CLUTTER_SCROLL:
|
||||
detail = quark_scroll;
|
||||
break;
|
||||
case CLUTTER_STAGE_STATE:
|
||||
detail = quark_stage;
|
||||
break;
|
||||
case CLUTTER_DESTROY_NOTIFY:
|
||||
detail = quark_destroy;
|
||||
break;
|
||||
case CLUTTER_CLIENT_MESSAGE:
|
||||
detail = quark_client;
|
||||
break;
|
||||
case CLUTTER_DELETE:
|
||||
detail = quark_delete;
|
||||
break;
|
||||
case CLUTTER_TOUCH_BEGIN:
|
||||
case CLUTTER_TOUCH_UPDATE:
|
||||
case CLUTTER_TOUCH_END:
|
||||
case CLUTTER_TOUCH_CANCEL:
|
||||
detail = quark_touch;
|
||||
break;
|
||||
case CLUTTER_TOUCHPAD_PINCH:
|
||||
case CLUTTER_TOUCHPAD_SWIPE:
|
||||
detail = quark_touchpad;
|
||||
break;
|
||||
case CLUTTER_PROXIMITY_IN:
|
||||
case CLUTTER_PROXIMITY_OUT:
|
||||
detail = quark_proximity;
|
||||
break;
|
||||
case CLUTTER_PAD_BUTTON_PRESS:
|
||||
case CLUTTER_PAD_BUTTON_RELEASE:
|
||||
case CLUTTER_PAD_STRIP:
|
||||
case CLUTTER_PAD_RING:
|
||||
detail = quark_pad;
|
||||
break;
|
||||
case CLUTTER_EVENT_LAST: /* Just keep compiler warnings quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
g_signal_emit (actor,
|
||||
actor_signals[CAPTURED_EVENT],
|
||||
detail,
|
||||
event,
|
||||
&retval);
|
||||
goto out;
|
||||
}
|
||||
@ -15898,6 +15999,63 @@ clutter_actor_get_opacity_override (ClutterActor *self)
|
||||
return self->priv->opacity_override;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_inhibit_culling:
|
||||
* @actor: a #ClutterActor
|
||||
*
|
||||
* Increases the culling inhibitor counter. Inhibiting culling
|
||||
* forces the actor to be painted even when outside the visible
|
||||
* bounds of the stage view.
|
||||
*
|
||||
* This is usually necessary when an actor is being painted on
|
||||
* another paint context.
|
||||
*
|
||||
* Pair with clutter_actor_uninhibit_culling() when the actor doesn't
|
||||
* need to be painted anymore.
|
||||
*/
|
||||
void
|
||||
clutter_actor_inhibit_culling (ClutterActor *actor)
|
||||
{
|
||||
ClutterActorPrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
priv = actor->priv;
|
||||
|
||||
priv->inhibit_culling_counter++;
|
||||
_clutter_actor_set_enable_paint_unmapped (actor, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_uninhibit_culling:
|
||||
* @actor: a #ClutterActor
|
||||
*
|
||||
* Decreases the culling inhibitor counter. See clutter_actor_inhibit_culling()
|
||||
* for when inhibit culling is necessary.
|
||||
*
|
||||
* Calling this function without a matching call to
|
||||
* clutter_actor_inhibit_culling() is a programming error.
|
||||
*/
|
||||
void
|
||||
clutter_actor_uninhibit_culling (ClutterActor *actor)
|
||||
{
|
||||
ClutterActorPrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
priv = actor->priv;
|
||||
|
||||
if (priv->inhibit_culling_counter == 0)
|
||||
{
|
||||
g_critical ("Unpaired call to clutter_actor_uninhibit_culling");
|
||||
return;
|
||||
}
|
||||
|
||||
priv->inhibit_culling_counter--;
|
||||
if (priv->inhibit_culling_counter == 0)
|
||||
_clutter_actor_set_enable_paint_unmapped (actor, FALSE);
|
||||
}
|
||||
|
||||
/* Allows you to disable applying the actors model view transform during
|
||||
* a paint. Used by ClutterClone. */
|
||||
void
|
||||
@ -17611,10 +17769,42 @@ _clutter_actor_compute_resource_scale (ClutterActor *self,
|
||||
resource_scale))
|
||||
{
|
||||
if (priv->parent)
|
||||
return _clutter_actor_compute_resource_scale (priv->parent,
|
||||
resource_scale);
|
||||
{
|
||||
gboolean in_clone_paint;
|
||||
gboolean was_parent_in_clone_paint;
|
||||
gboolean was_parent_unmapped;
|
||||
gboolean was_parent_paint_unmapped;
|
||||
gboolean ret;
|
||||
|
||||
in_clone_paint = clutter_actor_is_in_clone_paint (self);
|
||||
was_parent_unmapped = !clutter_actor_is_mapped (priv->parent);
|
||||
was_parent_in_clone_paint =
|
||||
clutter_actor_is_in_clone_paint (priv->parent);
|
||||
was_parent_paint_unmapped = priv->parent->priv->enable_paint_unmapped;
|
||||
|
||||
if (in_clone_paint && was_parent_unmapped)
|
||||
{
|
||||
_clutter_actor_set_in_clone_paint (priv->parent, TRUE);
|
||||
_clutter_actor_set_enable_paint_unmapped (priv->parent, TRUE);
|
||||
}
|
||||
|
||||
ret = _clutter_actor_compute_resource_scale (priv->parent,
|
||||
resource_scale);
|
||||
|
||||
if (in_clone_paint && was_parent_unmapped)
|
||||
{
|
||||
_clutter_actor_set_in_clone_paint (priv->parent,
|
||||
was_parent_in_clone_paint);
|
||||
_clutter_actor_set_enable_paint_unmapped (priv->parent,
|
||||
was_parent_paint_unmapped);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -19770,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
|
||||
@ -21157,7 +21364,7 @@ clutter_actor_create_texture_paint_node (ClutterActor *self,
|
||||
color.alpha = clutter_actor_get_paint_opacity_internal (self);
|
||||
|
||||
node = clutter_texture_node_new (texture, &color, priv->min_filter, priv->mag_filter);
|
||||
clutter_paint_node_set_name (node, "Texture");
|
||||
clutter_paint_node_set_static_name (node, "Texture");
|
||||
|
||||
if (priv->content_repeat == CLUTTER_REPEAT_NONE)
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
@ -21178,3 +21385,14 @@ clutter_actor_create_texture_paint_node (ClutterActor *self,
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_actor_has_accessible (ClutterActor *actor)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
|
||||
|
||||
if (CLUTTER_ACTOR_GET_CLASS (actor)->has_accessible)
|
||||
return CLUTTER_ACTOR_GET_CLASS (actor)->has_accessible (actor);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -299,10 +299,11 @@ struct _ClutterActorClass
|
||||
|
||||
gboolean (* touch_event) (ClutterActor *self,
|
||||
ClutterTouchEvent *event);
|
||||
gboolean (* has_accessible) (ClutterActor *self);
|
||||
|
||||
/*< private >*/
|
||||
/* padding for future expansion */
|
||||
gpointer _padding_dummy[26];
|
||||
gpointer _padding_dummy[25];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -380,6 +381,8 @@ CLUTTER_EXPORT
|
||||
const gchar * clutter_actor_get_name (ClutterActor *self);
|
||||
CLUTTER_EXPORT
|
||||
AtkObject * clutter_actor_get_accessible (ClutterActor *self);
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_actor_has_accessible (ClutterActor *self);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_actor_is_visible (ClutterActor *self);
|
||||
@ -881,6 +884,11 @@ void clutter_actor_set_opacity_override
|
||||
CLUTTER_EXPORT
|
||||
gint clutter_actor_get_opacity_override (ClutterActor *self);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_actor_inhibit_culling (ClutterActor *actor);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_actor_uninhibit_culling (ClutterActor *actor);
|
||||
|
||||
/**
|
||||
* ClutterActorCreateChildFunc:
|
||||
* @item: (type GObject): the item in the model
|
||||
|
@ -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)
|
||||
|
@ -352,7 +352,7 @@ clutter_canvas_paint_content (ClutterContent *content,
|
||||
return;
|
||||
|
||||
node = clutter_actor_create_texture_paint_node (actor, priv->texture);
|
||||
clutter_paint_node_set_name (node, "Canvas Content");
|
||||
clutter_paint_node_set_static_name (node, "Canvas Content");
|
||||
clutter_paint_node_add_child (root, node);
|
||||
clutter_paint_node_unref (node);
|
||||
|
||||
|
@ -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;
|
||||
|
36
clutter/clutter/clutter-container-private.h
Normal file
36
clutter/clutter/clutter-container-private.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright 2020 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 __CLUTTER_CONTAINER_PRIVATE_H__
|
||||
#define __CLUTTER_CONTAINER_PRIVATE_H__
|
||||
|
||||
#include <clutter/clutter-container.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void _clutter_container_emit_actor_added (ClutterContainer *container,
|
||||
ClutterActor *actor);
|
||||
void _clutter_container_emit_actor_removed (ClutterContainer *container,
|
||||
ClutterActor *actor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_CONTAINER_PRIVATE_H__ */
|
@ -37,6 +37,7 @@
|
||||
|
||||
#include "clutter-actor-private.h"
|
||||
#include "clutter-child-meta.h"
|
||||
#include "clutter-container-private.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-marshal.h"
|
||||
@ -1250,3 +1251,23 @@ clutter_container_child_notify (ClutterContainer *container,
|
||||
child,
|
||||
pspec);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_container_emit_actor_added (ClutterContainer *container,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
g_signal_emit (container, container_signals[ACTOR_ADDED], 0, actor);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_container_emit_actor_removed (ClutterContainer *container,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
g_signal_emit (container, container_signals[ACTOR_REMOVED], 0, actor);
|
||||
}
|
||||
|
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;
|
||||
|
@ -538,6 +538,10 @@ typedef enum /*< prefix=CLUTTER_ACTOR >*/
|
||||
* virtual returns %TRUE.
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: Always redirect the actor to an
|
||||
* offscreen buffer even if it is fully opaque.
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE: Only redirect the actor if it is the
|
||||
* most efficient thing to do based on its recent repaint behaviour. That
|
||||
* means when its contents are changing less frequently than it's being used
|
||||
* on stage.
|
||||
*
|
||||
* Possible flags to pass to clutter_actor_set_offscreen_redirect().
|
||||
*
|
||||
@ -545,8 +549,9 @@ typedef enum /*< prefix=CLUTTER_ACTOR >*/
|
||||
*/
|
||||
typedef enum /*< prefix=CLUTTER_OFFSCREEN_REDIRECT >*/
|
||||
{
|
||||
CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY = 1<<0,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS = 1<<1
|
||||
CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY = 1 << 0,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS = 1 << 1,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE = 1 << 2
|
||||
} ClutterOffscreenRedirect;
|
||||
|
||||
/**
|
||||
@ -673,12 +678,15 @@ typedef enum /*< prefix=CLUTTER_BIND >*/
|
||||
* has queued a redraw before this paint. This implies that the effect
|
||||
* should call clutter_actor_continue_paint() to chain to the next
|
||||
* effect and can not cache any results from a previous paint.
|
||||
* @CLUTTER_EFFECT_PAINT_BYPASS_EFFECT: The effect should not be used
|
||||
* on this frame, but it will be asked to paint the actor still.
|
||||
*
|
||||
* Flags passed to the ‘paint’ or ‘pick’ method of #ClutterEffect.
|
||||
*/
|
||||
typedef enum /*< prefix=CLUTTER_EFFECT_PAINT >*/
|
||||
{
|
||||
CLUTTER_EFFECT_PAINT_ACTOR_DIRTY = (1 << 0)
|
||||
CLUTTER_EFFECT_PAINT_ACTOR_DIRTY = (1 << 0),
|
||||
CLUTTER_EFFECT_PAINT_BYPASS_EFFECT = (1 << 1)
|
||||
} ClutterEffectPaintFlags;
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -130,7 +130,7 @@ clutter_image_paint_content (ClutterContent *content,
|
||||
return;
|
||||
|
||||
node = clutter_actor_create_texture_paint_node (actor, priv->texture);
|
||||
clutter_paint_node_set_name (node, "Image Content");
|
||||
clutter_paint_node_set_static_name (node, "Image Content");
|
||||
clutter_paint_node_add_child (root, node);
|
||||
clutter_paint_node_unref (node);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ void clutter_input_focus_focus_out (ClutterInputFocus *focus);
|
||||
void clutter_input_focus_commit (ClutterInputFocus *focus,
|
||||
const gchar *text);
|
||||
void clutter_input_focus_delete_surrounding (ClutterInputFocus *focus,
|
||||
guint offset,
|
||||
int offset,
|
||||
guint len);
|
||||
void clutter_input_focus_request_surrounding (ClutterInputFocus *focus);
|
||||
|
||||
|
@ -217,7 +217,7 @@ clutter_input_focus_commit (ClutterInputFocus *focus,
|
||||
|
||||
void
|
||||
clutter_input_focus_delete_surrounding (ClutterInputFocus *focus,
|
||||
guint offset,
|
||||
int offset,
|
||||
guint len)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
||||
|
@ -41,7 +41,7 @@ struct _ClutterInputFocusClass
|
||||
|
||||
void (* request_surrounding) (ClutterInputFocus *focus);
|
||||
void (* delete_surrounding) (ClutterInputFocus *focus,
|
||||
guint offset,
|
||||
int offset,
|
||||
guint len);
|
||||
void (* commit_text) (ClutterInputFocus *focus,
|
||||
const gchar *text);
|
||||
|
@ -168,7 +168,7 @@ clutter_input_method_class_init (ClutterInputMethodClass *klass)
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
|
||||
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT);
|
||||
signals[REQUEST_SURROUNDING] =
|
||||
g_signal_new ("request-surrounding",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
@ -292,7 +292,7 @@ clutter_input_method_commit (ClutterInputMethod *im,
|
||||
|
||||
void
|
||||
clutter_input_method_delete_surrounding (ClutterInputMethod *im,
|
||||
guint offset,
|
||||
int offset,
|
||||
guint len)
|
||||
{
|
||||
ClutterInputMethodPrivate *priv;
|
||||
|
@ -68,7 +68,7 @@ void clutter_input_method_commit (ClutterInputMethod *im,
|
||||
const gchar *text);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_input_method_delete_surrounding (ClutterInputMethod *im,
|
||||
guint offset,
|
||||
int offset,
|
||||
guint len);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_input_method_request_surrounding (ClutterInputMethod *im);
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-master-clock.h"
|
||||
#include "clutter-mutter.h"
|
||||
#include "clutter-paint-node-private.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-settings-private.h"
|
||||
#include "clutter-stage-manager.h"
|
||||
@ -970,6 +971,9 @@ clutter_init_real (GError **error)
|
||||
if (clutter_enable_accessibility)
|
||||
cally_accessibility_init ();
|
||||
|
||||
/* Initialize types required for paint nodes */
|
||||
_clutter_paint_node_init_types ();
|
||||
|
||||
return CLUTTER_INIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,8 @@
|
||||
|
||||
#include "clutter-build-config.h"
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
#include "clutter-master-clock.h"
|
||||
#include "clutter-master-clock-default.h"
|
||||
#include "clutter-debug.h"
|
||||
@ -461,6 +463,8 @@ clutter_clock_dispatch (GSource *source,
|
||||
|
||||
_clutter_threads_acquire_lock ();
|
||||
|
||||
COGL_TRACE_BEGIN (ClutterMasterClockTick, "Master Clock (tick)");
|
||||
|
||||
/* Get the time to use for this frame */
|
||||
master_clock->cur_tick = g_source_get_time (source);
|
||||
|
||||
@ -492,6 +496,8 @@ clutter_clock_dispatch (GSource *source,
|
||||
|
||||
g_slist_free_full (stages, g_object_unref);
|
||||
|
||||
COGL_TRACE_END (ClutterMasterClockTick);
|
||||
|
||||
_clutter_threads_release_lock ();
|
||||
|
||||
return TRUE;
|
||||
|
@ -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);
|
||||
@ -469,6 +472,13 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
|
||||
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
|
||||
ClutterOffscreenEffectPrivate *priv = self->priv;
|
||||
|
||||
if (flags & CLUTTER_EFFECT_PAINT_BYPASS_EFFECT)
|
||||
{
|
||||
clutter_actor_continue_paint (priv->actor, paint_context);
|
||||
cogl_clear_object (&priv->offscreen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we've already got a cached image and the actor hasn't been redrawn
|
||||
* then we can just use the cached image in the FBO.
|
||||
*/
|
||||
@ -491,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
|
||||
@ -511,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);
|
||||
}
|
||||
@ -527,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
|
||||
@ -593,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,9 @@
|
||||
|
||||
#include "clutter-paint-context.h"
|
||||
|
||||
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view);
|
||||
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags);
|
||||
|
||||
gboolean clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context);
|
||||
|
||||
|
@ -23,9 +23,13 @@ struct _ClutterPaintContext
|
||||
{
|
||||
grefcount ref_count;
|
||||
|
||||
ClutterPaintFlag paint_flags;
|
||||
|
||||
GList *framebuffers;
|
||||
|
||||
ClutterStageView *view;
|
||||
|
||||
cairo_region_t *redraw_clip;
|
||||
};
|
||||
|
||||
G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
|
||||
@ -33,7 +37,9 @@ G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
|
||||
clutter_paint_context_unref)
|
||||
|
||||
ClutterPaintContext *
|
||||
clutter_paint_context_new_for_view (ClutterStageView *view)
|
||||
clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags)
|
||||
{
|
||||
ClutterPaintContext *paint_context;
|
||||
CoglFramebuffer *framebuffer;
|
||||
@ -41,6 +47,8 @@ clutter_paint_context_new_for_view (ClutterStageView *view)
|
||||
paint_context = g_new0 (ClutterPaintContext, 1);
|
||||
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);
|
||||
@ -52,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);
|
||||
|
||||
@ -77,6 +89,7 @@ clutter_paint_context_dispose (ClutterPaintContext *paint_context)
|
||||
g_list_free_full (paint_context->framebuffers,
|
||||
cogl_object_unref);
|
||||
paint_context->framebuffers = NULL;
|
||||
g_clear_pointer (&paint_context->redraw_clip, cairo_region_destroy);
|
||||
}
|
||||
|
||||
void
|
||||
@ -115,6 +128,12 @@ clutter_paint_context_pop_framebuffer (ClutterPaintContext *paint_context)
|
||||
paint_context->framebuffers);
|
||||
}
|
||||
|
||||
const cairo_region_t *
|
||||
clutter_paint_context_get_redraw_clip (ClutterPaintContext *paint_context)
|
||||
{
|
||||
return paint_context->redraw_clip;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_paint_context_get_framebuffer:
|
||||
* @paint_context: The #ClutterPaintContext
|
||||
@ -159,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);
|
||||
@ -59,4 +67,10 @@ void clutter_paint_context_push_framebuffer (ClutterPaintContext *paint_context,
|
||||
CLUTTER_EXPORT
|
||||
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 */
|
||||
|
@ -49,11 +49,11 @@ struct _ClutterPaintNode
|
||||
ClutterPaintNode *next_sibling;
|
||||
ClutterPaintNode *last_child;
|
||||
|
||||
guint n_children;
|
||||
|
||||
GArray *operations;
|
||||
|
||||
gchar *name;
|
||||
const gchar *name;
|
||||
|
||||
guint n_children;
|
||||
|
||||
volatile int ref_count;
|
||||
};
|
||||
@ -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;
|
||||
};
|
||||
|
@ -171,8 +171,6 @@ clutter_paint_node_real_finalize (ClutterPaintNode *node)
|
||||
{
|
||||
ClutterPaintNode *iter;
|
||||
|
||||
g_free (node->name);
|
||||
|
||||
if (node->operations != NULL)
|
||||
{
|
||||
guint i;
|
||||
@ -297,7 +295,8 @@ clutter_paint_node_get_type (void)
|
||||
*
|
||||
* The @name will be used for debugging purposes.
|
||||
*
|
||||
* The @node will copy the passed string.
|
||||
* The @node will intern @name using g_intern_string(). If you have access to a
|
||||
* static string, use clutter_paint_node_set_static_name() instead.
|
||||
*
|
||||
* Since: 1.10
|
||||
*/
|
||||
@ -307,8 +306,22 @@ clutter_paint_node_set_name (ClutterPaintNode *node,
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
|
||||
|
||||
g_free (node->name);
|
||||
node->name = g_strdup (name);
|
||||
node->name = g_intern_string (name);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_paint_node_set_static_name: (skip)
|
||||
*
|
||||
* Like clutter_paint_node_set_name() but uses a static or interned string
|
||||
* containing the name.
|
||||
*/
|
||||
void
|
||||
clutter_paint_node_set_static_name (ClutterPaintNode *node,
|
||||
const char *name)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
|
||||
|
||||
node->name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -769,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);
|
||||
@ -823,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)
|
||||
@ -937,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
|
||||
@ -1101,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);
|
||||
@ -1181,8 +1146,6 @@ _clutter_paint_node_create (GType gtype)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (gtype, CLUTTER_TYPE_PAINT_NODE), NULL);
|
||||
|
||||
_clutter_paint_node_init_types ();
|
||||
|
||||
return (gpointer) g_type_create_instance (gtype);
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,9 @@ void clutter_paint_node_paint (Clutter
|
||||
CLUTTER_EXPORT
|
||||
void clutter_paint_node_set_name (ClutterPaintNode *node,
|
||||
const char *name);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_paint_node_set_static_name (ClutterPaintNode *node,
|
||||
const char *name);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
CoglFramebuffer * clutter_paint_node_get_framebuffer (ClutterPaintNode *node);
|
||||
@ -81,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;
|
||||
}
|
||||
|
@ -248,6 +248,9 @@ gboolean _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1
|
||||
const cairo_rectangle_int_t *src2,
|
||||
cairo_rectangle_int_t *dest);
|
||||
|
||||
gboolean clutter_util_rectangle_equal (const cairo_rectangle_int_t *src1,
|
||||
const cairo_rectangle_int_t *src2);
|
||||
|
||||
|
||||
struct _ClutterVertex4
|
||||
{
|
||||
|
@ -41,6 +41,7 @@ enum
|
||||
PTR_A11Y_DWELL_CLICK_TYPE_CHANGED,
|
||||
PTR_A11Y_TIMEOUT_STARTED,
|
||||
PTR_A11Y_TIMEOUT_STOPPED,
|
||||
IS_UNFOCUS_INHIBITED_CHANGED,
|
||||
N_SIGNALS,
|
||||
};
|
||||
|
||||
@ -62,6 +63,8 @@ struct _ClutterSeatPrivate
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
|
||||
unsigned int inhibit_unfocus_count;
|
||||
|
||||
/* Keyboard a11y */
|
||||
ClutterKbdA11ySettings kbd_a11y_settings;
|
||||
|
||||
@ -275,6 +278,22 @@ clutter_seat_class_init (ClutterSeatClass *klass)
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
_clutter_marshal_VOID__OBJECT_FLAGS_BOOLEANv);
|
||||
|
||||
/**
|
||||
* ClutterSeat::is-unfocus-inhibited-changed:
|
||||
* @seat: the #ClutterSeat that emitted the signal
|
||||
*
|
||||
* The ::is-unfocus-inhibited-changed signal is emitted when the
|
||||
* property to inhibit the unsetting of the focus-surface of the
|
||||
* #ClutterSeat changed. To get the current state of this property,
|
||||
* use clutter_seat_is_unfocus_inhibited().
|
||||
*/
|
||||
signals[IS_UNFOCUS_INHIBITED_CHANGED] =
|
||||
g_signal_new (I_("is-unfocus-inhibited-changed"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
props[PROP_BACKEND] =
|
||||
g_param_spec_object ("backend",
|
||||
P_("Backend"),
|
||||
@ -282,6 +301,12 @@ clutter_seat_class_init (ClutterSeatClass *klass)
|
||||
CLUTTER_TYPE_BACKEND,
|
||||
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* ClutterSeat:touch-mode:
|
||||
*
|
||||
* The current touch-mode of the #ClutterSeat, it is set to %TRUE if the
|
||||
* requirements documented in clutter_seat_get_touch_mode() are fulfilled.
|
||||
**/
|
||||
props[PROP_TOUCH_MODE] =
|
||||
g_param_spec_boolean ("touch-mode",
|
||||
P_("Touch mode"),
|
||||
@ -508,6 +533,85 @@ clutter_seat_set_pointer_a11y_dwell_click_type (ClutterSeat
|
||||
priv->pointer_a11y_settings.dwell_click_type = click_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_seat_inhibit_unfocus:
|
||||
* @seat: a #ClutterSeat
|
||||
*
|
||||
* Inhibits unsetting of the pointer focus-surface for the #ClutterSeat @seat,
|
||||
* this allows to keep using the pointer even when it's hidden.
|
||||
*
|
||||
* This property is refcounted, so clutter_seat_uninhibit_unfocus() must be
|
||||
* called the exact same number of times as clutter_seat_inhibit_unfocus()
|
||||
* was called before.
|
||||
**/
|
||||
void
|
||||
clutter_seat_inhibit_unfocus (ClutterSeat *seat)
|
||||
{
|
||||
ClutterSeatPrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_SEAT (seat));
|
||||
|
||||
priv = clutter_seat_get_instance_private (seat);
|
||||
|
||||
priv->inhibit_unfocus_count++;
|
||||
|
||||
if (priv->inhibit_unfocus_count == 1)
|
||||
g_signal_emit (G_OBJECT (seat), signals[IS_UNFOCUS_INHIBITED_CHANGED], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_seat_uninhibit_unfocus:
|
||||
* @seat: a #ClutterSeat
|
||||
*
|
||||
* Disables the inhibiting of unsetting of the pointer focus-surface
|
||||
* previously enabled by calling clutter_seat_inhibit_unfocus().
|
||||
*
|
||||
* This property is refcounted, so clutter_seat_uninhibit_unfocus() must be
|
||||
* called the exact same number of times as clutter_seat_inhibit_unfocus()
|
||||
* was called before.
|
||||
**/
|
||||
void
|
||||
clutter_seat_uninhibit_unfocus (ClutterSeat *seat)
|
||||
{
|
||||
ClutterSeatPrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_SEAT (seat));
|
||||
|
||||
priv = clutter_seat_get_instance_private (seat);
|
||||
|
||||
if (priv->inhibit_unfocus_count == 0)
|
||||
{
|
||||
g_warning ("Called clutter_seat_uninhibit_unfocus without inhibiting before");
|
||||
return;
|
||||
}
|
||||
|
||||
priv->inhibit_unfocus_count--;
|
||||
|
||||
if (priv->inhibit_unfocus_count == 0)
|
||||
g_signal_emit (G_OBJECT (seat), signals[IS_UNFOCUS_INHIBITED_CHANGED], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_seat_is_unfocus_inhibited:
|
||||
* @seat: a #ClutterSeat
|
||||
*
|
||||
* Gets whether unsetting of the pointer focus-surface is inhibited
|
||||
* for the #ClutterSeat @seat.
|
||||
*
|
||||
* Returns: %TRUE if unsetting is inhibited, %FALSE otherwise
|
||||
**/
|
||||
gboolean
|
||||
clutter_seat_is_unfocus_inhibited (ClutterSeat *seat)
|
||||
{
|
||||
ClutterSeatPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), FALSE);
|
||||
|
||||
priv = clutter_seat_get_instance_private (seat);
|
||||
|
||||
return priv->inhibit_unfocus_count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_seat_create_virtual_device:
|
||||
* @seat: a #ClutterSeat
|
||||
@ -569,6 +673,21 @@ clutter_seat_warp_pointer (ClutterSeat *seat,
|
||||
CLUTTER_SEAT_GET_CLASS (seat)->warp_pointer (seat, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_seat_get_touch_mode:
|
||||
* @seat: a #ClutterSeat
|
||||
*
|
||||
* Gets the current touch-mode state of the #ClutterSeat @seat.
|
||||
* The #ClutterSeat:touch-mode property is set to %TRUE if the following
|
||||
* requirements are fulfilled:
|
||||
*
|
||||
* - A touchscreen is available
|
||||
* - No external keyboard is attached to the device
|
||||
* - A tablet mode switch, if present, is enabled
|
||||
*
|
||||
* Returns: %TRUE if the device is a tablet that doesn't have an external
|
||||
* keyboard attached, %FALSE otherwise.
|
||||
**/
|
||||
gboolean
|
||||
clutter_seat_get_touch_mode (ClutterSeat *seat)
|
||||
{
|
||||
|
@ -159,6 +159,16 @@ void clutter_seat_get_pointer_a11y_settings (ClutterSeat *seat,
|
||||
CLUTTER_EXPORT
|
||||
void clutter_seat_set_pointer_a11y_dwell_click_type (ClutterSeat *seat,
|
||||
ClutterPointerA11yDwellClickType click_type);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_seat_inhibit_unfocus (ClutterSeat *seat);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_seat_uninhibit_unfocus (ClutterSeat *seat);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_seat_is_unfocus_inhibited (ClutterSeat *seat);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterVirtualInputDevice *clutter_seat_create_virtual_device (ClutterSeat *seat,
|
||||
ClutterInputDeviceType device_type);
|
||||
|
@ -36,9 +36,9 @@ typedef struct _ClutterStageQueueRedrawEntry ClutterStageQueueRedrawEntry;
|
||||
/* stage */
|
||||
ClutterStageWindow *_clutter_stage_get_default_window (void);
|
||||
|
||||
void _clutter_stage_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
const cairo_rectangle_int_t *clip);
|
||||
void clutter_stage_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip);
|
||||
|
||||
void _clutter_stage_emit_after_paint (ClutterStage *stage);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
@ -20,8 +20,7 @@
|
||||
|
||||
#include "clutter/clutter-stage-view.h"
|
||||
|
||||
void clutter_stage_view_after_paint (ClutterStageView *view,
|
||||
const cairo_rectangle_int_t *clip);
|
||||
void clutter_stage_view_after_paint (ClutterStageView *view);
|
||||
|
||||
gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
|
||||
|
||||
@ -33,7 +32,17 @@ gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view);
|
||||
void clutter_stage_view_set_dirty_projection (ClutterStageView *view,
|
||||
gboolean dirty);
|
||||
|
||||
void clutter_stage_view_add_redraw_clip (ClutterStageView *view,
|
||||
cairo_rectangle_int_t *clip);
|
||||
void clutter_stage_view_add_redraw_clip (ClutterStageView *view,
|
||||
const cairo_rectangle_int_t *clip);
|
||||
|
||||
gboolean clutter_stage_view_has_full_redraw_clip (ClutterStageView *view);
|
||||
|
||||
gboolean clutter_stage_view_has_redraw_clip (ClutterStageView *view);
|
||||
|
||||
const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *view);
|
||||
|
||||
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__ */
|
||||
|
@ -23,6 +23,10 @@
|
||||
#include <cairo-gobject.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "clutter/clutter-private.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "cogl/cogl.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
@ -50,6 +54,11 @@ typedef struct _ClutterStageViewPrivate
|
||||
CoglOffscreen *shadowfb;
|
||||
CoglPipeline *shadowfb_pipeline;
|
||||
|
||||
CoglScanout *next_scanout;
|
||||
|
||||
gboolean has_redraw_clip;
|
||||
cairo_region_t *redraw_clip;
|
||||
|
||||
guint dirty_viewport : 1;
|
||||
guint dirty_projection : 1;
|
||||
} ClutterStageViewPrivate;
|
||||
@ -166,12 +175,11 @@ clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_view_copy_to_framebuffer (ClutterStageView *view,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
CoglPipeline *pipeline,
|
||||
CoglFramebuffer *src_framebuffer,
|
||||
CoglFramebuffer *dst_framebuffer,
|
||||
gboolean can_blit)
|
||||
clutter_stage_view_copy_to_framebuffer (ClutterStageView *view,
|
||||
CoglPipeline *pipeline,
|
||||
CoglFramebuffer *src_framebuffer,
|
||||
CoglFramebuffer *dst_framebuffer,
|
||||
gboolean can_blit)
|
||||
{
|
||||
CoglMatrix matrix;
|
||||
|
||||
@ -204,8 +212,7 @@ clutter_stage_view_copy_to_framebuffer (ClutterStageView *view,
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_view_after_paint (ClutterStageView *view,
|
||||
const cairo_rectangle_int_t *rect)
|
||||
clutter_stage_view_after_paint (ClutterStageView *view)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
@ -222,7 +229,6 @@ clutter_stage_view_after_paint (ClutterStageView *view,
|
||||
if (priv->shadowfb)
|
||||
{
|
||||
clutter_stage_view_copy_to_framebuffer (view,
|
||||
rect,
|
||||
priv->offscreen_pipeline,
|
||||
priv->offscreen,
|
||||
priv->shadowfb,
|
||||
@ -231,7 +237,6 @@ clutter_stage_view_after_paint (ClutterStageView *view,
|
||||
else
|
||||
{
|
||||
clutter_stage_view_copy_to_framebuffer (view,
|
||||
rect,
|
||||
priv->offscreen_pipeline,
|
||||
priv->offscreen,
|
||||
priv->framebuffer,
|
||||
@ -243,7 +248,6 @@ clutter_stage_view_after_paint (ClutterStageView *view,
|
||||
{
|
||||
clutter_stage_view_ensure_shadowfb_blit_pipeline (view);
|
||||
clutter_stage_view_copy_to_framebuffer (view,
|
||||
rect,
|
||||
priv->shadowfb_pipeline,
|
||||
priv->shadowfb,
|
||||
priv->framebuffer,
|
||||
@ -307,6 +311,86 @@ clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view,
|
||||
view_class->get_offscreen_transformation_matrix (view, matrix);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_view_add_redraw_clip (ClutterStageView *view,
|
||||
const cairo_rectangle_int_t *clip)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
if (priv->has_redraw_clip && !priv->redraw_clip)
|
||||
return;
|
||||
|
||||
if (!clip)
|
||||
{
|
||||
g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
|
||||
priv->has_redraw_clip = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (clip->width == 0 || clip->height == 0)
|
||||
return;
|
||||
|
||||
if (!priv->redraw_clip)
|
||||
{
|
||||
if (!clutter_util_rectangle_equal (&priv->layout, clip))
|
||||
priv->redraw_clip = cairo_region_create_rectangle (clip);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_region_union_rectangle (priv->redraw_clip, clip);
|
||||
|
||||
if (cairo_region_num_rectangles (priv->redraw_clip) == 1)
|
||||
{
|
||||
cairo_rectangle_int_t redraw_clip_extents;
|
||||
|
||||
cairo_region_get_extents (priv->redraw_clip, &redraw_clip_extents);
|
||||
if (clutter_util_rectangle_equal (&priv->layout, &redraw_clip_extents))
|
||||
g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
priv->has_redraw_clip = TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_stage_view_has_redraw_clip (ClutterStageView *view)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
return priv->has_redraw_clip;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_stage_view_has_full_redraw_clip (ClutterStageView *view)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
return priv->has_redraw_clip && !priv->redraw_clip;
|
||||
}
|
||||
|
||||
const cairo_region_t *
|
||||
clutter_stage_view_peek_redraw_clip (ClutterStageView *view)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
return priv->redraw_clip;
|
||||
}
|
||||
|
||||
cairo_region_t *
|
||||
clutter_stage_view_take_redraw_clip (ClutterStageView *view)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
priv->has_redraw_clip = FALSE;
|
||||
|
||||
return g_steal_pointer (&priv->redraw_clip);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_view_transform_to_onscreen (ClutterStageView *view,
|
||||
gfloat *x,
|
||||
@ -327,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,
|
||||
@ -419,6 +522,7 @@ clutter_stage_view_dispose (GObject *object)
|
||||
g_clear_pointer (&priv->offscreen, cogl_object_unref);
|
||||
g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
|
||||
g_clear_pointer (&priv->shadowfb_pipeline, cogl_object_unref);
|
||||
g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
@ -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,90 +168,6 @@ _clutter_stage_window_clear_update_time (ClutterStageWindow *window)
|
||||
iface->clear_update_time (window);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_window_add_redraw_clip (ClutterStageWindow *window,
|
||||
cairo_rectangle_int_t *stage_clip)
|
||||
{
|
||||
ClutterStageWindowInterface *iface;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
|
||||
|
||||
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
|
||||
if (iface->add_redraw_clip != NULL)
|
||||
iface->add_redraw_clip (window, stage_clip);
|
||||
}
|
||||
|
||||
/* Determines if the backend will clip the rendering of the next
|
||||
* frame.
|
||||
*
|
||||
* Note: at the start of each new frame there is an implied clip that
|
||||
* clips everything (i.e. nothing would be drawn) so this function
|
||||
* will return True at the start of a new frame if the backend
|
||||
* supports clipped redraws.
|
||||
*/
|
||||
gboolean
|
||||
_clutter_stage_window_has_redraw_clips (ClutterStageWindow *window)
|
||||
{
|
||||
ClutterStageWindowInterface *iface;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), FALSE);
|
||||
|
||||
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
|
||||
if (iface->has_redraw_clips != NULL)
|
||||
return iface->has_redraw_clips (window);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Determines if the backend will discard any additional redraw clips
|
||||
* and instead promote them to a full stage redraw.
|
||||
*
|
||||
* The ideas is that backend may have some heuristics that cause it to
|
||||
* give up tracking redraw clips so this can be used to avoid the cost
|
||||
* of calculating a redraw clip when we know it's going to be ignored
|
||||
* anyway.
|
||||
*/
|
||||
gboolean
|
||||
_clutter_stage_window_ignoring_redraw_clips (ClutterStageWindow *window)
|
||||
{
|
||||
ClutterStageWindowInterface *iface;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), FALSE);
|
||||
|
||||
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
|
||||
if (iface->ignoring_redraw_clips != NULL)
|
||||
return iface->ignoring_redraw_clips (window);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cairo_region_t *
|
||||
_clutter_stage_window_get_redraw_clip (ClutterStageWindow *window)
|
||||
{
|
||||
ClutterStageWindowInterface *iface;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), FALSE);
|
||||
|
||||
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
|
||||
if (iface->get_redraw_clip != NULL)
|
||||
return iface->get_redraw_clip (window);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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,15 +49,6 @@ struct _ClutterStageWindowInterface
|
||||
gint64 (* get_update_time) (ClutterStageWindow *stage_window);
|
||||
void (* clear_update_time) (ClutterStageWindow *stage_window);
|
||||
|
||||
void (* add_redraw_clip) (ClutterStageWindow *stage_window,
|
||||
cairo_rectangle_int_t *stage_rectangle);
|
||||
gboolean (* has_redraw_clips) (ClutterStageWindow *stage_window);
|
||||
gboolean (* ignoring_redraw_clips) (ClutterStageWindow *stage_window);
|
||||
cairo_region_t * (* get_redraw_clip) (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);
|
||||
@ -94,12 +83,6 @@ void _clutter_stage_window_schedule_update (ClutterStageWin
|
||||
gint64 _clutter_stage_window_get_update_time (ClutterStageWindow *window);
|
||||
void _clutter_stage_window_clear_update_time (ClutterStageWindow *window);
|
||||
|
||||
void _clutter_stage_window_add_redraw_clip (ClutterStageWindow *window,
|
||||
cairo_rectangle_int_t *stage_clip);
|
||||
gboolean _clutter_stage_window_has_redraw_clips (ClutterStageWindow *window);
|
||||
gboolean _clutter_stage_window_ignoring_redraw_clips (ClutterStageWindow *window);
|
||||
cairo_region_t * _clutter_stage_window_get_redraw_clip (ClutterStageWindow *window);
|
||||
|
||||
void _clutter_stage_window_set_accept_focus (ClutterStageWindow *window,
|
||||
gboolean accept_focus);
|
||||
|
||||
|
@ -78,7 +78,6 @@
|
||||
#include "clutter-private.h"
|
||||
|
||||
#include "cogl/cogl.h"
|
||||
#include "cogl/cogl-trace.h"
|
||||
|
||||
struct _ClutterStageQueueRedrawEntry
|
||||
{
|
||||
@ -141,21 +140,12 @@ struct _ClutterStagePrivate
|
||||
|
||||
ClutterStageState current_state;
|
||||
|
||||
gpointer paint_data;
|
||||
GDestroyNotify paint_notify;
|
||||
|
||||
cairo_rectangle_int_t view_clip;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@ -164,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
|
||||
};
|
||||
|
||||
@ -559,6 +546,33 @@ pick_record_contains_point (ClutterStage *stage,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_add_redraw_clip (ClutterStage *stage,
|
||||
cairo_rectangle_int_t *clip)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
|
||||
if (!clip)
|
||||
{
|
||||
clutter_stage_view_add_redraw_clip (view, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_rectangle_int_t view_layout;
|
||||
cairo_rectangle_int_t intersection;
|
||||
|
||||
clutter_stage_view_get_layout (view, &view_layout);
|
||||
if (_clutter_util_rectangle_intersection (&view_layout, clip,
|
||||
&intersection))
|
||||
clutter_stage_view_add_redraw_clip (view, &intersection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
queue_full_redraw (ClutterStage *stage)
|
||||
{
|
||||
@ -577,7 +591,7 @@ queue_full_redraw (ClutterStage *stage)
|
||||
if (stage_window == NULL)
|
||||
return;
|
||||
|
||||
_clutter_stage_window_add_redraw_clip (stage_window, NULL);
|
||||
clutter_stage_add_redraw_clip (stage, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -903,15 +917,19 @@ setup_view_for_pick_or_paint (ClutterStage *stage,
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_do_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
const cairo_rectangle_int_t *clip)
|
||||
clutter_stage_do_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip)
|
||||
{
|
||||
ClutterPaintContext *paint_context;
|
||||
cairo_rectangle_int_t clip_rect;
|
||||
|
||||
paint_context = clutter_paint_context_new_for_view (view);
|
||||
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);
|
||||
|
||||
setup_view_for_pick_or_paint (stage, view, clip);
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage), paint_context);
|
||||
clutter_paint_context_destroy (paint_context);
|
||||
}
|
||||
@ -920,9 +938,9 @@ clutter_stage_do_paint_view (ClutterStage *stage,
|
||||
* for picking or painting...
|
||||
*/
|
||||
void
|
||||
_clutter_stage_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
const cairo_rectangle_int_t *clip)
|
||||
clutter_stage_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
|
||||
@ -931,15 +949,11 @@ _clutter_stage_paint_view (ClutterStage *stage,
|
||||
|
||||
COGL_TRACE_BEGIN_SCOPED (ClutterStagePaintView, "Paint (view)");
|
||||
|
||||
priv->view_clip = *clip;
|
||||
|
||||
if (g_signal_has_handler_pending (stage, stage_signals[PAINT_VIEW],
|
||||
0, TRUE))
|
||||
g_signal_emit (stage, stage_signals[PAINT_VIEW], 0, view);
|
||||
g_signal_emit (stage, stage_signals[PAINT_VIEW], 0, view, redraw_clip);
|
||||
else
|
||||
CLUTTER_STAGE_GET_CLASS (stage)->paint_view (stage, view);
|
||||
|
||||
priv->view_clip = (cairo_rectangle_int_t) { 0 };
|
||||
CLUTTER_STAGE_GET_CLASS (stage)->paint_view (stage, view, redraw_clip);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1297,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++;
|
||||
}
|
||||
@ -1416,16 +1424,12 @@ clutter_stage_do_redraw (ClutterStage *stage)
|
||||
static GSList *
|
||||
_clutter_stage_check_updated_pointers (ClutterStage *stage)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
ClutterBackend *backend;
|
||||
ClutterSeat *seat;
|
||||
GSList *updating = NULL;
|
||||
GList *l, *devices;
|
||||
cairo_region_t *clip;
|
||||
graphene_point_t point;
|
||||
|
||||
clip = _clutter_stage_window_get_redraw_clip (priv->impl);
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
seat = clutter_backend_get_default_seat (backend);
|
||||
devices = clutter_seat_list_devices (seat);
|
||||
@ -1433,6 +1437,8 @@ _clutter_stage_check_updated_pointers (ClutterStage *stage)
|
||||
for (l = devices; l; l = l->next)
|
||||
{
|
||||
ClutterInputDevice *dev = l->data;
|
||||
ClutterStageView *view;
|
||||
const cairo_region_t *clip;
|
||||
|
||||
if (clutter_input_device_get_device_mode (dev) !=
|
||||
CLUTTER_INPUT_MODE_MASTER)
|
||||
@ -1448,6 +1454,11 @@ _clutter_stage_check_updated_pointers (ClutterStage *stage)
|
||||
if (!clutter_input_device_get_coords (dev, NULL, &point))
|
||||
continue;
|
||||
|
||||
view = clutter_stage_get_view_at (stage, point.x, point.y);
|
||||
if (!view)
|
||||
continue;
|
||||
|
||||
clip = clutter_stage_view_peek_redraw_clip (view);
|
||||
if (!clip || cairo_region_contains_point (clip, point.x, point.y))
|
||||
updating = g_slist_prepend (updating, dev);
|
||||
break;
|
||||
@ -1557,6 +1568,22 @@ clutter_stage_real_queue_relayout (ClutterActor *self)
|
||||
parent_class->queue_relayout (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_full_stage_redraw_queued (ClutterStage *stage)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
|
||||
if (!clutter_stage_view_has_full_redraw_clip (view))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_stage_real_queue_redraw (ClutterActor *actor,
|
||||
ClutterActor *leaf,
|
||||
@ -1578,12 +1605,12 @@ clutter_stage_real_queue_redraw (ClutterActor *actor,
|
||||
if (stage_window == NULL)
|
||||
return TRUE;
|
||||
|
||||
if (_clutter_stage_window_ignoring_redraw_clips (stage_window))
|
||||
if (is_full_stage_redraw_queued (stage))
|
||||
return FALSE;
|
||||
|
||||
if (redraw_clip == NULL)
|
||||
{
|
||||
_clutter_stage_window_add_redraw_clip (stage_window, NULL);
|
||||
clutter_stage_add_redraw_clip (stage, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1615,43 +1642,20 @@ clutter_stage_real_queue_redraw (ClutterActor *actor,
|
||||
stage_clip.width = intersection_box.x2 - stage_clip.x;
|
||||
stage_clip.height = intersection_box.y2 - stage_clip.y;
|
||||
|
||||
_clutter_stage_window_add_redraw_clip (stage_window, &stage_clip);
|
||||
clutter_stage_add_redraw_clip (stage, &stage_clip);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_clutter_stage_has_full_redraw_queued (ClutterStage *stage)
|
||||
{
|
||||
ClutterStageWindow *stage_window = _clutter_stage_get_window (stage);
|
||||
|
||||
if (CLUTTER_ACTOR_IN_DESTRUCTION (stage) || stage_window == NULL)
|
||||
if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
|
||||
return FALSE;
|
||||
|
||||
if (stage->priv->redraw_pending &&
|
||||
!_clutter_stage_window_has_redraw_clips (stage_window))
|
||||
return TRUE;
|
||||
else
|
||||
if (!stage->priv->redraw_pending)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cairo_region_t *
|
||||
clutter_stage_get_redraw_clip (ClutterStage *stage)
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
cairo_rectangle_int_t clip;
|
||||
cairo_region_t *region;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
|
||||
|
||||
priv = stage->priv;
|
||||
|
||||
region = _clutter_stage_window_get_redraw_clip (priv->impl);
|
||||
if (region)
|
||||
return region;
|
||||
|
||||
/* Set clip to the full extents of the stage */
|
||||
_clutter_stage_window_get_geometry (priv->impl, &clip);
|
||||
return cairo_region_create_rectangle (&clip);
|
||||
return is_full_stage_redraw_queued (stage);
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
@ -1833,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;
|
||||
@ -1886,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;
|
||||
@ -1898,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;
|
||||
@ -1973,20 +1946,15 @@ 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);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_real_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view)
|
||||
clutter_stage_real_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
const cairo_rectangle_int_t *clip = &priv->view_clip;
|
||||
|
||||
clutter_stage_do_paint_view (stage, view, clip);
|
||||
clutter_stage_do_paint_view (stage, view, redraw_clip);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2019,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:
|
||||
*
|
||||
@ -2060,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:
|
||||
@ -2076,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:
|
||||
*
|
||||
@ -2110,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);
|
||||
|
||||
/**
|
||||
@ -2212,6 +2137,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
||||
* ClutterStage::paint-view:
|
||||
* @stage: the stage that received the event
|
||||
* @view: a #ClutterStageView
|
||||
* @redraw_clip: a #cairo_region_t with the redraw clip
|
||||
*
|
||||
* The ::paint-view signal is emitted before a #ClutterStageView is being
|
||||
* painted.
|
||||
@ -2226,8 +2152,9 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterStageClass, paint_view),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_STAGE_VIEW);
|
||||
G_TYPE_NONE, 2,
|
||||
CLUTTER_TYPE_STAGE_VIEW,
|
||||
G_TYPE_POINTER);
|
||||
|
||||
/**
|
||||
* ClutterStage::presented: (skip)
|
||||
@ -2296,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;
|
||||
@ -2419,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;
|
||||
|
||||
@ -2445,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
|
||||
@ -2501,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
|
||||
*/
|
||||
@ -2665,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
|
||||
@ -2803,13 +2633,17 @@ clutter_stage_read_pixels (ClutterStage *stage,
|
||||
.height = height,
|
||||
});
|
||||
cairo_region_get_extents (clip, &clip_rect);
|
||||
cairo_region_destroy (clip);
|
||||
|
||||
if (clip_rect.width == 0 || clip_rect.height == 0)
|
||||
return NULL;
|
||||
{
|
||||
cairo_region_destroy (clip);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
framebuffer = clutter_stage_view_get_framebuffer (view);
|
||||
clutter_stage_do_paint_view (stage, view, &clip_rect);
|
||||
clutter_stage_do_paint_view (stage, view, clip);
|
||||
|
||||
cairo_region_destroy (clip);
|
||||
|
||||
view_scale = clutter_stage_view_get_scale (view);
|
||||
pixel_width = roundf (clip_rect.width * view_scale);
|
||||
@ -3278,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,
|
||||
@ -3531,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
|
||||
@ -3927,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
|
||||
@ -4316,7 +4040,6 @@ capture_view (ClutterStage *stage,
|
||||
texture_width, texture_height);
|
||||
cairo_surface_set_device_scale (image, view_scale, view_scale);
|
||||
|
||||
|
||||
data = cairo_image_surface_get_data (image);
|
||||
stride = cairo_image_surface_get_stride (image);
|
||||
|
||||
@ -4326,6 +4049,20 @@ capture_view (ClutterStage *stage,
|
||||
cairo_surface_mark_dirty (capture->image);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_capture:
|
||||
* @stage: a #ClutterStage
|
||||
* @paint: whether to pain the frame
|
||||
* @rect: a #cairo_rectangle_int_t in stage coordinates
|
||||
* @out_captures: (out) (array length=out_n_captures): an array of
|
||||
* #ClutterCapture
|
||||
* @out_n_captures: (out): the number of captures in @out_captures
|
||||
*
|
||||
* Captures the stage pixels of @rect into @captures. @rect is in stage
|
||||
* coordinates.
|
||||
*
|
||||
* Returns: %TRUE if a #ClutterCapture has been created, %FALSE otherwise
|
||||
*/
|
||||
gboolean
|
||||
clutter_stage_capture (ClutterStage *stage,
|
||||
gboolean paint,
|
||||
@ -4427,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,
|
||||
@ -4450,8 +4278,12 @@ capture_view_into (ClutterStage *stage,
|
||||
|
||||
if (paint)
|
||||
{
|
||||
cairo_region_t *region;
|
||||
|
||||
_clutter_stage_maybe_setup_viewport (stage, view);
|
||||
clutter_stage_do_paint_view (stage, view, rect);
|
||||
region = cairo_region_create_rectangle (rect);
|
||||
clutter_stage_do_paint_view (stage, view, region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
|
||||
view_scale = clutter_stage_view_get_scale (view);
|
||||
@ -4477,49 +4309,42 @@ capture_view_into (ClutterStage *stage,
|
||||
cogl_object_unref (bitmap);
|
||||
}
|
||||
|
||||
static ClutterStageView *
|
||||
get_view_at_rect (ClutterStage *stage,
|
||||
cairo_rectangle_int_t *rect)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
GList *views = _clutter_stage_window_get_views (priv->impl);
|
||||
GList *l;
|
||||
|
||||
for (l = views; l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
cairo_rectangle_int_t view_layout;
|
||||
cairo_region_t *region;
|
||||
cairo_rectangle_int_t view_capture_rect;
|
||||
|
||||
clutter_stage_view_get_layout (view, &view_layout);
|
||||
region = cairo_region_create_rectangle (&view_layout);
|
||||
cairo_region_intersect_rectangle (region, rect);
|
||||
cairo_region_get_extents (region, &view_capture_rect);
|
||||
cairo_region_destroy (region);
|
||||
|
||||
if (view_capture_rect.width == 0 || view_capture_rect.height == 0)
|
||||
continue;
|
||||
|
||||
g_assert (view_capture_rect.width == rect->width &&
|
||||
view_capture_rect.height == rect->height);
|
||||
return view;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_capture_into (ClutterStage *stage,
|
||||
gboolean paint,
|
||||
cairo_rectangle_int_t *rect,
|
||||
uint8_t *data)
|
||||
{
|
||||
ClutterStageView *view;
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
GList *l;
|
||||
int bpp = 4;
|
||||
int stride;
|
||||
|
||||
view = get_view_at_rect (stage, rect);
|
||||
capture_view_into (stage, paint, view, rect, data, rect->width * bpp);
|
||||
stride = rect->width * 4;
|
||||
|
||||
for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
cairo_rectangle_int_t view_layout;
|
||||
cairo_region_t *region;
|
||||
cairo_rectangle_int_t capture_rect;
|
||||
int x_offset, y_offset;
|
||||
|
||||
clutter_stage_view_get_layout (view, &view_layout);
|
||||
region = cairo_region_create_rectangle (&view_layout);
|
||||
cairo_region_intersect_rectangle (region, rect);
|
||||
|
||||
cairo_region_get_extents (region, &capture_rect);
|
||||
cairo_region_destroy (region);
|
||||
|
||||
x_offset = capture_rect.x - rect->x;
|
||||
y_offset = capture_rect.y - rect->y;
|
||||
|
||||
capture_view_into (stage, paint, view,
|
||||
&capture_rect,
|
||||
data + (x_offset * bpp) + (y_offset * stride),
|
||||
stride);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4577,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;
|
||||
|
||||
|
@ -84,8 +84,9 @@ struct _ClutterStageClass
|
||||
gboolean (* delete_event) (ClutterStage *stage,
|
||||
ClutterEvent *event);
|
||||
|
||||
void (* paint_view) (ClutterStage *stage,
|
||||
ClutterStageView *view);
|
||||
void (* paint_view) (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip);
|
||||
|
||||
/*< private >*/
|
||||
/* padding for future expansion */
|
||||
@ -102,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
|
||||
*/
|
||||
@ -139,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
|
||||
@ -185,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);
|
||||
|
||||
@ -205,8 +193,6 @@ guchar * clutter_stage_read_pixels (ClutterStage
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
cairo_region_t * clutter_stage_get_redraw_clip (ClutterStage *stage);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_ensure_viewport (ClutterStage *stage);
|
||||
CLUTTER_EXPORT
|
||||
@ -234,8 +220,8 @@ CLUTTER_EXPORT
|
||||
gboolean clutter_stage_capture (ClutterStage *stage,
|
||||
gboolean paint,
|
||||
cairo_rectangle_int_t *rect,
|
||||
ClutterCapture **captures,
|
||||
int *n_captures);
|
||||
ClutterCapture **out_captures,
|
||||
int *out_n_captures);
|
||||
CLUTTER_EXPORT
|
||||
ClutterStageView * clutter_stage_get_view_at (ClutterStage *stage,
|
||||
float x,
|
||||
|
@ -348,13 +348,23 @@ clutter_text_input_focus_request_surrounding (ClutterInputFocus *focus)
|
||||
|
||||
static void
|
||||
clutter_text_input_focus_delete_surrounding (ClutterInputFocus *focus,
|
||||
guint offset,
|
||||
int offset,
|
||||
guint len)
|
||||
{
|
||||
ClutterText *clutter_text = CLUTTER_TEXT_INPUT_FOCUS (focus)->text;
|
||||
int cursor;
|
||||
int start;
|
||||
|
||||
cursor = clutter_text_get_cursor_position (clutter_text);
|
||||
start = cursor + offset;
|
||||
if (start < 0)
|
||||
{
|
||||
g_warning ("The offset '%d' of deleting surrounding is larger than the cursor pos '%d'",
|
||||
offset, cursor);
|
||||
return;
|
||||
}
|
||||
if (clutter_text_get_editable (clutter_text))
|
||||
clutter_text_delete_text (clutter_text, offset, len);
|
||||
clutter_text_delete_text (clutter_text, start, len);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1897,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,
|
||||
@ -1913,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,
|
||||
@ -1955,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,6 +214,16 @@ _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1,
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_util_rectangle_equal (const cairo_rectangle_int_t *src1,
|
||||
const cairo_rectangle_int_t *src2)
|
||||
{
|
||||
return ((src1->x == src2->x) &&
|
||||
(src1->y == src2->y) &&
|
||||
(src1->width == src2->width) &&
|
||||
(src1->height == src2->height));
|
||||
}
|
||||
|
||||
float
|
||||
_clutter_util_matrix_determinant (const ClutterMatrix *matrix)
|
||||
{
|
||||
|
@ -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"
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include "clutter-stage-private.h"
|
||||
#include "clutter-stage-view-private.h"
|
||||
|
||||
#include "cogl/cogl-trace.h"
|
||||
#define MAX_STACK_RECTS 256
|
||||
|
||||
typedef struct _ClutterStageViewCoglPrivate
|
||||
{
|
||||
@ -288,97 +288,6 @@ clutter_stage_cogl_resize (ClutterStageWindow *stage_window,
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_stage_cogl_has_redraw_clips (ClutterStageWindow *stage_window)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||
|
||||
/* NB: at the start of each new frame there is an implied clip that
|
||||
* clips everything (i.e. nothing would be drawn) so we need to make
|
||||
* sure we return True in the un-initialized case here.
|
||||
*/
|
||||
if (!stage_cogl->initialized_redraw_clip ||
|
||||
(stage_cogl->initialized_redraw_clip &&
|
||||
stage_cogl->redraw_clip))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_stage_cogl_ignoring_redraw_clips (ClutterStageWindow *stage_window)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||
|
||||
/* NB: a NULL clip means a full stage redraw is required */
|
||||
if (stage_cogl->initialized_redraw_clip &&
|
||||
!stage_cogl->redraw_clip)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* A redraw clip represents (in stage coordinates) the bounding box of
|
||||
* something that needs to be redrawn. Typically they are added to the
|
||||
* StageWindow as a result of clutter_actor_queue_clipped_redraw() by
|
||||
* actors such as ClutterGLXTexturePixmap. All redraw clips are
|
||||
* discarded after the next paint.
|
||||
*
|
||||
* A NULL stage_clip means the whole stage needs to be redrawn.
|
||||
*
|
||||
* What we do with this information:
|
||||
* - we keep track of the bounding box for all redraw clips
|
||||
* - when we come to redraw; we scissor the redraw to that box and use
|
||||
* glBlitFramebuffer to present the redraw to the front
|
||||
* buffer.
|
||||
*/
|
||||
static void
|
||||
clutter_stage_cogl_add_redraw_clip (ClutterStageWindow *stage_window,
|
||||
cairo_rectangle_int_t *stage_clip)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||
|
||||
/* If we are already forced to do a full stage redraw then bail early */
|
||||
if (clutter_stage_cogl_ignoring_redraw_clips (stage_window))
|
||||
return;
|
||||
|
||||
/* A NULL stage clip means a full stage redraw has been queued and
|
||||
* we keep track of this by setting a NULL redraw_clip.
|
||||
*/
|
||||
if (stage_clip == NULL)
|
||||
{
|
||||
g_clear_pointer (&stage_cogl->redraw_clip, cairo_region_destroy);
|
||||
stage_cogl->initialized_redraw_clip = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ignore requests to add degenerate/empty clip rectangles */
|
||||
if (stage_clip->width == 0 || stage_clip->height == 0)
|
||||
return;
|
||||
|
||||
if (!stage_cogl->redraw_clip)
|
||||
{
|
||||
stage_cogl->redraw_clip = cairo_region_create_rectangle (stage_clip);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_region_union_rectangle (stage_cogl->redraw_clip, stage_clip);
|
||||
}
|
||||
|
||||
stage_cogl->initialized_redraw_clip = TRUE;
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
clutter_stage_cogl_get_redraw_clip (ClutterStageWindow *stage_window)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||
|
||||
if (stage_cogl->using_clipped_redraw && stage_cogl->redraw_clip)
|
||||
return cairo_region_copy (stage_cogl->redraw_clip);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
valid_buffer_age (ClutterStageViewCogl *view_cogl,
|
||||
int age)
|
||||
@ -395,7 +304,8 @@ valid_buffer_age (ClutterStageViewCogl *view_cogl,
|
||||
static void
|
||||
paint_damage_region (ClutterStageWindow *stage_window,
|
||||
ClutterStageView *view,
|
||||
cairo_region_t *swap_region)
|
||||
cairo_region_t *swap_region,
|
||||
cairo_region_t *queued_redraw_clip)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
|
||||
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
|
||||
@ -432,8 +342,7 @@ paint_damage_region (ClutterStageWindow *stage_window,
|
||||
}
|
||||
|
||||
/* Red for the clip */
|
||||
if (stage_cogl->initialized_redraw_clip &&
|
||||
stage_cogl->redraw_clip)
|
||||
if (queued_redraw_clip)
|
||||
{
|
||||
static CoglPipeline *overlay_red = NULL;
|
||||
|
||||
@ -443,13 +352,13 @@ paint_damage_region (ClutterStageWindow *stage_window,
|
||||
cogl_pipeline_set_color4ub (overlay_red, 0x33, 0x00, 0x00, 0x33);
|
||||
}
|
||||
|
||||
n_rects = cairo_region_num_rectangles (stage_cogl->redraw_clip);
|
||||
n_rects = cairo_region_num_rectangles (queued_redraw_clip);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
float x_1, x_2, y_1, y_2;
|
||||
|
||||
cairo_region_get_rectangle (stage_cogl->redraw_clip, i, &rect);
|
||||
cairo_region_get_rectangle (queued_redraw_clip, i, &rect);
|
||||
x_1 = rect.x;
|
||||
x_2 = rect.x + rect.width;
|
||||
y_1 = rect.y;
|
||||
@ -471,9 +380,6 @@ swap_framebuffer (ClutterStageWindow *stage_window,
|
||||
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);
|
||||
|
||||
n_rects = cairo_region_num_rectangles (swap_region);
|
||||
damage = g_newa (int, n_rects * 4);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
@ -536,34 +442,52 @@ scale_and_clamp_rect (const graphene_rect_t *rect,
|
||||
_clutter_util_rectangle_int_extents (&tmp, dest);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
offset_scale_and_clamp_region (const cairo_region_t *region,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
float scale)
|
||||
{
|
||||
int n_rects, i;
|
||||
cairo_rectangle_int_t *rects;
|
||||
g_autofree cairo_rectangle_int_t *freeme = NULL;
|
||||
|
||||
n_rects = cairo_region_num_rectangles (region);
|
||||
|
||||
if (n_rects == 0)
|
||||
return cairo_region_create ();
|
||||
|
||||
if (n_rects < MAX_STACK_RECTS)
|
||||
rects = g_newa (cairo_rectangle_int_t, n_rects);
|
||||
else
|
||||
rects = freeme = g_new (cairo_rectangle_int_t, n_rects);
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
cairo_region_get_rectangle (region, i, &rects[i]);
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
graphene_rect_t tmp;
|
||||
|
||||
_clutter_util_rect_from_rectangle (&rects[i], &tmp);
|
||||
graphene_rect_offset (&tmp, offset_x, offset_y);
|
||||
scale_and_clamp_rect (&tmp, scale, &rects[i]);
|
||||
}
|
||||
|
||||
return cairo_region_create_rectangles (rects, n_rects);
|
||||
}
|
||||
|
||||
static void
|
||||
paint_stage (ClutterStageCogl *stage_cogl,
|
||||
ClutterStageView *view,
|
||||
cairo_region_t *clip)
|
||||
paint_stage (ClutterStageCogl *stage_cogl,
|
||||
ClutterStageView *view,
|
||||
cairo_region_t *redraw_clip)
|
||||
{
|
||||
ClutterStage *stage = stage_cogl->wrapper;
|
||||
cairo_rectangle_int_t clip_rect;
|
||||
cairo_rectangle_int_t paint_rect;
|
||||
cairo_rectangle_int_t view_rect;
|
||||
graphene_rect_t rect;
|
||||
float fb_scale;
|
||||
|
||||
clutter_stage_view_get_layout (view, &view_rect);
|
||||
fb_scale = clutter_stage_view_get_scale (view);
|
||||
|
||||
cairo_region_get_extents (clip, &clip_rect);
|
||||
|
||||
_clutter_util_rect_from_rectangle (&clip_rect, &rect);
|
||||
scale_and_clamp_rect (&rect, 1.0f / fb_scale, &paint_rect);
|
||||
_clutter_util_rectangle_offset (&paint_rect,
|
||||
view_rect.x,
|
||||
view_rect.y,
|
||||
&paint_rect);
|
||||
|
||||
_clutter_stage_maybe_setup_viewport (stage, view);
|
||||
_clutter_stage_paint_view (stage, view, &paint_rect);
|
||||
clutter_stage_paint_view (stage, view, redraw_clip);
|
||||
|
||||
clutter_stage_view_after_paint (view, &paint_rect);
|
||||
clutter_stage_view_after_paint (view);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -683,7 +607,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
clutter_stage_view_cogl_get_instance_private (view_cogl);
|
||||
CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
|
||||
cairo_rectangle_int_t view_rect;
|
||||
gboolean have_clip;
|
||||
gboolean is_full_redraw;
|
||||
gboolean may_use_clipped_redraw;
|
||||
gboolean use_clipped_redraw;
|
||||
gboolean can_blit_sub_buffer;
|
||||
@ -691,7 +615,8 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
gboolean do_swap_buffer;
|
||||
gboolean swap_with_damage;
|
||||
ClutterActor *wrapper;
|
||||
cairo_region_t *redraw_clip = NULL;
|
||||
cairo_region_t *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;
|
||||
@ -699,6 +624,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
float fb_scale;
|
||||
int subpixel_compensation = 0;
|
||||
int fb_width, fb_height;
|
||||
int buffer_age;
|
||||
|
||||
wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
|
||||
|
||||
@ -713,55 +639,46 @@ 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 (!stage_cogl->redraw_clip)
|
||||
have_clip = FALSE;
|
||||
if (!redraw_clip)
|
||||
is_full_redraw = TRUE;
|
||||
else
|
||||
is_full_redraw = FALSE;
|
||||
|
||||
may_use_clipped_redraw =
|
||||
_clutter_stage_window_can_clip_redraws (stage_window) &&
|
||||
(can_blit_sub_buffer || has_buffer_age) &&
|
||||
!is_full_redraw &&
|
||||
/* some drivers struggle to get going and produce some junk
|
||||
* frames when starting up... */
|
||||
cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3;
|
||||
|
||||
if (has_buffer_age)
|
||||
{
|
||||
cairo_region_t *view_region;
|
||||
redraw_clip = cairo_region_copy (stage_cogl->redraw_clip);
|
||||
|
||||
view_region = cairo_region_create_rectangle (&view_rect);
|
||||
cairo_region_intersect (redraw_clip, view_region);
|
||||
|
||||
have_clip = !cairo_region_equal (redraw_clip, view_region);
|
||||
cairo_region_destroy (view_region);
|
||||
buffer_age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
|
||||
if (!valid_buffer_age (view_cogl, buffer_age))
|
||||
{
|
||||
CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", buffer_age);
|
||||
may_use_clipped_redraw = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
may_use_clipped_redraw = FALSE;
|
||||
if (_clutter_stage_window_can_clip_redraws (stage_window) &&
|
||||
(can_blit_sub_buffer || has_buffer_age) &&
|
||||
have_clip &&
|
||||
/* some drivers struggle to get going and produce some junk
|
||||
* frames when starting up... */
|
||||
cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3)
|
||||
if (may_use_clipped_redraw)
|
||||
{
|
||||
graphene_rect_t rect;
|
||||
cairo_rectangle_int_t *rects;
|
||||
int n_rects, i;
|
||||
|
||||
may_use_clipped_redraw = TRUE;
|
||||
|
||||
fb_clip_region = cairo_region_create ();
|
||||
|
||||
n_rects = cairo_region_num_rectangles (redraw_clip);
|
||||
rects = g_new (cairo_rectangle_int_t, n_rects);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t new_fb_clip_rect;
|
||||
|
||||
cairo_region_get_rectangle (redraw_clip, i, &rects[i]);
|
||||
|
||||
_clutter_util_rect_from_rectangle (&rects[i], &rect);
|
||||
graphene_rect_offset (&rect, -view_rect.x, -view_rect.y);
|
||||
scale_and_clamp_rect (&rect, fb_scale, &new_fb_clip_rect);
|
||||
|
||||
cairo_region_union_rectangle (fb_clip_region, &new_fb_clip_rect);
|
||||
}
|
||||
g_free (rects);
|
||||
fb_clip_region = offset_scale_and_clamp_region (redraw_clip,
|
||||
-view_rect.x,
|
||||
-view_rect.y,
|
||||
fb_scale);
|
||||
|
||||
if (fb_scale != floorf (fb_scale))
|
||||
{
|
||||
int n_rects, i;
|
||||
cairo_rectangle_int_t *rects;
|
||||
|
||||
subpixel_compensation = ceilf (fb_scale);
|
||||
|
||||
n_rects = cairo_region_num_rectangles (fb_clip_region);
|
||||
@ -780,10 +697,16 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_rectangle_int_t rect = { 0, 0, view_rect.width, view_rect.height };
|
||||
fb_clip_region = cairo_region_create_rectangle (&rect);
|
||||
cairo_rectangle_int_t fb_rect;
|
||||
|
||||
fb_rect = (cairo_rectangle_int_t) {
|
||||
.width = fb_width,
|
||||
.height = fb_height,
|
||||
};
|
||||
fb_clip_region = cairo_region_create_rectangle (&fb_rect);
|
||||
|
||||
g_clear_pointer (&redraw_clip, cairo_region_destroy);
|
||||
redraw_clip = cairo_region_copy (fb_clip_region);
|
||||
redraw_clip = cairo_region_create_rectangle (&view_rect);
|
||||
}
|
||||
|
||||
if (may_use_clipped_redraw &&
|
||||
@ -799,62 +722,43 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
{
|
||||
if (use_clipped_redraw && !clip_region_empty)
|
||||
{
|
||||
int age;
|
||||
cairo_region_t *fb_damage;
|
||||
cairo_region_t *view_damage;
|
||||
int i;
|
||||
|
||||
age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
|
||||
fill_current_damage_history (view, fb_clip_region);
|
||||
|
||||
if (valid_buffer_age (view_cogl, age))
|
||||
fb_damage = cairo_region_create ();
|
||||
|
||||
for (i = 1; i <= buffer_age; i++)
|
||||
{
|
||||
graphene_rect_t rect;
|
||||
cairo_rectangle_int_t damage_region;
|
||||
cairo_rectangle_int_t *rects;
|
||||
int n_rects, i;
|
||||
int damage_index;
|
||||
|
||||
fill_current_damage_history (view, fb_clip_region);
|
||||
|
||||
for (i = 1; i <= age; i++)
|
||||
{
|
||||
cairo_region_t *fb_damage =
|
||||
view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - i - 1)];
|
||||
cairo_region_union (fb_clip_region, fb_damage);
|
||||
}
|
||||
|
||||
/* Update the redraw clip state with the extra damage. */
|
||||
n_rects = cairo_region_num_rectangles (fb_clip_region);
|
||||
rects = g_newa (cairo_rectangle_int_t, n_rects);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_region_get_rectangle (fb_clip_region, i, &rects[i]);
|
||||
_clutter_util_rect_from_rectangle (&rects[i], &rect);
|
||||
scale_and_clamp_rect (&rect, 1.0f / fb_scale, &damage_region);
|
||||
_clutter_util_rectangle_offset (&damage_region,
|
||||
view_rect.x,
|
||||
view_rect.y,
|
||||
&damage_region);
|
||||
cairo_region_union_rectangle (stage_cogl->redraw_clip,
|
||||
&damage_region);
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: num rects: %d\n",
|
||||
age,
|
||||
cairo_region_num_rectangles (fb_clip_region));
|
||||
|
||||
swap_with_damage = TRUE;
|
||||
damage_index = DAMAGE_HISTORY (view_priv->damage_index - i - 1);
|
||||
cairo_region_union (fb_damage,
|
||||
view_priv->damage_history[damage_index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_rectangle_int_t fb_damage;
|
||||
|
||||
CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", age);
|
||||
use_clipped_redraw = FALSE;
|
||||
fb_damage = (cairo_rectangle_int_t) {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = ceilf (view_rect.width * fb_scale),
|
||||
.height = ceilf (view_rect.height * fb_scale)
|
||||
};
|
||||
fill_current_damage_history_rectangle (view, &fb_damage);
|
||||
}
|
||||
/* Update the fb clip region with the extra damage. */
|
||||
cairo_region_union (fb_clip_region, fb_damage);
|
||||
|
||||
view_damage = offset_scale_and_clamp_region (fb_damage,
|
||||
0, 0,
|
||||
1.0f / fb_scale);
|
||||
cairo_region_translate (view_damage, view_rect.x, view_rect.y);
|
||||
cairo_region_intersect_rectangle (view_damage, &view_rect);
|
||||
|
||||
/* Update the redraw clip region with the extra damage. */
|
||||
cairo_region_union (redraw_clip, view_damage);
|
||||
|
||||
cairo_region_destroy (view_damage);
|
||||
cairo_region_destroy (fb_damage);
|
||||
|
||||
CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: num rects: %d\n",
|
||||
buffer_age,
|
||||
cairo_region_num_rectangles (fb_clip_region));
|
||||
|
||||
swap_with_damage = TRUE;
|
||||
}
|
||||
else if (!use_clipped_redraw)
|
||||
{
|
||||
@ -879,8 +783,6 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
cairo_rectangle_int_t clip_rect;
|
||||
cairo_rectangle_int_t scissor_rect;
|
||||
|
||||
stage_cogl->using_clipped_redraw = TRUE;
|
||||
|
||||
if (cairo_region_num_rectangles (fb_clip_region) == 1)
|
||||
{
|
||||
cairo_region_get_extents (fb_clip_region, &clip_rect);
|
||||
@ -908,11 +810,9 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
cogl_framebuffer_push_region_clip (fb, fb_clip_region);
|
||||
}
|
||||
|
||||
paint_stage (stage_cogl, view, fb_clip_region);
|
||||
paint_stage (stage_cogl, view, redraw_clip);
|
||||
|
||||
cogl_framebuffer_pop_clip (fb);
|
||||
|
||||
stage_cogl->using_clipped_redraw = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -940,24 +840,13 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
scissor_rect.width,
|
||||
scissor_rect.height);
|
||||
|
||||
paint_stage (stage_cogl, view, fb_clip_region);
|
||||
paint_stage (stage_cogl, view, redraw_clip);
|
||||
|
||||
cogl_framebuffer_pop_clip (fb);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_rectangle_int_t clip;
|
||||
cairo_region_t *view_region;
|
||||
|
||||
clip = (cairo_rectangle_int_t) {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = ceilf (view_rect.width * fb_scale),
|
||||
.height = ceilf (view_rect.height * fb_scale)
|
||||
};
|
||||
view_region = cairo_region_create_rectangle (&clip);
|
||||
paint_stage (stage_cogl, view, view_region);
|
||||
cairo_region_destroy (view_region);
|
||||
paint_stage (stage_cogl, view, redraw_clip);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1028,10 +917,8 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
do_swap_buffer = TRUE;
|
||||
}
|
||||
|
||||
if (redraw_clip)
|
||||
cairo_region_destroy (redraw_clip);
|
||||
if (fb_clip_region)
|
||||
cairo_region_destroy (fb_clip_region);
|
||||
g_clear_pointer (&redraw_clip, cairo_region_destroy);
|
||||
g_clear_pointer (&fb_clip_region, cairo_region_destroy);
|
||||
|
||||
if (do_swap_buffer)
|
||||
{
|
||||
@ -1051,6 +938,13 @@ 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,
|
||||
@ -1062,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)
|
||||
{
|
||||
@ -1078,9 +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;
|
||||
|
||||
swap_event =
|
||||
clutter_stage_cogl_redraw_view (stage_window, view) || swap_event;
|
||||
if (!clutter_stage_view_has_redraw_clip (view))
|
||||
continue;
|
||||
|
||||
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);
|
||||
@ -1096,10 +1019,6 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
stage_cogl->pending_swaps++;
|
||||
}
|
||||
|
||||
/* reset the redraw clipping for the next paint... */
|
||||
stage_cogl->initialized_redraw_clip = FALSE;
|
||||
g_clear_pointer (&stage_cogl->redraw_clip, cairo_region_destroy);
|
||||
|
||||
stage_cogl->frame_count++;
|
||||
|
||||
COGL_TRACE_END (ClutterStageCoglRedraw);
|
||||
@ -1117,10 +1036,6 @@ clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
|
||||
iface->schedule_update = clutter_stage_cogl_schedule_update;
|
||||
iface->get_update_time = clutter_stage_cogl_get_update_time;
|
||||
iface->clear_update_time = clutter_stage_cogl_clear_update_time;
|
||||
iface->add_redraw_clip = clutter_stage_cogl_add_redraw_clip;
|
||||
iface->has_redraw_clips = clutter_stage_cogl_has_redraw_clips;
|
||||
iface->ignoring_redraw_clips = clutter_stage_cogl_ignoring_redraw_clips;
|
||||
iface->get_redraw_clip = clutter_stage_cogl_get_redraw_clip;
|
||||
iface->redraw = clutter_stage_cogl_redraw;
|
||||
}
|
||||
|
||||
|
@ -55,14 +55,6 @@ struct _ClutterStageCogl
|
||||
unsigned int frame_count;
|
||||
|
||||
gint last_sync_delay;
|
||||
|
||||
cairo_region_t *redraw_clip;
|
||||
|
||||
guint initialized_redraw_clip : 1;
|
||||
|
||||
/* TRUE if the current paint cycle has a clipped redraw. In that
|
||||
case bounding_redraw_clip specifies the the bounds. */
|
||||
guint using_clipped_redraw : 1;
|
||||
};
|
||||
|
||||
struct _ClutterStageCoglClass
|
||||
|
@ -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
|
||||
|
@ -81,6 +81,7 @@ struct _CoglPangoDisplayListNode
|
||||
GArray *rectangles;
|
||||
/* A primitive representing those vertices */
|
||||
CoglPrimitive *primitive;
|
||||
guint has_color : 1;
|
||||
} texture;
|
||||
|
||||
struct
|
||||
@ -420,7 +421,9 @@ _cogl_pango_display_list_render (CoglFramebuffer *fb,
|
||||
cogl_color_get_red_byte (&node->color),
|
||||
cogl_color_get_green_byte (&node->color),
|
||||
cogl_color_get_blue_byte (&node->color),
|
||||
cogl_color_get_alpha_byte (color));
|
||||
(cogl_color_get_alpha_byte (&node->color) *
|
||||
cogl_color_get_alpha_byte (color) /
|
||||
255));
|
||||
else
|
||||
draw_color = *color;
|
||||
cogl_color_premultiply (&draw_color);
|
||||
|
@ -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;
|
||||
|
@ -58,27 +58,29 @@ struct _CoglPangoGlyphCacheValue
|
||||
|
||||
/* This will be set to TRUE when the glyph atlas is reorganized
|
||||
which means the glyph will need to be redrawn */
|
||||
gboolean dirty;
|
||||
guint dirty : 1;
|
||||
/* Set to TRUE if the glyph has colors (eg. emoji) */
|
||||
guint has_color : 1;
|
||||
};
|
||||
|
||||
typedef void (* CoglPangoGlyphCacheDirtyFunc) (PangoFont *font,
|
||||
PangoGlyph glyph,
|
||||
CoglPangoGlyphCacheValue *value);
|
||||
|
||||
CoglPangoGlyphCache *
|
||||
COGL_EXPORT CoglPangoGlyphCache *
|
||||
cogl_pango_glyph_cache_new (CoglContext *ctx,
|
||||
gboolean use_mipmapping);
|
||||
|
||||
void
|
||||
COGL_EXPORT void
|
||||
cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache);
|
||||
|
||||
CoglPangoGlyphCacheValue *
|
||||
COGL_EXPORT CoglPangoGlyphCacheValue *
|
||||
cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
|
||||
gboolean create,
|
||||
PangoFont *font,
|
||||
PangoGlyph glyph);
|
||||
|
||||
void
|
||||
COGL_EXPORT void
|
||||
cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache);
|
||||
|
||||
void
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <pango/pangocairo.h>
|
||||
#include <pango/pango-renderer.h>
|
||||
#include <cairo.h>
|
||||
#include <cairo-ft.h>
|
||||
|
||||
#include "cogl/cogl-debug.h"
|
||||
#include "cogl/cogl-context-private.h"
|
||||
@ -526,6 +527,24 @@ cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer,
|
||||
create, font, glyph);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
font_has_color_glyphs (const PangoFont *font)
|
||||
{
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
gboolean has_color = FALSE;
|
||||
|
||||
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *) font);
|
||||
|
||||
if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
|
||||
{
|
||||
FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
|
||||
has_color = (FT_HAS_COLOR (ft_face) != 0);
|
||||
cairo_ft_scaled_font_unlock_face (scaled_font);
|
||||
}
|
||||
|
||||
return has_color;
|
||||
}
|
||||
|
||||
static void
|
||||
cogl_pango_renderer_set_dirty_glyph (PangoFont *font,
|
||||
PangoGlyph glyph,
|
||||
@ -600,6 +619,8 @@ cogl_pango_renderer_set_dirty_glyph (PangoFont *font,
|
||||
cairo_image_surface_get_data (surface));
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
value->has_color = font_has_color_glyphs (font);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -698,6 +719,7 @@ cogl_pango_renderer_set_color_for_part (PangoRenderer *renderer,
|
||||
PangoRenderPart part)
|
||||
{
|
||||
PangoColor *pango_color = pango_renderer_get_color (renderer, part);
|
||||
uint16_t alpha = pango_renderer_get_alpha (renderer, part);
|
||||
CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
|
||||
|
||||
if (pango_color)
|
||||
@ -708,7 +730,7 @@ cogl_pango_renderer_set_color_for_part (PangoRenderer *renderer,
|
||||
pango_color->red >> 8,
|
||||
pango_color->green >> 8,
|
||||
pango_color->blue >> 8,
|
||||
0xff);
|
||||
alpha ? alpha >> 8 : 0xff);
|
||||
|
||||
_cogl_pango_display_list_set_color_override (priv->display_list, &color);
|
||||
}
|
||||
@ -820,14 +842,13 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
|
||||
CoglPangoGlyphCacheValue *cache_value;
|
||||
int i;
|
||||
|
||||
cogl_pango_renderer_set_color_for_part (renderer,
|
||||
PANGO_RENDER_PART_FOREGROUND);
|
||||
|
||||
for (i = 0; i < glyphs->num_glyphs; i++)
|
||||
{
|
||||
PangoGlyphInfo *gi = glyphs->glyphs + i;
|
||||
float x, y;
|
||||
|
||||
cogl_pango_renderer_set_color_for_part (renderer,
|
||||
PANGO_RENDER_PART_FOREGROUND);
|
||||
cogl_pango_renderer_get_device_units (renderer,
|
||||
xi + gi->geometry.x_offset,
|
||||
yi + gi->geometry.y_offset,
|
||||
@ -884,6 +905,19 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
|
||||
x += (float)(cache_value->draw_x);
|
||||
y += (float)(cache_value->draw_y);
|
||||
|
||||
/* Do not override color if the glyph/font provide its own */
|
||||
if (cache_value->has_color)
|
||||
{
|
||||
CoglColor color;
|
||||
uint16_t alpha;
|
||||
|
||||
alpha = pango_renderer_get_alpha (renderer,
|
||||
PANGO_RENDER_PART_FOREGROUND);
|
||||
cogl_color_init_from_4ub (&color, 0xff, 0xff, 0xff,
|
||||
alpha ? alpha >> 8 : 0xff);
|
||||
_cogl_pango_display_list_set_color_override (priv->display_list, &color);
|
||||
}
|
||||
|
||||
cogl_pango_renderer_draw_glyph (priv, cache_value, x, y);
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ typedef PangoCairoFontMap CoglPangoFontMap;
|
||||
*
|
||||
* Since: 1.14
|
||||
*/
|
||||
PangoFontMap *
|
||||
COGL_EXPORT PangoFontMap *
|
||||
cogl_pango_font_map_new (void);
|
||||
|
||||
/**
|
||||
@ -86,7 +86,7 @@ cogl_pango_font_map_new (void);
|
||||
*
|
||||
* Returns: (transfer full): the newly created context: free with g_object_unref().
|
||||
*/
|
||||
PangoContext *
|
||||
COGL_EXPORT PangoContext *
|
||||
cogl_pango_font_map_create_context (CoglPangoFontMap *font_map);
|
||||
|
||||
/**
|
||||
@ -102,7 +102,7 @@ cogl_pango_font_map_create_context (CoglPangoFontMap *font_map);
|
||||
*
|
||||
* Since: 1.14
|
||||
*/
|
||||
void
|
||||
COGL_EXPORT void
|
||||
cogl_pango_font_map_set_resolution (CoglPangoFontMap *font_map,
|
||||
double dpi);
|
||||
|
||||
@ -114,7 +114,7 @@ cogl_pango_font_map_set_resolution (CoglPangoFontMap *font_map,
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void
|
||||
COGL_EXPORT void
|
||||
cogl_pango_font_map_clear_glyph_cache (CoglPangoFontMap *font_map);
|
||||
|
||||
/**
|
||||
@ -129,7 +129,7 @@ cogl_pango_font_map_clear_glyph_cache (CoglPangoFontMap *font_map);
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void
|
||||
COGL_EXPORT void
|
||||
cogl_pango_ensure_glyph_cache_for_layout (PangoLayout *layout);
|
||||
|
||||
/**
|
||||
@ -142,7 +142,7 @@ cogl_pango_ensure_glyph_cache_for_layout (PangoLayout *layout);
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void
|
||||
COGL_EXPORT void
|
||||
cogl_pango_font_map_set_use_mipmapping (CoglPangoFontMap *font_map,
|
||||
gboolean value);
|
||||
|
||||
@ -157,7 +157,7 @@ cogl_pango_font_map_set_use_mipmapping (CoglPangoFontMap *font_map,
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
gboolean
|
||||
COGL_EXPORT gboolean
|
||||
cogl_pango_font_map_get_use_mipmapping (CoglPangoFontMap *font_map);
|
||||
|
||||
/**
|
||||
@ -170,7 +170,7 @@ cogl_pango_font_map_get_use_mipmapping (CoglPangoFontMap *font_map);
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
PangoRenderer *
|
||||
COGL_EXPORT PangoRenderer *
|
||||
cogl_pango_font_map_get_renderer (CoglPangoFontMap *font_map);
|
||||
|
||||
/**
|
||||
@ -187,7 +187,7 @@ cogl_pango_font_map_get_renderer (CoglPangoFontMap *font_map);
|
||||
*
|
||||
* Since: 1.14
|
||||
*/
|
||||
void
|
||||
COGL_EXPORT void
|
||||
cogl_pango_show_layout (CoglFramebuffer *framebuffer,
|
||||
PangoLayout *layout,
|
||||
float x,
|
||||
@ -208,7 +208,7 @@ cogl_pango_show_layout (CoglFramebuffer *framebuffer,
|
||||
*
|
||||
* Since: 1.14
|
||||
*/
|
||||
void
|
||||
COGL_EXPORT void
|
||||
cogl_pango_show_layout_line (CoglFramebuffer *framebuffer,
|
||||
PangoLayoutLine *line,
|
||||
float x,
|
||||
@ -227,7 +227,7 @@ cogl_pango_show_layout_line (CoglFramebuffer *framebuffer,
|
||||
typedef struct _CoglPangoRenderer CoglPangoRenderer;
|
||||
typedef struct _CoglPangoRendererClass CoglPangoRendererClass;
|
||||
|
||||
GType cogl_pango_renderer_get_type (void) G_GNUC_CONST;
|
||||
COGL_EXPORT GType cogl_pango_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
global:
|
||||
cogl_pango_*;
|
||||
local:
|
||||
*;
|
||||
};
|
@ -20,19 +20,13 @@ cogl_pango_deps = [
|
||||
libmutter_cogl_dep,
|
||||
]
|
||||
|
||||
libmutter_cogl_pango_map = 'libmutter-cogl-pango.map'
|
||||
libmutter_cogl_pango_link_args = [
|
||||
'-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(),
|
||||
libmutter_cogl_pango_map),
|
||||
]
|
||||
libmutter_cogl_pango = shared_library('mutter-cogl-pango-' + libmutter_api_version,
|
||||
sources: [cogl_pango_sources, cogl_pango_public_headers],
|
||||
version: '0.0.0',
|
||||
soversion: 0,
|
||||
c_args: cogl_c_args,
|
||||
include_directories: [cogl_includepath, cogl_path_includepath],
|
||||
link_depends: libmutter_cogl_pango_map,
|
||||
link_args: libmutter_cogl_pango_link_args,
|
||||
include_directories: [cogl_includepath],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
dependencies: [cogl_pango_deps],
|
||||
install_rpath: pkglibdir,
|
||||
install_dir: 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,486 +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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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,17 +0,0 @@
|
||||
{
|
||||
global:
|
||||
cogl_framebuffer_*;
|
||||
cogl_path_*;
|
||||
cogl_is_*;
|
||||
cogl_clip_*;
|
||||
cogl_get_*;
|
||||
cogl_set_*;
|
||||
cogl2_framebuffer_*;
|
||||
cogl2_path_*;
|
||||
cogl2_is_*;
|
||||
cogl2_clip_*;
|
||||
cogl2_get_*;
|
||||
cogl2_set_*;
|
||||
local:
|
||||
*;
|
||||
};
|
@ -1,93 +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_map = 'libmutter-cogl-path.map'
|
||||
libmutter_cogl_path_link_args = [
|
||||
'-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(),
|
||||
libmutter_cogl_path_map),
|
||||
]
|
||||
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],
|
||||
link_depends: libmutter_cogl_path_map,
|
||||
link_args: libmutter_cogl_path_link_args,
|
||||
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;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user