010f98b083
We just set the input region to the bounding box of the window frame and set the opaque region to be the opaque rectangle inside the window if the child widget is opaque.
382 lines
10 KiB
C
382 lines
10 KiB
C
/*
|
|
* Copyright © 2008 Kristian Høgsberg
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
* that the name of the copyright holders not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. The copyright holders make no representations
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
* is" without express or implied warranty.
|
|
*
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include <glib.h>
|
|
|
|
#include <GL/gl.h>
|
|
#include <EGL/egl.h>
|
|
#include <EGL/eglext.h>
|
|
|
|
#include <wayland-client.h>
|
|
|
|
#include "window.h"
|
|
|
|
struct gears {
|
|
struct window *window;
|
|
struct widget *widget;
|
|
|
|
struct display *d;
|
|
|
|
EGLDisplay display;
|
|
EGLDisplay config;
|
|
EGLContext context;
|
|
GLfloat angle;
|
|
|
|
GLint gear_list[3];
|
|
};
|
|
|
|
struct gear_template {
|
|
GLfloat material[4];
|
|
GLfloat inner_radius;
|
|
GLfloat outer_radius;
|
|
GLfloat width;
|
|
GLint teeth;
|
|
GLfloat tooth_depth;
|
|
};
|
|
|
|
const static struct gear_template gear_templates[] = {
|
|
{ { 0.8, 0.1, 0.0, 1.0 }, 1.0, 4.0, 1.0, 20, 0.7 },
|
|
{ { 0.0, 0.8, 0.2, 1.0 }, 0.5, 2.0, 2.0, 10, 0.7 },
|
|
{ { 0.2, 0.2, 1.0, 1.0 }, 1.3, 2.0, 0.5, 10, 0.7 },
|
|
};
|
|
|
|
static GLfloat light_pos[4] = {5.0, 5.0, 10.0, 0.0};
|
|
|
|
static void die(const char *msg)
|
|
{
|
|
fprintf(stderr, "%s", msg);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
static void
|
|
make_gear(const struct gear_template *t)
|
|
{
|
|
GLint i;
|
|
GLfloat r0, r1, r2;
|
|
GLfloat angle, da;
|
|
GLfloat u, v, len;
|
|
|
|
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->material);
|
|
|
|
r0 = t->inner_radius;
|
|
r1 = t->outer_radius - t->tooth_depth / 2.0;
|
|
r2 = t->outer_radius + t->tooth_depth / 2.0;
|
|
|
|
da = 2.0 * M_PI / t->teeth / 4.0;
|
|
|
|
glShadeModel(GL_FLAT);
|
|
|
|
glNormal3f(0.0, 0.0, 1.0);
|
|
|
|
/* draw front face */
|
|
glBegin(GL_QUAD_STRIP);
|
|
for (i = 0; i <= t->teeth; i++) {
|
|
angle = i * 2.0 * M_PI / t->teeth;
|
|
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
|
|
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
|
|
if (i < t->teeth) {
|
|
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
|
|
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
|
|
}
|
|
}
|
|
glEnd();
|
|
|
|
/* draw front sides of teeth */
|
|
glBegin(GL_QUADS);
|
|
da = 2.0 * M_PI / t->teeth / 4.0;
|
|
for (i = 0; i < t->teeth; i++) {
|
|
angle = i * 2.0 * M_PI / t->teeth;
|
|
|
|
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
|
|
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
|
|
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
|
|
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
|
|
}
|
|
glEnd();
|
|
|
|
glNormal3f(0.0, 0.0, -1.0);
|
|
|
|
/* draw back face */
|
|
glBegin(GL_QUAD_STRIP);
|
|
for (i = 0; i <= t->teeth; i++) {
|
|
angle = i * 2.0 * M_PI / t->teeth;
|
|
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
|
|
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
|
|
if (i < t->teeth) {
|
|
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
|
|
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
|
|
}
|
|
}
|
|
glEnd();
|
|
|
|
/* draw back sides of teeth */
|
|
glBegin(GL_QUADS);
|
|
da = 2.0 * M_PI / t->teeth / 4.0;
|
|
for (i = 0; i < t->teeth; i++) {
|
|
angle = i * 2.0 * M_PI / t->teeth;
|
|
|
|
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
|
|
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
|
|
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
|
|
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
|
|
}
|
|
glEnd();
|
|
|
|
/* draw outward faces of teeth */
|
|
glBegin(GL_QUAD_STRIP);
|
|
for (i = 0; i < t->teeth; i++) {
|
|
angle = i * 2.0 * M_PI / t->teeth;
|
|
|
|
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
|
|
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
|
|
u = r2 * cos(angle + da) - r1 * cos(angle);
|
|
v = r2 * sin(angle + da) - r1 * sin(angle);
|
|
len = sqrt(u * u + v * v);
|
|
u /= len;
|
|
v /= len;
|
|
glNormal3f(v, -u, 0.0);
|
|
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
|
|
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
|
|
glNormal3f(cos(angle), sin(angle), 0.0);
|
|
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
|
|
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
|
|
u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
|
|
v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
|
|
glNormal3f(v, -u, 0.0);
|
|
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
|
|
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
|
|
glNormal3f(cos(angle), sin(angle), 0.0);
|
|
}
|
|
|
|
glVertex3f(r1 * cos(0), r1 * sin(0), t->width * 0.5);
|
|
glVertex3f(r1 * cos(0), r1 * sin(0), -t->width * 0.5);
|
|
|
|
glEnd();
|
|
|
|
glShadeModel(GL_SMOOTH);
|
|
|
|
/* draw inside radius cylinder */
|
|
glBegin(GL_QUAD_STRIP);
|
|
for (i = 0; i <= t->teeth; i++) {
|
|
angle = i * 2.0 * M_PI / t->teeth;
|
|
glNormal3f(-cos(angle), -sin(angle), 0.0);
|
|
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
|
|
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
static void
|
|
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
|
|
{
|
|
struct gears *gears = data;
|
|
|
|
gears->angle = (GLfloat) (time % 8192) * 360 / 8192.0;
|
|
|
|
window_schedule_redraw(gears->window);
|
|
|
|
if (callback)
|
|
wl_callback_destroy(callback);
|
|
}
|
|
|
|
static const struct wl_callback_listener listener = {
|
|
frame_callback
|
|
};
|
|
|
|
static void
|
|
redraw_handler(struct widget *widget, void *data)
|
|
{
|
|
GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
|
|
struct rectangle window_allocation;
|
|
struct rectangle allocation;
|
|
struct wl_callback *callback;
|
|
struct gears *gears = data;
|
|
|
|
widget_get_allocation(gears->widget, &allocation);
|
|
window_get_allocation(gears->window, &window_allocation);
|
|
|
|
if (display_acquire_window_surface(gears->d,
|
|
gears->window,
|
|
gears->context) < 0) {
|
|
die("Unable to acquire window surface, "
|
|
"compiled without cairo-egl?\n");
|
|
}
|
|
|
|
glViewport(allocation.x,
|
|
window_allocation.height - allocation.height - allocation.y,
|
|
allocation.width, allocation.height);
|
|
glScissor(allocation.x,
|
|
window_allocation.height - allocation.height - allocation.y,
|
|
allocation.width, allocation.height);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef(0.0, 0.0, -50);
|
|
|
|
glRotatef(view_rotx, 1.0, 0.0, 0.0);
|
|
glRotatef(view_roty, 0.0, 1.0, 0.0);
|
|
glRotatef(view_rotz, 0.0, 0.0, 1.0);
|
|
|
|
glPushMatrix();
|
|
glTranslatef(-3.0, -2.0, 0.0);
|
|
glRotatef(gears->angle, 0.0, 0.0, 1.0);
|
|
glCallList(gears->gear_list[0]);
|
|
glPopMatrix();
|
|
|
|
glPushMatrix();
|
|
glTranslatef(3.1, -2.0, 0.0);
|
|
glRotatef(-2.0 * gears->angle - 9.0, 0.0, 0.0, 1.0);
|
|
glCallList(gears->gear_list[1]);
|
|
glPopMatrix();
|
|
|
|
glPushMatrix();
|
|
glTranslatef(-3.1, 4.2, 0.0);
|
|
glRotatef(-2.0 * gears->angle - 25.0, 0.0, 0.0, 1.0);
|
|
glCallList(gears->gear_list[2]);
|
|
glPopMatrix();
|
|
|
|
glPopMatrix();
|
|
|
|
glFlush();
|
|
|
|
display_release_window_surface(gears->d, gears->window);
|
|
|
|
callback = wl_surface_frame(window_get_wl_surface(gears->window));
|
|
wl_callback_add_listener(callback, &listener, gears);
|
|
}
|
|
|
|
static void
|
|
resize_handler(struct widget *widget,
|
|
int32_t width, int32_t height, void *data)
|
|
{
|
|
struct gears *gears = data;
|
|
|
|
/* Constrain child size to be square and at least 300x300 */
|
|
if (width > height)
|
|
height = width;
|
|
else
|
|
width = height;
|
|
if (width < 300) {
|
|
width = 300;
|
|
height = 300;
|
|
}
|
|
|
|
widget_set_size(gears->widget, width, height);
|
|
}
|
|
|
|
static void
|
|
keyboard_focus_handler(struct window *window,
|
|
struct input *device, void *data)
|
|
{
|
|
window_schedule_redraw(window);
|
|
}
|
|
|
|
static struct gears *
|
|
gears_create(struct display *display)
|
|
{
|
|
const int width = 450, height = 500;
|
|
struct gears *gears;
|
|
int i;
|
|
|
|
gears = malloc(sizeof *gears);
|
|
memset(gears, 0, sizeof *gears);
|
|
gears->d = display;
|
|
gears->window = window_create(display);
|
|
gears->widget = frame_create(gears->window, gears);
|
|
window_set_title(gears->window, "Wayland Gears");
|
|
|
|
gears->display = display_get_egl_display(gears->d);
|
|
if (gears->display == NULL)
|
|
die("failed to create egl display\n");
|
|
|
|
eglBindAPI(EGL_OPENGL_API);
|
|
|
|
gears->config = display_get_argb_egl_config(gears->d);
|
|
|
|
gears->context = eglCreateContext(gears->display, gears->config,
|
|
EGL_NO_CONTEXT, NULL);
|
|
if (gears->context == NULL)
|
|
die("failed to create context\n");
|
|
|
|
if (!eglMakeCurrent(gears->display, NULL, NULL, gears->context))
|
|
die("failed to make context current\n");
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
gears->gear_list[i] = glGenLists(1);
|
|
glNewList(gears->gear_list[i], GL_COMPILE);
|
|
make_gear(&gear_templates[i]);
|
|
glEndList();
|
|
}
|
|
|
|
glEnable(GL_NORMALIZE);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 200.0);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
|
|
glEnable(GL_CULL_FACE);
|
|
glEnable(GL_LIGHTING);
|
|
glEnable(GL_LIGHT0);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glClearColor(0, 0, 0, 0.92);
|
|
|
|
window_set_user_data(gears->window, gears);
|
|
widget_set_resize_handler(gears->widget, resize_handler);
|
|
widget_set_redraw_handler(gears->widget, redraw_handler);
|
|
window_set_keyboard_focus_handler(gears->window,
|
|
keyboard_focus_handler);
|
|
|
|
window_schedule_resize(gears->window, width, height);
|
|
|
|
return gears;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct display *d;
|
|
|
|
d = display_create(&argc, &argv, NULL);
|
|
if (d == NULL) {
|
|
fprintf(stderr, "failed to create display: %m\n");
|
|
return -1;
|
|
}
|
|
gears_create(d);
|
|
display_run(d);
|
|
|
|
return 0;
|
|
}
|