drop examples
This commit is contained in:
parent
8366fd5438
commit
a9e1130244
@ -14,7 +14,7 @@ if BUILD_COGL_GLES2
|
||||
SUBDIRS += cogl-gles2
|
||||
endif
|
||||
|
||||
SUBDIRS += tests examples po
|
||||
SUBDIRS += tests po
|
||||
|
||||
ACLOCAL_AMFLAGS = -I build/autotools ${ACLOCAL_FLAGS}
|
||||
|
||||
|
12
configure.ac
12
configure.ac
@ -502,17 +502,6 @@ AS_IF(
|
||||
]
|
||||
)
|
||||
|
||||
dnl ============================================================
|
||||
dnl Should examples be installed?
|
||||
dnl ============================================================
|
||||
AC_ARG_ENABLE(
|
||||
[examples-install],
|
||||
[AC_HELP_STRING([--enable-examples-install=@<:@no/yes@:>@], [Enable installation of examples @<:@default=no@:>@])],
|
||||
[],
|
||||
enable_examples_install=no
|
||||
)
|
||||
AM_CONDITIONAL([INSTALL_EXAMPLES], [test "x$enable_examples_install" = "xyes"])
|
||||
|
||||
dnl ============================================================
|
||||
dnl Determine which drivers and window systems we can support
|
||||
dnl ============================================================
|
||||
@ -1091,7 +1080,6 @@ cogl-path/cogl-path-2.0-experimental.pc
|
||||
cogl-gles2/Makefile
|
||||
cogl-gles2/cogl-gles2-1.0.pc
|
||||
cogl-gles2/cogl-gles2-2.0-experimental.pc
|
||||
examples/Makefile
|
||||
tests/Makefile
|
||||
tests/config.env
|
||||
tests/conform/Makefile
|
||||
|
@ -1,102 +0,0 @@
|
||||
include $(top_srcdir)/build/autotools/Makefile.am.silent
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)
|
||||
|
||||
if !USE_GLIB
|
||||
AM_CPPFLAGS += -I$(top_builddir)/deps/glib
|
||||
endif
|
||||
|
||||
AM_CFLAGS = \
|
||||
$(COGL_DEP_CFLAGS) \
|
||||
$(COGL_EXTRA_CFLAGS) \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API
|
||||
|
||||
if INSTALL_EXAMPLES
|
||||
AM_CFLAGS += -DCOGL_EXAMPLES_DATA=\""$(pkgdatadir)/examples-data/"\"
|
||||
else
|
||||
AM_CFLAGS += -DCOGL_EXAMPLES_DATA=\""$(abs_top_srcdir)/examples/"\"
|
||||
endif
|
||||
|
||||
common_ldadd = \
|
||||
$(COGL_DEP_LIBS) \
|
||||
$(top_builddir)/cogl/libcogl.la \
|
||||
$(LIBM)
|
||||
|
||||
if !USE_GLIB
|
||||
common_ldadd += $(top_builddir)/deps/glib/libglib.la
|
||||
endif
|
||||
|
||||
programs = cogl-info
|
||||
|
||||
cogl_info_SOURCES = cogl-info.c
|
||||
cogl_info_LDADD = $(common_ldadd)
|
||||
|
||||
if USE_GLIB
|
||||
programs += cogl-hello cogl-msaa cogl-gles2-context cogl-point-sprites cogl-stereo
|
||||
examples_datadir = $(pkgdatadir)/examples-data
|
||||
examples_data_DATA =
|
||||
|
||||
cogl_hello_SOURCES = cogl-hello.c
|
||||
cogl_hello_LDADD = $(common_ldadd)
|
||||
cogl_msaa_SOURCES = cogl-msaa.c
|
||||
cogl_msaa_LDADD = $(common_ldadd)
|
||||
cogl_point_sprites_SOURCES = cogl-point-sprites.c
|
||||
cogl_point_sprites_LDADD = $(common_ldadd)
|
||||
cogl_stereo_SOURCES = cogl-stereo.c
|
||||
cogl_stereo_LDADD = $(common_ldadd)
|
||||
|
||||
if BUILD_COGL_PANGO
|
||||
programs += cogl-crate
|
||||
cogl_crate_SOURCES = cogl-crate.c
|
||||
cogl_crate_LDADD = $(common_ldadd) $(COGL_PANGO_DEP_LIBS) $(top_builddir)/cogl-pango/libcogl-pango.la
|
||||
cogl_crate_CFLAGS = $(AM_CFLAGS) $(COGL_PANGO_DEP_CFLAGS)
|
||||
examples_data_DATA += crate.jpg
|
||||
endif
|
||||
|
||||
if X11_TESTS
|
||||
programs += cogl-x11-foreign cogl-x11-tfp
|
||||
cogl_x11_foreign_SOURCES = cogl-x11-foreign.c
|
||||
cogl_x11_foreign_LDADD = $(common_ldadd)
|
||||
cogl_x11_tfp_SOURCES = cogl-x11-tfp.c
|
||||
cogl_x11_tfp_LDADD = $(common_ldadd)
|
||||
endif
|
||||
|
||||
if SUPPORT_WAYLAND_EGL_SERVER
|
||||
# Note: Cogland currently only builds for Wayland 0.85
|
||||
programs += cogland
|
||||
cogland_SOURCES = cogland.c
|
||||
cogland_LDADD = $(common_ldadd)
|
||||
endif
|
||||
|
||||
cogl_gles2_context_SOURCES = cogl-gles2-context.c
|
||||
cogl_gles2_context_LDADD = $(common_ldadd)
|
||||
|
||||
if BUILD_COGL_GLES2
|
||||
programs += cogl-gles2-gears
|
||||
cogl_gles2_gears_SOURCES = cogl-gles2-gears.c
|
||||
cogl_gles2_gears_CFLAGS = -I$(top_srcdir)/cogl-gles2 $(AM_CFLAGS)
|
||||
cogl_gles2_gears_LDADD = $(common_ldadd) $(top_builddir)/cogl-gles2/libcogl-gles2.la
|
||||
endif
|
||||
|
||||
endif #USE_GLIB
|
||||
|
||||
if INSTALL_EXAMPLES
|
||||
bin_PROGRAMS = $(programs)
|
||||
else
|
||||
noinst_PROGRAMS = $(programs)
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
cogl-gjs.js \
|
||||
crate.jpg \
|
||||
emscripten-example-js.h \
|
||||
emscripten-example-js-library.js \
|
||||
android/hello/AndroidManifest.xml \
|
||||
android/hello/jni/Application.mk \
|
||||
android/hello/jni/Android.mk \
|
||||
android/hello/jni/main.c \
|
||||
android/hello/res/values/strings.xml \
|
||||
android/hello/.gitignore \
|
||||
android/hello/build.xml
|
||||
|
7
examples/android/hello/.gitignore
vendored
7
examples/android/hello/.gitignore
vendored
@ -1,7 +0,0 @@
|
||||
bin
|
||||
libs
|
||||
obj
|
||||
|
||||
default.properties
|
||||
local.properties
|
||||
proguard.cfg
|
@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- BEGIN_INCLUDE(manifest) -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.cogl.Hello"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<!-- This is the platform API where NativeActivity was introduced. -->
|
||||
<uses-sdk android:minSdkVersion="9" />
|
||||
|
||||
<!-- This .apk has no Java code itself, so set hasCode to false. -->
|
||||
<application android:label="@string/app_name" android:hasCode="false">
|
||||
|
||||
<!-- Our activity is the built-in NativeActivity framework class.
|
||||
This will take care of integrating with our NDK code. -->
|
||||
<activity android:name="android.app.NativeActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<!-- Tell NativeActivity the name of or .so -->
|
||||
<meta-data android:name="android.app.lib_name"
|
||||
android:value="test-cogl-hello" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
<!-- END_INCLUDE(manifest) -->
|
@ -1,84 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="TestCoglHello" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android'
|
||||
tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The build.properties file can be created by you and is never touched
|
||||
by the 'android' tool. This is the place to change some of the
|
||||
default property values used by the Ant rules.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="build.properties" />
|
||||
|
||||
<!-- The default.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<property file="default.properties" />
|
||||
|
||||
<!-- Custom Android task to deal with the project target, and import the
|
||||
proper rules.
|
||||
This requires ant 1.6.0 or above. -->
|
||||
<path id="android.antlibs">
|
||||
<pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
|
||||
<pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
|
||||
<pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
|
||||
</path>
|
||||
|
||||
<taskdef name="setup"
|
||||
classname="com.android.ant.SetupTask"
|
||||
classpathref="android.antlibs" />
|
||||
|
||||
<!-- extension targets. Uncomment the ones where you want to do custom work
|
||||
in between standard targets -->
|
||||
<!--
|
||||
<target name="-pre-build">
|
||||
</target>
|
||||
<target name="-pre-compile">
|
||||
</target>
|
||||
|
||||
[This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir}]
|
||||
<target name="-post-compile">
|
||||
</target>
|
||||
-->
|
||||
|
||||
|
||||
<!-- Execute the Android Setup task that will setup some properties
|
||||
specific to the target, and import the build rules files.
|
||||
|
||||
The rules file is imported from
|
||||
<SDK>/platforms/<target_platform>/ant/ant_rules_r#.xml
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<setup> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole script.
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, *after* the <setup> task
|
||||
- disable the import of the rules by changing the setup task
|
||||
below to <setup import="false" />.
|
||||
- customize to your needs.
|
||||
-->
|
||||
<setup />
|
||||
|
||||
</project>
|
@ -1,19 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := test-cogl-hello
|
||||
LOCAL_SRC_FILES := main.c
|
||||
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
|
||||
LOCAL_STATIC_LIBRARIES := cogl android_native_app_glue gobject gmodule gthread glib-android glib iconv
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_CFLAGS := \
|
||||
-DG_LOG_DOMAIN=\"TestCoglHello\" \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API \
|
||||
$(NULL)
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
$(call import-module,android/native_app_glue)
|
||||
$(call import-module,glib)
|
||||
$(call import-module,cogl)
|
@ -1 +0,0 @@
|
||||
APP_PLATFORM := android-9
|
@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* Copyright (C) 2011 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived from the "native-activity" sample of the android NDK
|
||||
* r5b. The coding style has been adapted to the code style most commonly found
|
||||
* in glib/gobject based projects.
|
||||
*/
|
||||
|
||||
#include <android_native_app_glue.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-android/glib-android.h>
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct android_app* app;
|
||||
|
||||
CoglContext *context;
|
||||
CoglPrimitive *triangle;
|
||||
CoglFramebuffer *fb;
|
||||
} TestData;
|
||||
|
||||
static int test_init (TestData* data)
|
||||
{
|
||||
CoglOnscreen *onscreen;
|
||||
CoglError *error = NULL;
|
||||
CoglVertexP2C4 triangle_vertices[] = {
|
||||
{0, 0.7, 0xff, 0x00, 0x00, 0xff},
|
||||
{-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
|
||||
{0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
|
||||
};
|
||||
|
||||
cogl_android_set_native_window (data->app->window);
|
||||
|
||||
data->context = cogl_context_new (NULL, &error);
|
||||
if (!data->context)
|
||||
{
|
||||
g_critical ("Failed to create context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (data->context, 320, 420);
|
||||
|
||||
/* Eventually there will be an implicit allocate on first use so this
|
||||
* will become optional... */
|
||||
data->fb = COGL_FRAMEBUFFER (onscreen);
|
||||
if (!cogl_framebuffer_allocate (data->fb, &error))
|
||||
{
|
||||
if (error)
|
||||
g_critical ("Failed to allocate framebuffer: %s\n", error->message);
|
||||
else
|
||||
g_critical ("Failed to allocate framebuffer");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cogl_onscreen_show (onscreen);
|
||||
|
||||
cogl_push_framebuffer (data->fb);
|
||||
|
||||
data->triangle = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
|
||||
3, triangle_vertices);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static test_draw_frame_and_swap (TestData *data)
|
||||
{
|
||||
if (data->context)
|
||||
{
|
||||
cogl_primitive_draw (data->triangle);
|
||||
cogl_framebuffer_swap_buffers (data->fb);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_fini (TestData *data)
|
||||
{
|
||||
if (data->fb)
|
||||
{
|
||||
cogl_object_unref (data->triangle);
|
||||
cogl_object_unref (data->fb);
|
||||
cogl_object_unref (data->context);
|
||||
data->triangle = NULL;
|
||||
data->fb = NULL;
|
||||
data->context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next main command.
|
||||
*/
|
||||
static void
|
||||
test_handle_cmd (struct android_app* app,
|
||||
int32_t cmd)
|
||||
{
|
||||
TestData *data = (TestData *) app->userData;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case APP_CMD_INIT_WINDOW:
|
||||
/* The window is being shown, get it ready */
|
||||
g_message ("command: INIT_WINDOW");
|
||||
if (data->app->window != NULL)
|
||||
{
|
||||
test_init (data);
|
||||
test_draw_frame_and_swap (data);
|
||||
}
|
||||
break;
|
||||
|
||||
case APP_CMD_TERM_WINDOW:
|
||||
/* The window is being hidden or closed, clean it up */
|
||||
g_message ("command: TERM_WINDOW");
|
||||
test_fini (data);
|
||||
break;
|
||||
|
||||
case APP_CMD_GAINED_FOCUS:
|
||||
g_message ("command: GAINED_FOCUS");
|
||||
break;
|
||||
|
||||
case APP_CMD_LOST_FOCUS:
|
||||
/* When our app loses focus, we stop monitoring the accelerometer.
|
||||
* This is to avoid consuming battery while not being used. */
|
||||
g_message ("command: LOST_FOCUS");
|
||||
test_draw_frame_and_swap (data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main entry point of a native application that is using
|
||||
* android_native_app_glue. It runs in its own thread, with its own
|
||||
* event loop for receiving input events and doing other things.
|
||||
*/
|
||||
void
|
||||
android_main (struct android_app* application)
|
||||
{
|
||||
TestData data;
|
||||
|
||||
/* Make sure glue isn't stripped */
|
||||
app_dummy ();
|
||||
|
||||
g_android_init ();
|
||||
|
||||
memset (&data, 0, sizeof (TestData));
|
||||
application->userData = &data;
|
||||
application->onAppCmd = test_handle_cmd;
|
||||
data.app = application;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int events;
|
||||
struct android_poll_source* source;
|
||||
|
||||
while ((ALooper_pollAll (0, NULL, &events, (void**)&source)) >= 0)
|
||||
{
|
||||
|
||||
/* Process this event */
|
||||
if (source != NULL)
|
||||
source->process (application, source);
|
||||
|
||||
/* Check if we are exiting */
|
||||
if (application->destroyRequested != 0)
|
||||
{
|
||||
test_fini (&data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
test_draw_frame_and_swap (&data);
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">TestCoglHello</string>
|
||||
</resources>
|
@ -1,422 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl-gst/cogl-gst.h>
|
||||
|
||||
typedef struct _Data
|
||||
{
|
||||
CoglFramebuffer *fb;
|
||||
CoglPipeline *border_pipeline;
|
||||
CoglPipeline *video_pipeline;
|
||||
CoglGstVideoSink *sink;
|
||||
int onscreen_width;
|
||||
int onscreen_height;
|
||||
CoglGstRectangle video_output;
|
||||
bool draw_ready;
|
||||
bool frame_ready;
|
||||
GMainLoop *main_loop;
|
||||
}Data;
|
||||
|
||||
static gboolean
|
||||
_bus_watch (GstBus *bus,
|
||||
GstMessage *msg,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = (Data*) user_data;
|
||||
switch (GST_MESSAGE_TYPE (msg))
|
||||
{
|
||||
case GST_MESSAGE_EOS:
|
||||
{
|
||||
g_main_loop_quit (data->main_loop);
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_ERROR:
|
||||
{
|
||||
char *debug;
|
||||
GError *error = NULL;
|
||||
|
||||
gst_message_parse_error (msg, &error, &debug);
|
||||
g_free (debug);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_error ("Playback error: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_main_loop_quit (data->main_loop);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_draw (Data *data)
|
||||
{
|
||||
/*
|
||||
The cogl pipeline needs to be retrieved from the sink before every draw.
|
||||
This is due to the cogl-gst sink creating a new cogl pipeline for each frame
|
||||
by copying the previous one and attaching the new frame to it.
|
||||
*/
|
||||
CoglPipeline* current = cogl_gst_video_sink_get_pipeline (data->sink);
|
||||
|
||||
data->video_pipeline = current;
|
||||
|
||||
if (data->video_output.x)
|
||||
{
|
||||
int x = data->video_output.x;
|
||||
|
||||
/* Letterboxed with vertical borders */
|
||||
cogl_framebuffer_draw_rectangle (data->fb,
|
||||
data->border_pipeline,
|
||||
0, 0, x, data->onscreen_height);
|
||||
cogl_framebuffer_draw_rectangle (data->fb,
|
||||
data->border_pipeline,
|
||||
data->onscreen_width - x,
|
||||
0,
|
||||
data->onscreen_width,
|
||||
data->onscreen_height);
|
||||
cogl_framebuffer_draw_rectangle (data->fb, data->video_pipeline,
|
||||
x, 0,
|
||||
x + data->video_output.width,
|
||||
data->onscreen_height);
|
||||
}
|
||||
else if (data->video_output.y)
|
||||
{
|
||||
int y = data->video_output.y;
|
||||
|
||||
/* Letterboxed with horizontal borders */
|
||||
cogl_framebuffer_draw_rectangle (data->fb,
|
||||
data->border_pipeline,
|
||||
0, 0, data->onscreen_width, y);
|
||||
cogl_framebuffer_draw_rectangle (data->fb,
|
||||
data->border_pipeline,
|
||||
0,
|
||||
data->onscreen_height - y,
|
||||
data->onscreen_width,
|
||||
data->onscreen_height);
|
||||
cogl_framebuffer_draw_rectangle (data->fb, data->video_pipeline,
|
||||
0, y,
|
||||
data->onscreen_width,
|
||||
y + data->video_output.height);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cogl_framebuffer_draw_rectangle (data->fb,
|
||||
data->video_pipeline,
|
||||
0, 0,
|
||||
data->onscreen_width,
|
||||
data->onscreen_height);
|
||||
}
|
||||
|
||||
cogl_onscreen_swap_buffers (COGL_ONSCREEN (data->fb));
|
||||
}
|
||||
|
||||
static void
|
||||
_check_draw (Data *data)
|
||||
{
|
||||
/* The frame is only drawn once we know that a new buffer is ready
|
||||
* from GStreamer and that Cogl is ready to accept some new
|
||||
* rendering */
|
||||
if (data->draw_ready && data->frame_ready)
|
||||
{
|
||||
_draw (data);
|
||||
data->draw_ready = FALSE;
|
||||
data->frame_ready = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_frame_callback (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
if (event == COGL_FRAME_EVENT_SYNC)
|
||||
{
|
||||
data->draw_ready = TRUE;
|
||||
_check_draw (data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_new_frame_cb (CoglGstVideoSink *sink,
|
||||
Data *data)
|
||||
{
|
||||
data->frame_ready = TRUE;
|
||||
_check_draw (data);
|
||||
}
|
||||
|
||||
static void
|
||||
_resize_callback (CoglOnscreen *onscreen,
|
||||
int width,
|
||||
int height,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
CoglGstRectangle available;
|
||||
|
||||
data->onscreen_width = width;
|
||||
data->onscreen_height = height;
|
||||
|
||||
cogl_framebuffer_orthographic (data->fb, 0, 0, width, height, -1, 100);
|
||||
|
||||
if (!data->video_pipeline)
|
||||
return;
|
||||
|
||||
available.x = 0;
|
||||
available.y = 0;
|
||||
available.width = width;
|
||||
available.height = height;
|
||||
cogl_gst_video_sink_fit_size (data->sink,
|
||||
&available,
|
||||
&data->video_output);
|
||||
}
|
||||
|
||||
/*
|
||||
A callback like this should be attached to the cogl-pipeline-ready
|
||||
signal. This way requesting the cogl pipeline before its creation
|
||||
by the sink is avoided. At this point, user textures and snippets can
|
||||
be added to the cogl pipeline.
|
||||
*/
|
||||
|
||||
static void
|
||||
_set_up_pipeline (gpointer instance,
|
||||
gpointer user_data)
|
||||
{
|
||||
Data* data = (Data*) user_data;
|
||||
|
||||
data->video_pipeline = cogl_gst_video_sink_get_pipeline (data->sink);
|
||||
|
||||
/* disable blending... */
|
||||
cogl_pipeline_set_blend (data->video_pipeline,
|
||||
"RGBA = ADD (SRC_COLOR, 0)", NULL);
|
||||
|
||||
/* Now that we know the video size we can perform letterboxing */
|
||||
_resize_callback (COGL_ONSCREEN (data->fb),
|
||||
data->onscreen_width,
|
||||
data->onscreen_height,
|
||||
data);
|
||||
|
||||
cogl_onscreen_add_frame_callback (COGL_ONSCREEN (data->fb), _frame_callback,
|
||||
data, NULL);
|
||||
|
||||
/*
|
||||
The cogl-gst-new-frame signal is emitted when the cogl-gst sink has
|
||||
retrieved a new frame and attached it to the cogl pipeline. This can be
|
||||
used to make sure cogl doesn't do any unnecessary drawing i.e. keeps to the
|
||||
frame-rate of the video.
|
||||
*/
|
||||
|
||||
g_signal_connect (data->sink, "new-frame", G_CALLBACK (_new_frame_cb), data);
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
is_uri (const char *str)
|
||||
{
|
||||
const char *p = str;
|
||||
|
||||
while (g_ascii_isalpha (*p))
|
||||
p++;
|
||||
|
||||
return p > str && g_str_has_prefix (p, "://");
|
||||
}
|
||||
|
||||
static CoglGstVideoSink *
|
||||
find_cogl_gst_video_sink (GstElement *element)
|
||||
{
|
||||
GstElement *sink_element = NULL;
|
||||
GstIterator *iterator;
|
||||
GstElement *iterator_value;
|
||||
GValue value;
|
||||
|
||||
if (!GST_IS_BIN (element))
|
||||
return NULL;
|
||||
|
||||
iterator = gst_bin_iterate_recurse (GST_BIN (element));
|
||||
|
||||
g_value_init (&value, GST_TYPE_ELEMENT);
|
||||
|
||||
while (gst_iterator_next (iterator, &value) == GST_ITERATOR_OK)
|
||||
{
|
||||
iterator_value = g_value_get_object (&value);
|
||||
|
||||
g_value_reset (&value);
|
||||
|
||||
if (COGL_GST_IS_VIDEO_SINK (iterator_value))
|
||||
{
|
||||
sink_element = iterator_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_value_unset (&value);
|
||||
|
||||
gst_iterator_free (iterator);
|
||||
|
||||
return COGL_GST_VIDEO_SINK (sink_element);
|
||||
}
|
||||
|
||||
|
||||
static CoglBool
|
||||
make_pipeline_for_uri (CoglContext *ctx,
|
||||
const char *uri,
|
||||
GstElement **pipeline_out,
|
||||
CoglGstVideoSink **sink_out,
|
||||
GError **error)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *bin;
|
||||
CoglGstVideoSink *sink;
|
||||
GError *tmp_error = NULL;
|
||||
|
||||
if (is_uri (uri))
|
||||
{
|
||||
pipeline = gst_pipeline_new ("gst-player");
|
||||
bin = gst_element_factory_make ("playbin", "bin");
|
||||
|
||||
sink = cogl_gst_video_sink_new (ctx);
|
||||
|
||||
g_object_set (G_OBJECT (bin),
|
||||
"video-sink",
|
||||
GST_ELEMENT (sink),
|
||||
NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), bin);
|
||||
|
||||
g_object_set (G_OBJECT (bin), "uri", uri, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
pipeline = gst_parse_launch (uri, &tmp_error);
|
||||
|
||||
if (tmp_error)
|
||||
{
|
||||
if (pipeline)
|
||||
g_object_unref (pipeline);
|
||||
|
||||
g_propagate_error (error, tmp_error);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sink = find_cogl_gst_video_sink (pipeline);
|
||||
|
||||
if (sink == NULL)
|
||||
{
|
||||
g_set_error (error,
|
||||
GST_STREAM_ERROR,
|
||||
GST_STREAM_ERROR_FAILED,
|
||||
"The pipeline does not contain a CoglGstVideoSink. "
|
||||
"Make sure you add a 'coglsink' element somewhere in "
|
||||
"the pipeline");
|
||||
g_object_unref (pipeline);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_object_ref (sink);
|
||||
|
||||
cogl_gst_video_sink_set_context (sink, ctx);
|
||||
}
|
||||
|
||||
*pipeline_out = pipeline;
|
||||
*sink_out = sink;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
Data data;
|
||||
CoglContext *ctx;
|
||||
CoglOnscreen *onscreen;
|
||||
GstElement *pipeline;
|
||||
GSource *cogl_source;
|
||||
GstBus *bus;
|
||||
char *uri;
|
||||
GError *error = NULL;
|
||||
|
||||
memset (&data, 0, sizeof (Data));
|
||||
|
||||
/* Set the necessary cogl elements */
|
||||
|
||||
ctx = cogl_context_new (NULL, NULL);
|
||||
|
||||
onscreen = cogl_onscreen_new (ctx, 640, 480);
|
||||
cogl_onscreen_set_resizable (onscreen, TRUE);
|
||||
cogl_onscreen_add_resize_callback (onscreen, _resize_callback, &data, NULL);
|
||||
cogl_onscreen_show (onscreen);
|
||||
|
||||
data.fb = onscreen;
|
||||
cogl_framebuffer_orthographic (data.fb, 0, 0, 640, 480, -1, 100);
|
||||
|
||||
data.border_pipeline = cogl_pipeline_new (ctx);
|
||||
cogl_pipeline_set_color4f (data.border_pipeline, 0, 0, 0, 1);
|
||||
/* disable blending */
|
||||
cogl_pipeline_set_blend (data.border_pipeline,
|
||||
"RGBA = ADD (SRC_COLOR, 0)", NULL);
|
||||
|
||||
/* Intialize GStreamer */
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
/*
|
||||
Create the cogl-gst video sink by calling the cogl_gst_video_sink_new
|
||||
function and passing it a CoglContext (this is used to create the
|
||||
CoglPipeline and the texures for each frame). Alternatively you can use
|
||||
gst_element_factory_make ("coglsink", "some_name") and then set the
|
||||
context with cogl_gst_video_sink_set_context.
|
||||
*/
|
||||
|
||||
if (argc < 2)
|
||||
uri = "http://docs.gstreamer.com/media/sintel_trailer-480p.webm";
|
||||
else
|
||||
uri = argv[1];
|
||||
|
||||
if (!make_pipeline_for_uri (ctx, uri, &pipeline, &data.sink, &error))
|
||||
{
|
||||
g_print ("Error creating pipeline: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||
gst_bus_add_watch (bus, _bus_watch, &data);
|
||||
|
||||
data.main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
cogl_source = cogl_glib_source_new (ctx, G_PRIORITY_DEFAULT);
|
||||
g_source_attach (cogl_source, NULL);
|
||||
|
||||
/*
|
||||
The cogl-pipeline-ready signal tells you when the cogl pipeline is
|
||||
initialized i.e. when cogl-gst has figured out the video format and
|
||||
is prepared to retrieve and attach the first frame of the video.
|
||||
*/
|
||||
|
||||
g_signal_connect (data.sink, "pipeline-ready",
|
||||
G_CALLBACK (_set_up_pipeline), &data);
|
||||
|
||||
data.draw_ready = TRUE;
|
||||
data.frame_ready = FALSE;
|
||||
|
||||
g_main_loop_run (data.main_loop);
|
||||
|
||||
g_source_destroy (cogl_source);
|
||||
g_source_unref (cogl_source);
|
||||
|
||||
g_main_loop_unref (data.main_loop);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,300 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl-pango/cogl-pango.h>
|
||||
|
||||
/* The state for this example... */
|
||||
typedef struct _Data
|
||||
{
|
||||
CoglFramebuffer *fb;
|
||||
int framebuffer_width;
|
||||
int framebuffer_height;
|
||||
|
||||
CoglMatrix view;
|
||||
|
||||
CoglIndices *indices;
|
||||
CoglPrimitive *prim;
|
||||
CoglTexture *texture;
|
||||
CoglPipeline *crate_pipeline;
|
||||
|
||||
CoglPangoFontMap *pango_font_map;
|
||||
PangoContext *pango_context;
|
||||
PangoFontDescription *pango_font_desc;
|
||||
|
||||
PangoLayout *hello_label;
|
||||
int hello_label_width;
|
||||
int hello_label_height;
|
||||
|
||||
GTimer *timer;
|
||||
|
||||
CoglBool swap_ready;
|
||||
|
||||
} Data;
|
||||
|
||||
/* A static identity matrix initialized for convenience. */
|
||||
static CoglMatrix identity;
|
||||
/* static colors initialized for convenience. */
|
||||
static CoglColor white;
|
||||
|
||||
/* A cube modelled using 4 vertices for each face.
|
||||
*
|
||||
* We use an index buffer when drawing the cube later so the GPU will
|
||||
* actually read each face as 2 separate triangles.
|
||||
*/
|
||||
static CoglVertexP3T2 vertices[] =
|
||||
{
|
||||
/* Front face */
|
||||
{ /* pos = */ -1.0f, -1.0f, 1.0f, /* tex coords = */ 0.0f, 1.0f},
|
||||
{ /* pos = */ 1.0f, -1.0f, 1.0f, /* tex coords = */ 1.0f, 1.0f},
|
||||
{ /* pos = */ 1.0f, 1.0f, 1.0f, /* tex coords = */ 1.0f, 0.0f},
|
||||
{ /* pos = */ -1.0f, 1.0f, 1.0f, /* tex coords = */ 0.0f, 0.0f},
|
||||
|
||||
/* Back face */
|
||||
{ /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 0.0f},
|
||||
{ /* pos = */ -1.0f, 1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f},
|
||||
{ /* pos = */ 1.0f, 1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f},
|
||||
{ /* pos = */ 1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 0.0f},
|
||||
|
||||
/* Top face */
|
||||
{ /* pos = */ -1.0f, 1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f},
|
||||
{ /* pos = */ -1.0f, 1.0f, 1.0f, /* tex coords = */ 0.0f, 0.0f},
|
||||
{ /* pos = */ 1.0f, 1.0f, 1.0f, /* tex coords = */ 1.0f, 0.0f},
|
||||
{ /* pos = */ 1.0f, 1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f},
|
||||
|
||||
/* Bottom face */
|
||||
{ /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f},
|
||||
{ /* pos = */ 1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f},
|
||||
{ /* pos = */ 1.0f, -1.0f, 1.0f, /* tex coords = */ 0.0f, 0.0f},
|
||||
{ /* pos = */ -1.0f, -1.0f, 1.0f, /* tex coords = */ 1.0f, 0.0f},
|
||||
|
||||
/* Right face */
|
||||
{ /* pos = */ 1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 0.0f},
|
||||
{ /* pos = */ 1.0f, 1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f},
|
||||
{ /* pos = */ 1.0f, 1.0f, 1.0f, /* tex coords = */ 0.0f, 1.0f},
|
||||
{ /* pos = */ 1.0f, -1.0f, 1.0f, /* tex coords = */ 0.0f, 0.0f},
|
||||
|
||||
/* Left face */
|
||||
{ /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 0.0f},
|
||||
{ /* pos = */ -1.0f, -1.0f, 1.0f, /* tex coords = */ 1.0f, 0.0f},
|
||||
{ /* pos = */ -1.0f, 1.0f, 1.0f, /* tex coords = */ 1.0f, 1.0f},
|
||||
{ /* pos = */ -1.0f, 1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f}
|
||||
};
|
||||
|
||||
static void
|
||||
paint (Data *data)
|
||||
{
|
||||
CoglFramebuffer *fb = data->fb;
|
||||
float rotation;
|
||||
|
||||
cogl_framebuffer_clear4f (fb,
|
||||
COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_DEPTH,
|
||||
0, 0, 0, 1);
|
||||
|
||||
cogl_framebuffer_push_matrix (fb);
|
||||
|
||||
cogl_framebuffer_translate (fb,
|
||||
data->framebuffer_width / 2,
|
||||
data->framebuffer_height / 2,
|
||||
0);
|
||||
|
||||
cogl_framebuffer_scale (fb, 75, 75, 75);
|
||||
|
||||
/* Update the rotation based on the time the application has been
|
||||
running so that we get a linear animation regardless of the frame
|
||||
rate */
|
||||
rotation = g_timer_elapsed (data->timer, NULL) * 60.0f;
|
||||
|
||||
/* Rotate the cube separately around each axis.
|
||||
*
|
||||
* Note: Cogl matrix manipulation follows the same rules as for
|
||||
* OpenGL. We use column-major matrices and - if you consider the
|
||||
* transformations happening to the model - then they are combined
|
||||
* in reverse order which is why the rotation is done last, since
|
||||
* we want it to be a rotation around the origin, before it is
|
||||
* scaled and translated.
|
||||
*/
|
||||
cogl_framebuffer_rotate (fb, rotation, 0, 0, 1);
|
||||
cogl_framebuffer_rotate (fb, rotation, 0, 1, 0);
|
||||
cogl_framebuffer_rotate (fb, rotation, 1, 0, 0);
|
||||
|
||||
cogl_primitive_draw (data->prim, fb, data->crate_pipeline);
|
||||
|
||||
cogl_framebuffer_pop_matrix (fb);
|
||||
|
||||
/* And finally render our Pango layouts... */
|
||||
|
||||
cogl_pango_show_layout (fb, data->hello_label,
|
||||
(data->framebuffer_width / 2) -
|
||||
(data->hello_label_width / 2),
|
||||
(data->framebuffer_height / 2) -
|
||||
(data->hello_label_height / 2),
|
||||
&white);
|
||||
}
|
||||
|
||||
static void
|
||||
frame_event_cb (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
if (event == COGL_FRAME_EVENT_SYNC)
|
||||
data->swap_ready = TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
CoglContext *ctx;
|
||||
CoglOnscreen *onscreen;
|
||||
CoglFramebuffer *fb;
|
||||
CoglError *error = NULL;
|
||||
Data data;
|
||||
PangoRectangle hello_label_size;
|
||||
float fovy, aspect, z_near, z_2d, z_far;
|
||||
CoglDepthState depth_state;
|
||||
|
||||
ctx = cogl_context_new (NULL, &error);
|
||||
if (!ctx) {
|
||||
fprintf (stderr, "Failed to create context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (ctx, 640, 480);
|
||||
fb = onscreen;
|
||||
data.fb = fb;
|
||||
data.framebuffer_width = cogl_framebuffer_get_width (fb);
|
||||
data.framebuffer_height = cogl_framebuffer_get_height (fb);
|
||||
|
||||
data.timer = g_timer_new ();
|
||||
|
||||
cogl_onscreen_show (onscreen);
|
||||
|
||||
cogl_framebuffer_set_viewport (fb, 0, 0,
|
||||
data.framebuffer_width,
|
||||
data.framebuffer_height);
|
||||
|
||||
fovy = 60; /* y-axis field of view */
|
||||
aspect = (float)data.framebuffer_width/(float)data.framebuffer_height;
|
||||
z_near = 0.1; /* distance to near clipping plane */
|
||||
z_2d = 1000; /* position to 2d plane */
|
||||
z_far = 2000; /* distance to far clipping plane */
|
||||
|
||||
cogl_framebuffer_perspective (fb, fovy, aspect, z_near, z_far);
|
||||
|
||||
/* Since the pango renderer emits geometry in pixel/device coordinates
|
||||
* and the anti aliasing is implemented with the assumption that the
|
||||
* geometry *really* does end up pixel aligned, we setup a modelview
|
||||
* matrix so that for geometry in the plane z = 0 we exactly map x
|
||||
* coordinates in the range [0,stage_width] and y coordinates in the
|
||||
* range [0,stage_height] to the framebuffer extents with (0,0) being
|
||||
* the top left.
|
||||
*
|
||||
* This is roughly what Clutter does for a ClutterStage, but this
|
||||
* demonstrates how it is done manually using Cogl.
|
||||
*/
|
||||
cogl_matrix_init_identity (&data.view);
|
||||
cogl_matrix_view_2d_in_perspective (&data.view, fovy, aspect, z_near, z_2d,
|
||||
data.framebuffer_width,
|
||||
data.framebuffer_height);
|
||||
cogl_framebuffer_set_modelview_matrix (fb, &data.view);
|
||||
|
||||
/* Initialize some convenient constants */
|
||||
cogl_matrix_init_identity (&identity);
|
||||
cogl_color_init_from_4ub (&white, 0xff, 0xff, 0xff, 0xff);
|
||||
|
||||
/* rectangle indices allow the GPU to interpret a list of quads (the
|
||||
* faces of our cube) as a list of triangles.
|
||||
*
|
||||
* Since this is a very common thing to do
|
||||
* cogl_get_rectangle_indices() is a convenience function for
|
||||
* accessing internal index buffers that can be shared.
|
||||
*/
|
||||
data.indices = cogl_get_rectangle_indices (ctx, 6 /* n_rectangles */);
|
||||
data.prim = cogl_primitive_new_p3t2 (ctx, COGL_VERTICES_MODE_TRIANGLES,
|
||||
G_N_ELEMENTS (vertices),
|
||||
vertices);
|
||||
/* Each face will have 6 indices so we have 6 * 6 indices in total... */
|
||||
cogl_primitive_set_indices (data.prim,
|
||||
data.indices,
|
||||
6 * 6);
|
||||
|
||||
/* Load a jpeg crate texture from a file */
|
||||
printf ("crate.jpg (CC by-nc-nd http://bit.ly/9kP45T) ShadowRunner27 http://bit.ly/m1YXLh\n");
|
||||
data.texture =
|
||||
cogl_texture_2d_new_from_file (ctx,
|
||||
COGL_EXAMPLES_DATA "crate.jpg",
|
||||
&error);
|
||||
if (!data.texture)
|
||||
g_error ("Failed to load texture: %s", error->message);
|
||||
|
||||
/* a CoglPipeline conceptually describes all the state for vertex
|
||||
* processing, fragment processing and blending geometry. When
|
||||
* drawing the geometry for the crate this pipeline says to sample a
|
||||
* single texture during fragment processing... */
|
||||
data.crate_pipeline = cogl_pipeline_new (ctx);
|
||||
cogl_pipeline_set_layer_texture (data.crate_pipeline, 0, data.texture);
|
||||
|
||||
/* Since the box is made of multiple triangles that will overlap
|
||||
* when drawn and we don't control the order they are drawn in, we
|
||||
* enable depth testing to make sure that triangles that shouldn't
|
||||
* be visible get culled by the GPU. */
|
||||
cogl_depth_state_init (&depth_state);
|
||||
cogl_depth_state_set_test_enabled (&depth_state, TRUE);
|
||||
|
||||
cogl_pipeline_set_depth_state (data.crate_pipeline, &depth_state, NULL);
|
||||
|
||||
/* Setup a Pango font map and context */
|
||||
|
||||
data.pango_font_map = COGL_PANGO_FONT_MAP (cogl_pango_font_map_new());
|
||||
|
||||
cogl_pango_font_map_set_use_mipmapping (data.pango_font_map, TRUE);
|
||||
|
||||
data.pango_context = cogl_pango_font_map_create_context (data.pango_font_map);
|
||||
|
||||
data.pango_font_desc = pango_font_description_new ();
|
||||
pango_font_description_set_family (data.pango_font_desc, "Sans");
|
||||
pango_font_description_set_size (data.pango_font_desc, 30 * PANGO_SCALE);
|
||||
|
||||
/* Setup the "Hello Cogl" text */
|
||||
|
||||
data.hello_label = pango_layout_new (data.pango_context);
|
||||
pango_layout_set_font_description (data.hello_label, data.pango_font_desc);
|
||||
pango_layout_set_text (data.hello_label, "Hello Cogl", -1);
|
||||
|
||||
pango_layout_get_extents (data.hello_label, NULL, &hello_label_size);
|
||||
data.hello_label_width = PANGO_PIXELS (hello_label_size.width);
|
||||
data.hello_label_height = PANGO_PIXELS (hello_label_size.height);
|
||||
|
||||
data.swap_ready = TRUE;
|
||||
|
||||
cogl_onscreen_add_frame_callback (COGL_ONSCREEN (fb),
|
||||
frame_event_cb,
|
||||
&data,
|
||||
NULL); /* destroy notify */
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
CoglPollFD *poll_fds;
|
||||
int n_poll_fds;
|
||||
int64_t timeout;
|
||||
|
||||
if (data.swap_ready)
|
||||
{
|
||||
paint (&data);
|
||||
cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
|
||||
}
|
||||
|
||||
cogl_poll_renderer_get_info (cogl_context_get_renderer (ctx),
|
||||
&poll_fds, &n_poll_fds, &timeout);
|
||||
|
||||
g_poll ((GPollFD *) poll_fds, n_poll_fds,
|
||||
timeout == -1 ? -1 : timeout / 1000);
|
||||
|
||||
cogl_poll_renderer_dispatch (cogl_context_get_renderer (ctx),
|
||||
poll_fds, n_poll_fds);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,149 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
#include <emscripten.h>
|
||||
#include "emscripten-example-js.h"
|
||||
|
||||
/* This short example is just to demonstrate using Cogl with
|
||||
* Emscripten using SDL to receive input events */
|
||||
|
||||
typedef struct Data
|
||||
{
|
||||
CoglPrimitive *triangle;
|
||||
CoglPipeline *pipeline;
|
||||
float center_x, center_y;
|
||||
CoglFramebuffer *fb;
|
||||
CoglBool redraw_queued;
|
||||
CoglBool ready_to_draw;
|
||||
} Data;
|
||||
|
||||
static Data data;
|
||||
static CoglContext *ctx;
|
||||
|
||||
static void
|
||||
redraw (Data *data)
|
||||
{
|
||||
CoglFramebuffer *fb = data->fb;
|
||||
|
||||
cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
|
||||
|
||||
cogl_framebuffer_push_matrix (fb);
|
||||
cogl_framebuffer_translate (fb, data->center_x, -data->center_y, 0.0f);
|
||||
|
||||
cogl_primitive_draw (data->triangle, fb, data->pipeline);
|
||||
cogl_framebuffer_pop_matrix (fb);
|
||||
|
||||
cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
|
||||
}
|
||||
|
||||
static void
|
||||
handle_event (Data *data, SDL_Event *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
case SDL_MOUSEMOTION:
|
||||
{
|
||||
int width =
|
||||
cogl_framebuffer_get_width (COGL_FRAMEBUFFER (data->fb));
|
||||
int height =
|
||||
cogl_framebuffer_get_height (COGL_FRAMEBUFFER (data->fb));
|
||||
|
||||
data->center_x = event->motion.x * 2.0f / width - 1.0f;
|
||||
data->center_y = event->motion.y * 2.0f / height - 1.0f;
|
||||
|
||||
data->redraw_queued = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
frame_cb (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
if (event == COGL_FRAME_EVENT_SYNC)
|
||||
data->ready_to_draw = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
mainloop (void)
|
||||
{
|
||||
SDL_Event event;
|
||||
|
||||
while (SDL_PollEvent (&event))
|
||||
{
|
||||
handle_event (&data, &event);
|
||||
cogl_sdl_handle_event (ctx, &event);
|
||||
}
|
||||
|
||||
if (data.redraw_queued && data.ready_to_draw)
|
||||
{
|
||||
data.redraw_queued = FALSE;
|
||||
data.ready_to_draw = FALSE;
|
||||
redraw (&data);
|
||||
}
|
||||
|
||||
/* NB: The mainloop will be automatically resumed if user input is received */
|
||||
if (!data.redraw_queued)
|
||||
emscripten_pause_main_loop ();
|
||||
|
||||
cogl_sdl_idle (ctx);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
CoglOnscreen *onscreen;
|
||||
CoglError *error = NULL;
|
||||
CoglVertexP2C4 triangle_vertices[] = {
|
||||
{0, 0.7, 0xff, 0x00, 0x00, 0xff},
|
||||
{-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
|
||||
{0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
|
||||
};
|
||||
|
||||
ctx = cogl_sdl_context_new (SDL_USEREVENT, &error);
|
||||
if (!ctx)
|
||||
{
|
||||
fprintf (stderr, "Failed to create context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (ctx, 800, 600);
|
||||
data.fb = COGL_FRAMEBUFFER (onscreen);
|
||||
|
||||
cogl_onscreen_add_frame_callback (onscreen,
|
||||
frame_cb,
|
||||
&data,
|
||||
NULL /* destroy callback */);
|
||||
|
||||
data.center_x = 0.0f;
|
||||
data.center_y = 0.0f;
|
||||
|
||||
cogl_onscreen_show (onscreen);
|
||||
|
||||
data.triangle = cogl_primitive_new_p2c4 (ctx, COGL_VERTICES_MODE_TRIANGLES,
|
||||
3, triangle_vertices);
|
||||
data.pipeline = cogl_pipeline_new (ctx);
|
||||
|
||||
data.redraw_queued = TRUE;
|
||||
data.ready_to_draw = TRUE;
|
||||
|
||||
/* The emscripten mainloop isn't event driven, it's periodic and so
|
||||
* we aim to pause the emscripten mainlooop whenever we don't have a
|
||||
* redraw queued. What we do instead is hook into the real browser
|
||||
* mainloop using this javascript binding api to add an input event
|
||||
* listener that will resume the emscripten mainloop whenever input
|
||||
* is received.
|
||||
*/
|
||||
example_js_add_input_listener ();
|
||||
|
||||
emscripten_set_main_loop (mainloop, -1, TRUE);
|
||||
|
||||
cogl_object_unref (ctx);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
const Cogl = imports.gi.Cogl;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
|
||||
let renderer = new Cogl.Renderer();
|
||||
let display = new Cogl.Display(renderer, new Cogl.OnscreenTemplate(new Cogl.SwapChain()));
|
||||
let ctx = new Cogl.Context(display);
|
||||
|
||||
// Should be able to replace the 3 previous lines with :
|
||||
// let ctx = new Cogl.Context(null);
|
||||
// But crashing for some reason.
|
||||
|
||||
// GLib mainloop integration
|
||||
let gsource = Cogl.glib_renderer_source_new(renderer, 0);
|
||||
let loop = GLib.MainLoop.new(null, false);
|
||||
gsource.attach(loop.get_context());
|
||||
|
||||
// Onscreen creation
|
||||
let onscreen = new Cogl.Onscreen(ctx, 800, 600);
|
||||
onscreen.show();
|
||||
|
||||
// Drawing pipeline
|
||||
let crate = Cogl.Texture2D.new_from_file(ctx, 'crate.jpg');
|
||||
let pipeline = new Cogl.Pipeline(ctx);
|
||||
pipeline.set_layer_texture(0, crate);
|
||||
let clearColor = new Cogl.Color();
|
||||
clearColor.init_from_4f(0, 0, 0, 1.0);
|
||||
|
||||
// Redraw callback
|
||||
let closure = onscreen.add_dirty_callback(Lang.bind(this, function() {
|
||||
onscreen.clear(Cogl.BufferBit.COLOR, clearColor);
|
||||
onscreen.draw_rectangle(pipeline, -1, -1, 1, 1);
|
||||
onscreen.swap_buffers();
|
||||
return true;
|
||||
}), null);
|
||||
|
||||
// Quit after 5s
|
||||
let tm = GLib.timeout_source_new(5000);
|
||||
tm.set_callback(Lang.bind(this, function() {
|
||||
loop.quit();
|
||||
return false;
|
||||
}), null);
|
||||
tm.attach(loop.get_context());
|
||||
|
||||
// Run!
|
||||
loop.run();
|
@ -1,138 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-gles2.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define OFFSCREEN_WIDTH 100
|
||||
#define OFFSCREEN_HEIGHT 100
|
||||
|
||||
typedef struct _Data
|
||||
{
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPrimitive *triangle;
|
||||
CoglPipeline *pipeline;
|
||||
|
||||
CoglTexture *offscreen_texture;
|
||||
CoglOffscreen *offscreen;
|
||||
CoglGLES2Context *gles2_ctx;
|
||||
const CoglGLES2Vtable *gles2_vtable;
|
||||
} Data;
|
||||
|
||||
static gboolean
|
||||
paint_cb (void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
CoglError *error = NULL;
|
||||
const CoglGLES2Vtable *gles2 = data->gles2_vtable;
|
||||
|
||||
/* Draw scene with GLES2 */
|
||||
if (!cogl_push_gles2_context (data->ctx,
|
||||
data->gles2_ctx,
|
||||
data->fb,
|
||||
data->fb,
|
||||
&error))
|
||||
{
|
||||
g_error ("Failed to push gles2 context: %s\n", error->message);
|
||||
}
|
||||
|
||||
/* Clear offscreen framebuffer with a random color */
|
||||
gles2->glClearColor (g_random_double (),
|
||||
g_random_double (),
|
||||
g_random_double (),
|
||||
1.0f);
|
||||
gles2->glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
cogl_pop_gles2_context (data->ctx);
|
||||
|
||||
/* Draw scene with Cogl */
|
||||
cogl_primitive_draw (data->triangle, data->fb, data->pipeline);
|
||||
|
||||
cogl_onscreen_swap_buffers (COGL_ONSCREEN (data->fb));
|
||||
|
||||
return FALSE; /* remove the callback */
|
||||
}
|
||||
|
||||
static void
|
||||
frame_event_cb (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
if (event == COGL_FRAME_EVENT_SYNC)
|
||||
paint_cb (user_data);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
Data data;
|
||||
CoglOnscreen *onscreen;
|
||||
CoglError *error = NULL;
|
||||
CoglVertexP2C4 triangle_vertices[] = {
|
||||
{0, 0.7, 0xff, 0x00, 0x00, 0xff},
|
||||
{-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
|
||||
{0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
|
||||
};
|
||||
GSource *cogl_source;
|
||||
GMainLoop *loop;
|
||||
CoglRenderer *renderer;
|
||||
CoglDisplay *display;
|
||||
|
||||
renderer = cogl_renderer_new ();
|
||||
cogl_renderer_add_constraint (renderer,
|
||||
COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2);
|
||||
display = cogl_display_new (renderer, NULL);
|
||||
data.ctx = cogl_context_new (display, NULL);
|
||||
|
||||
onscreen = cogl_onscreen_new (data.ctx, 640, 480);
|
||||
cogl_onscreen_show (onscreen);
|
||||
data.fb = onscreen;
|
||||
|
||||
/* Prepare onscreen primitive */
|
||||
data.triangle = cogl_primitive_new_p2c4 (data.ctx,
|
||||
COGL_VERTICES_MODE_TRIANGLES,
|
||||
3, triangle_vertices);
|
||||
data.pipeline = cogl_pipeline_new (data.ctx);
|
||||
|
||||
data.offscreen_texture =
|
||||
cogl_texture_2d_new_with_size (data.ctx,
|
||||
OFFSCREEN_WIDTH,
|
||||
OFFSCREEN_HEIGHT);
|
||||
data.offscreen = cogl_offscreen_new_with_texture (data.offscreen_texture);
|
||||
|
||||
data.gles2_ctx = cogl_gles2_context_new (data.ctx, &error);
|
||||
if (!data.gles2_ctx) {
|
||||
g_error ("Failed to create GLES2 context: %s\n", error->message);
|
||||
}
|
||||
|
||||
data.gles2_vtable = cogl_gles2_context_get_vtable (data.gles2_ctx);
|
||||
|
||||
/* Draw scene with GLES2 */
|
||||
if (!cogl_push_gles2_context (data.ctx,
|
||||
data.gles2_ctx,
|
||||
data.fb,
|
||||
data.fb,
|
||||
&error))
|
||||
{
|
||||
g_error ("Failed to push gles2 context: %s\n", error->message);
|
||||
}
|
||||
|
||||
cogl_pop_gles2_context (data.ctx);
|
||||
|
||||
cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);
|
||||
|
||||
g_source_attach (cogl_source, NULL);
|
||||
|
||||
cogl_onscreen_add_frame_callback (COGL_ONSCREEN (data.fb),
|
||||
frame_event_cb,
|
||||
&data,
|
||||
NULL); /* destroy notify */
|
||||
|
||||
g_idle_add (paint_cb, &data);
|
||||
|
||||
loop = g_main_loop_new (NULL, TRUE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,825 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2001 Brian Paul 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 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
|
||||
* BRIAN PAUL 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Ported to GLES2.
|
||||
* Kristian Høgsberg <krh@bitplanet.net>
|
||||
* May 3, 2010
|
||||
*
|
||||
* Improve GLES2 port:
|
||||
* * Refactor gear drawing.
|
||||
* * Use correct normals for surfaces.
|
||||
* * Improve shader.
|
||||
* * Use perspective projection transformation.
|
||||
* * Add FPS count.
|
||||
* * Add comments.
|
||||
* Alexandros Frantzis <alexandros.frantzis@linaro.org>
|
||||
* Jul 13, 2010
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-gles2.h>
|
||||
#include <glib.h>
|
||||
|
||||
#define STRIPS_PER_TOOTH 7
|
||||
#define VERTICES_PER_TOOTH 34
|
||||
#define GEAR_VERTEX_STRIDE 6
|
||||
|
||||
typedef struct _Data
|
||||
{
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
|
||||
CoglGLES2Context *gles2_ctx;
|
||||
|
||||
GTimer *timer;
|
||||
int frames;
|
||||
double last_elapsed;
|
||||
} Data;
|
||||
|
||||
|
||||
/**
|
||||
* Struct describing the vertices in triangle strip
|
||||
*/
|
||||
struct vertex_strip {
|
||||
/** The first vertex in the strip */
|
||||
GLint first;
|
||||
/** The number of consecutive vertices in the strip after the first */
|
||||
GLint count;
|
||||
};
|
||||
|
||||
/* Each vertex consist of GEAR_VERTEX_STRIDE GLfloat attributes */
|
||||
typedef GLfloat GearVertex[GEAR_VERTEX_STRIDE];
|
||||
|
||||
/**
|
||||
* Struct representing a gear.
|
||||
*/
|
||||
struct gear {
|
||||
/** The array of vertices comprising the gear */
|
||||
GearVertex *vertices;
|
||||
/** The number of vertices comprising the gear */
|
||||
int nvertices;
|
||||
/** The array of triangle strips comprising the gear */
|
||||
struct vertex_strip *strips;
|
||||
/** The number of triangle strips comprising the gear */
|
||||
int nstrips;
|
||||
/** The Vertex Buffer Object holding the vertices in the graphics card */
|
||||
GLuint vbo;
|
||||
};
|
||||
|
||||
/** The view rotation [x, y, z] */
|
||||
static GLfloat view_rot[3] = { 20.0, 30.0, 0.0 };
|
||||
/** The gears */
|
||||
static struct gear *gear1, *gear2, *gear3;
|
||||
/** The current gear rotation angle */
|
||||
static GLfloat angle = 0.0;
|
||||
/** The location of the shader uniforms */
|
||||
static GLuint ModelViewProjectionMatrix_location,
|
||||
NormalMatrix_location,
|
||||
LightSourcePosition_location,
|
||||
MaterialColor_location;
|
||||
/** The projection matrix */
|
||||
static GLfloat ProjectionMatrix[16];
|
||||
/** The direction of the directional light for the scene */
|
||||
static const GLfloat LightSourcePosition[4] = { 5.0, 5.0, 10.0, 1.0};
|
||||
|
||||
#ifndef HAVE_SINCOS
|
||||
static void
|
||||
sincos (double x, double *sinx, double *cosx)
|
||||
{
|
||||
*sinx = sin (x);
|
||||
*cosx = cos (x);
|
||||
}
|
||||
#endif /* HAVE_SINCOS */
|
||||
|
||||
/**
|
||||
* Fills a gear vertex.
|
||||
*
|
||||
* @param v the vertex to fill
|
||||
* @param x the x coordinate
|
||||
* @param y the y coordinate
|
||||
* @param z the z coortinate
|
||||
* @param n pointer to the normal table
|
||||
*
|
||||
* @return the operation error code
|
||||
*/
|
||||
static GearVertex *
|
||||
vert (GearVertex *v, GLfloat x, GLfloat y, GLfloat z, GLfloat n[3])
|
||||
{
|
||||
v[0][0] = x;
|
||||
v[0][1] = y;
|
||||
v[0][2] = z;
|
||||
v[0][3] = n[0];
|
||||
v[0][4] = n[1];
|
||||
v[0][5] = n[2];
|
||||
|
||||
return v + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gear wheel.
|
||||
*
|
||||
* @param inner_radius radius of hole at center
|
||||
* @param outer_radius radius at center of teeth
|
||||
* @param width width of gear
|
||||
* @param teeth number of teeth
|
||||
* @param tooth_depth depth of tooth
|
||||
*
|
||||
* @return pointer to the constructed struct gear
|
||||
*/
|
||||
static struct gear *
|
||||
create_gear (GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
|
||||
GLint teeth, GLfloat tooth_depth)
|
||||
{
|
||||
GLfloat r0, r1, r2;
|
||||
GLfloat da;
|
||||
GearVertex *v;
|
||||
struct gear *gear;
|
||||
double s[5], c[5];
|
||||
GLfloat normal[3];
|
||||
int cur_strip = 0;
|
||||
int i;
|
||||
|
||||
/* Allocate memory for the gear */
|
||||
gear = malloc (sizeof *gear);
|
||||
if (gear == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Calculate the radii used in the gear */
|
||||
r0 = inner_radius;
|
||||
r1 = outer_radius - tooth_depth / 2.0;
|
||||
r2 = outer_radius + tooth_depth / 2.0;
|
||||
|
||||
da = 2.0 * M_PI / teeth / 4.0;
|
||||
|
||||
/* Allocate memory for the triangle strip information */
|
||||
gear->nstrips = STRIPS_PER_TOOTH * teeth;
|
||||
gear->strips = calloc (gear->nstrips, sizeof (*gear->strips));
|
||||
|
||||
/* Allocate memory for the vertices */
|
||||
gear->vertices = calloc (VERTICES_PER_TOOTH * teeth, sizeof(*gear->vertices));
|
||||
v = gear->vertices;
|
||||
|
||||
for (i = 0; i < teeth; i++) {
|
||||
/* Calculate needed sin/cos for varius angles */
|
||||
sincos (i * 2.0 * M_PI / teeth, &s[0], &c[0]);
|
||||
sincos (i * 2.0 * M_PI / teeth + da, &s[1], &c[1]);
|
||||
sincos (i * 2.0 * M_PI / teeth + da * 2, &s[2], &c[2]);
|
||||
sincos (i * 2.0 * M_PI / teeth + da * 3, &s[3], &c[3]);
|
||||
sincos (i * 2.0 * M_PI / teeth + da * 4, &s[4], &c[4]);
|
||||
|
||||
/* A set of macros for making the creation of the gears easier */
|
||||
#define GEAR_POINT(r, da) { (r) * c[(da)], (r) * s[(da)] }
|
||||
#define SET_NORMAL(x, y, z) do { \
|
||||
normal[0] = (x); normal[1] = (y); normal[2] = (z); \
|
||||
} while(0)
|
||||
|
||||
#define GEAR_VERT(v, point, sign) vert((v), p[(point)].x, p[(point)].y, (sign) * width * 0.5, normal)
|
||||
|
||||
#define START_STRIP do { \
|
||||
gear->strips[cur_strip].first = v - gear->vertices; \
|
||||
} while(0);
|
||||
|
||||
#define END_STRIP do { \
|
||||
int _tmp = (v - gear->vertices); \
|
||||
gear->strips[cur_strip].count = _tmp - gear->strips[cur_strip].first; \
|
||||
cur_strip++; \
|
||||
} while (0)
|
||||
|
||||
#define QUAD_WITH_NORMAL(p1, p2) do { \
|
||||
SET_NORMAL((p[(p1)].y - p[(p2)].y), -(p[(p1)].x - p[(p2)].x), 0); \
|
||||
v = GEAR_VERT(v, (p1), -1); \
|
||||
v = GEAR_VERT(v, (p1), 1); \
|
||||
v = GEAR_VERT(v, (p2), -1); \
|
||||
v = GEAR_VERT(v, (p2), 1); \
|
||||
} while(0)
|
||||
|
||||
{
|
||||
struct point {
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
};
|
||||
|
||||
/* Create the 7 points (only x,y coords) used to draw a tooth */
|
||||
struct point p[7] = {
|
||||
GEAR_POINT (r2, 1), // 0
|
||||
GEAR_POINT (r2, 2), // 1
|
||||
GEAR_POINT (r1, 0), // 2
|
||||
GEAR_POINT (r1, 3), // 3
|
||||
GEAR_POINT (r0, 0), // 4
|
||||
GEAR_POINT (r1, 4), // 5
|
||||
GEAR_POINT (r0, 4), // 6
|
||||
};
|
||||
|
||||
/* Front face */
|
||||
START_STRIP;
|
||||
SET_NORMAL (0, 0, 1.0);
|
||||
v = GEAR_VERT (v, 0, +1);
|
||||
v = GEAR_VERT (v, 1, +1);
|
||||
v = GEAR_VERT (v, 2, +1);
|
||||
v = GEAR_VERT (v, 3, +1);
|
||||
v = GEAR_VERT (v, 4, +1);
|
||||
v = GEAR_VERT (v, 5, +1);
|
||||
v = GEAR_VERT (v, 6, +1);
|
||||
END_STRIP;
|
||||
|
||||
/* Inner face */
|
||||
START_STRIP;
|
||||
QUAD_WITH_NORMAL (4, 6);
|
||||
END_STRIP;
|
||||
|
||||
/* Back face */
|
||||
START_STRIP;
|
||||
SET_NORMAL (0, 0, -1.0);
|
||||
v = GEAR_VERT (v, 6, -1);
|
||||
v = GEAR_VERT (v, 5, -1);
|
||||
v = GEAR_VERT (v, 4, -1);
|
||||
v = GEAR_VERT (v, 3, -1);
|
||||
v = GEAR_VERT (v, 2, -1);
|
||||
v = GEAR_VERT (v, 1, -1);
|
||||
v = GEAR_VERT (v, 0, -1);
|
||||
END_STRIP;
|
||||
|
||||
/* Outer face */
|
||||
START_STRIP;
|
||||
QUAD_WITH_NORMAL (0, 2);
|
||||
END_STRIP;
|
||||
|
||||
START_STRIP;
|
||||
QUAD_WITH_NORMAL (1, 0);
|
||||
END_STRIP;
|
||||
|
||||
START_STRIP;
|
||||
QUAD_WITH_NORMAL (3, 1);
|
||||
END_STRIP;
|
||||
|
||||
START_STRIP;
|
||||
QUAD_WITH_NORMAL (5, 3);
|
||||
END_STRIP;
|
||||
}
|
||||
}
|
||||
|
||||
gear->nvertices = (v - gear->vertices);
|
||||
|
||||
/* Store the vertices in a vertex buffer object (VBO) */
|
||||
glGenBuffers (1, &gear->vbo);
|
||||
glBindBuffer (GL_ARRAY_BUFFER, gear->vbo);
|
||||
glBufferData (GL_ARRAY_BUFFER, gear->nvertices * sizeof(GearVertex),
|
||||
gear->vertices, GL_STATIC_DRAW);
|
||||
|
||||
return gear;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two 4x4 matrices.
|
||||
*
|
||||
* The result is stored in matrix m.
|
||||
*
|
||||
* @param m the first matrix to multiply
|
||||
* @param n the second matrix to multiply
|
||||
*/
|
||||
static void
|
||||
multiply (GLfloat *m, const GLfloat *n)
|
||||
{
|
||||
GLfloat tmp[16];
|
||||
const GLfloat *row, *column;
|
||||
div_t d;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
tmp[i] = 0;
|
||||
d = div(i, 4);
|
||||
row = n + d.quot * 4;
|
||||
column = m + d.rem;
|
||||
for (j = 0; j < 4; j++)
|
||||
tmp[i] += row[j] * column[j * 4];
|
||||
}
|
||||
memcpy (m, &tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates a 4x4 matrix.
|
||||
*
|
||||
* @param[in,out] m the matrix to rotate
|
||||
* @param angle the angle to rotate
|
||||
* @param x the x component of the direction to rotate to
|
||||
* @param y the y component of the direction to rotate to
|
||||
* @param z the z component of the direction to rotate to
|
||||
*/
|
||||
static void
|
||||
rotate (GLfloat *m, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
|
||||
{
|
||||
double s, c;
|
||||
|
||||
sincos (angle, &s, &c);
|
||||
|
||||
{
|
||||
GLfloat r[16] = {
|
||||
x * x * (1 - c) + c, y * x * (1 - c) + z * s, x * z * (1 - c) - y * s, 0,
|
||||
x * y * (1 - c) - z * s, y * y * (1 - c) + c, y * z * (1 - c) + x * s, 0,
|
||||
x * z * (1 - c) + y * s, y * z * (1 - c) - x * s, z * z * (1 - c) + c, 0,
|
||||
0, 0, 0, 1
|
||||
};
|
||||
|
||||
multiply (m, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translates a 4x4 matrix.
|
||||
*
|
||||
* @param[in,out] m the matrix to translate
|
||||
* @param x the x component of the direction to translate to
|
||||
* @param y the y component of the direction to translate to
|
||||
* @param z the z component of the direction to translate to
|
||||
*/
|
||||
static void
|
||||
translate(GLfloat *m, GLfloat x, GLfloat y, GLfloat z)
|
||||
{
|
||||
GLfloat t[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 };
|
||||
|
||||
multiply (m, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identity 4x4 matrix.
|
||||
*
|
||||
* @param m the matrix make an identity matrix
|
||||
*/
|
||||
static void
|
||||
identity (GLfloat *m)
|
||||
{
|
||||
GLfloat t[16] = {
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
};
|
||||
|
||||
memcpy (m, t, sizeof(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transposes a 4x4 matrix.
|
||||
*
|
||||
* @param m the matrix to transpose
|
||||
*/
|
||||
static void
|
||||
transpose (GLfloat *m)
|
||||
{
|
||||
GLfloat t[16] = {
|
||||
m[0], m[4], m[8], m[12],
|
||||
m[1], m[5], m[9], m[13],
|
||||
m[2], m[6], m[10], m[14],
|
||||
m[3], m[7], m[11], m[15]};
|
||||
|
||||
memcpy (m, t, sizeof(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts a 4x4 matrix.
|
||||
*
|
||||
* This function can currently handle only pure translation-rotation matrices.
|
||||
* Read http://www.gamedev.net/community/forums/topic.asp?topic_id=425118
|
||||
* for an explanation.
|
||||
*/
|
||||
static void
|
||||
invert (GLfloat *m)
|
||||
{
|
||||
GLfloat t[16];
|
||||
identity (t);
|
||||
|
||||
// Extract and invert the translation part 't'. The inverse of a
|
||||
// translation matrix can be calculated by negating the translation
|
||||
// coordinates.
|
||||
t[12] = -m[12]; t[13] = -m[13]; t[14] = -m[14];
|
||||
|
||||
// Invert the rotation part 'r'. The inverse of a rotation matrix is
|
||||
// equal to its transpose.
|
||||
m[12] = m[13] = m[14] = 0;
|
||||
transpose (m);
|
||||
|
||||
// inv (m) = inv (r) * inv (t)
|
||||
multiply (m, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a perspective projection transformation.
|
||||
*
|
||||
* @param m the matrix to save the transformation in
|
||||
* @param fovy the field of view in the y direction
|
||||
* @param aspect the view aspect ratio
|
||||
* @param zNear the near clipping plane
|
||||
* @param zFar the far clipping plane
|
||||
*/
|
||||
static void
|
||||
perspective (GLfloat *m, GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
|
||||
{
|
||||
GLfloat tmp[16];
|
||||
double sine, cosine, cotangent, deltaZ;
|
||||
GLfloat radians = fovy / 2 * M_PI / 180;
|
||||
|
||||
identity (tmp);
|
||||
|
||||
deltaZ = zFar - zNear;
|
||||
sincos (radians, &sine, &cosine);
|
||||
|
||||
if ((deltaZ == 0) || (sine == 0) || (aspect == 0))
|
||||
return;
|
||||
|
||||
cotangent = cosine / sine;
|
||||
|
||||
tmp[0] = cotangent / aspect;
|
||||
tmp[5] = cotangent;
|
||||
tmp[10] = -(zFar + zNear) / deltaZ;
|
||||
tmp[11] = -1;
|
||||
tmp[14] = -2 * zNear * zFar / deltaZ;
|
||||
tmp[15] = 0;
|
||||
|
||||
memcpy (m, tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a gear.
|
||||
*
|
||||
* @param gear the gear to draw
|
||||
* @param transform the current transformation matrix
|
||||
* @param x the x position to draw the gear at
|
||||
* @param y the y position to draw the gear at
|
||||
* @param angle the rotation angle of the gear
|
||||
* @param color the color of the gear
|
||||
*/
|
||||
static void
|
||||
draw_gear (struct gear *gear, GLfloat *transform,
|
||||
GLfloat x, GLfloat y, GLfloat angle, const GLfloat color[4])
|
||||
{
|
||||
GLfloat model_view[16];
|
||||
GLfloat normal_matrix[16];
|
||||
GLfloat model_view_projection[16];
|
||||
int n;
|
||||
|
||||
/* Translate and rotate the gear */
|
||||
memcpy(model_view, transform, sizeof (model_view));
|
||||
translate(model_view, x, y, 0);
|
||||
rotate(model_view, 2 * M_PI * angle / 360.0, 0, 0, 1);
|
||||
|
||||
/* Create and set the ModelViewProjectionMatrix */
|
||||
memcpy (model_view_projection,
|
||||
ProjectionMatrix,
|
||||
sizeof(model_view_projection));
|
||||
multiply (model_view_projection, model_view);
|
||||
|
||||
glUniformMatrix4fv (ModelViewProjectionMatrix_location, 1, GL_FALSE,
|
||||
model_view_projection);
|
||||
|
||||
/*
|
||||
* Create and set the NormalMatrix. It's the inverse transpose of the
|
||||
* ModelView matrix.
|
||||
*/
|
||||
memcpy (normal_matrix, model_view, sizeof (normal_matrix));
|
||||
invert (normal_matrix);
|
||||
transpose (normal_matrix);
|
||||
glUniformMatrix4fv (NormalMatrix_location, 1, GL_FALSE, normal_matrix);
|
||||
|
||||
/* Set the gear color */
|
||||
glUniform4fv (MaterialColor_location, 1, color);
|
||||
|
||||
/* Set the vertex buffer object to use */
|
||||
glBindBuffer (GL_ARRAY_BUFFER, gear->vbo);
|
||||
|
||||
/* Set up the position of the attributes in the vertex buffer object */
|
||||
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE,
|
||||
6 * sizeof(GLfloat), NULL);
|
||||
glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE,
|
||||
6 * sizeof(GLfloat), (GLfloat *) 0 + 3);
|
||||
|
||||
/* Enable the attributes */
|
||||
glEnableVertexAttribArray (0);
|
||||
glEnableVertexAttribArray (1);
|
||||
|
||||
/* Draw the triangle strips that comprise the gear */
|
||||
for (n = 0; n < gear->nstrips; n++)
|
||||
glDrawArrays (GL_TRIANGLE_STRIP,
|
||||
gear->strips[n].first,
|
||||
gear->strips[n].count);
|
||||
|
||||
/* Disable the attributes */
|
||||
glDisableVertexAttribArray (1);
|
||||
glDisableVertexAttribArray (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the gears.
|
||||
*/
|
||||
static void
|
||||
gears_draw(void)
|
||||
{
|
||||
const static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
|
||||
const static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
|
||||
const static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
|
||||
GLfloat transform[16];
|
||||
identity(transform);
|
||||
|
||||
glClearColor (0.0, 0.0, 0.0, 0.0);
|
||||
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
/* Translate and rotate the view */
|
||||
translate (transform, 0, 0, -20);
|
||||
rotate (transform, 2 * M_PI * view_rot[0] / 360.0, 1, 0, 0);
|
||||
rotate (transform, 2 * M_PI * view_rot[1] / 360.0, 0, 1, 0);
|
||||
rotate (transform, 2 * M_PI * view_rot[2] / 360.0, 0, 0, 1);
|
||||
|
||||
/* Draw the gears */
|
||||
draw_gear (gear1, transform, -3.0, -2.0, angle, red);
|
||||
draw_gear (gear2, transform, 3.1, -2.0, -2 * angle - 9.0, green);
|
||||
draw_gear (gear3, transform, -3.1, 4.2, -2 * angle - 25.0, blue);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
paint_cb (void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
double elapsed = g_timer_elapsed (data->timer, NULL);
|
||||
double dt = elapsed - data->last_elapsed;
|
||||
CoglError *error = NULL;
|
||||
|
||||
/* Draw scene with GLES2 */
|
||||
if (!cogl_push_gles2_context (data->ctx,
|
||||
data->gles2_ctx,
|
||||
data->fb,
|
||||
data->fb,
|
||||
&error))
|
||||
{
|
||||
g_error ("Failed to push gles2 context: %s\n", error->message);
|
||||
}
|
||||
|
||||
gears_draw ();
|
||||
|
||||
cogl_pop_gles2_context (data->ctx);
|
||||
|
||||
cogl_onscreen_swap_buffers (COGL_ONSCREEN (data->fb));
|
||||
|
||||
/* advance rotation for next frame */
|
||||
angle += 70.0 * dt; /* 70 degrees per second */
|
||||
if (angle > 3600.0)
|
||||
angle -= 3600.0;
|
||||
|
||||
data->frames++;
|
||||
|
||||
if (elapsed > 5.0) {
|
||||
GLfloat fps = data->frames / elapsed;
|
||||
printf ("%d frames in %3.1f seconds = %6.3f FPS\n",
|
||||
data->frames, elapsed, fps);
|
||||
g_timer_reset (data->timer);
|
||||
data->last_elapsed = 0;
|
||||
data->frames = 0;
|
||||
}else
|
||||
data->last_elapsed = elapsed;
|
||||
|
||||
return FALSE; /* remove the callback */
|
||||
}
|
||||
|
||||
static void
|
||||
frame_event_cb (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
if (event == COGL_FRAME_EVENT_SYNC)
|
||||
paint_cb (user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a new window size or exposure.
|
||||
*
|
||||
* @param width the window width
|
||||
* @param height the window height
|
||||
*/
|
||||
static void
|
||||
gears_reshape (int width, int height)
|
||||
{
|
||||
/* Update the projection matrix */
|
||||
perspective (ProjectionMatrix, 60.0, width / (float)height, 1.0, 1024.0);
|
||||
|
||||
/* Set the viewport */
|
||||
glViewport (0, 0, (GLint) width, (GLint) height);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Handles special eglut events.
|
||||
*
|
||||
* @param special the event to handle.
|
||||
*/
|
||||
static void
|
||||
gears_special(int special)
|
||||
{
|
||||
switch (special) {
|
||||
case EGLUT_KEY_LEFT:
|
||||
view_rot[1] += 5.0;
|
||||
break;
|
||||
case EGLUT_KEY_RIGHT:
|
||||
view_rot[1] -= 5.0;
|
||||
break;
|
||||
case EGLUT_KEY_UP:
|
||||
view_rot[0] += 5.0;
|
||||
break;
|
||||
case EGLUT_KEY_DOWN:
|
||||
view_rot[0] -= 5.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char vertex_shader[] =
|
||||
"attribute vec3 position;\n"
|
||||
"attribute vec3 normal;\n"
|
||||
"\n"
|
||||
"uniform mat4 ModelViewProjectionMatrix;\n"
|
||||
"uniform mat4 NormalMatrix;\n"
|
||||
"uniform vec4 LightSourcePosition;\n"
|
||||
"uniform vec4 MaterialColor;\n"
|
||||
"\n"
|
||||
"varying vec4 Color;\n"
|
||||
"\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" // Transform the normal to eye coordinates\n"
|
||||
" vec3 N = normalize(vec3(NormalMatrix * vec4(normal, 1.0)));\n"
|
||||
"\n"
|
||||
" // The LightSourcePosition is actually its direction for directional light\n"
|
||||
" vec3 L = normalize(LightSourcePosition.xyz);\n"
|
||||
"\n"
|
||||
" // Multiply the diffuse value by the vertex color (which is fixed in this case)\n"
|
||||
" // to get the actual color that we will use to draw this vertex with\n"
|
||||
" float diffuse = max(dot(N, L), 0.0);\n"
|
||||
" Color = diffuse * MaterialColor;\n"
|
||||
"\n"
|
||||
" // Transform the position to clip coordinates\n"
|
||||
" gl_Position = ModelViewProjectionMatrix * vec4(position, 1.0);\n"
|
||||
"}";
|
||||
|
||||
static const char fragment_shader[] =
|
||||
"precision mediump float;\n"
|
||||
"varying vec4 Color;\n"
|
||||
"\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" gl_FragColor = Color;\n"
|
||||
"}";
|
||||
|
||||
static void
|
||||
gears_init(void)
|
||||
{
|
||||
GLuint v, f, program;
|
||||
const char *p;
|
||||
char msg[512];
|
||||
|
||||
glEnable (GL_CULL_FACE);
|
||||
glEnable (GL_DEPTH_TEST);
|
||||
|
||||
/* Compile the vertex shader */
|
||||
p = vertex_shader;
|
||||
v = glCreateShader (GL_VERTEX_SHADER);
|
||||
glShaderSource (v, 1, &p, NULL);
|
||||
glCompileShader (v);
|
||||
glGetShaderInfoLog (v, sizeof msg, NULL, msg);
|
||||
printf ("vertex shader info: %s\n", msg);
|
||||
|
||||
/* Compile the fragment shader */
|
||||
p = fragment_shader;
|
||||
f = glCreateShader (GL_FRAGMENT_SHADER);
|
||||
glShaderSource (f, 1, &p, NULL);
|
||||
glCompileShader (f);
|
||||
glGetShaderInfoLog (f, sizeof msg, NULL, msg);
|
||||
printf ("fragment shader info: %s\n", msg);
|
||||
|
||||
/* Create and link the shader program */
|
||||
program = glCreateProgram ();
|
||||
glAttachShader (program, v);
|
||||
glAttachShader (program, f);
|
||||
glBindAttribLocation (program, 0, "position");
|
||||
glBindAttribLocation (program, 1, "normal");
|
||||
|
||||
glLinkProgram (program);
|
||||
glGetProgramInfoLog (program, sizeof msg, NULL, msg);
|
||||
printf ("info: %s\n", msg);
|
||||
|
||||
/* Enable the shaders */
|
||||
glUseProgram (program);
|
||||
|
||||
/* Get the locations of the uniforms so we can access them */
|
||||
ModelViewProjectionMatrix_location =
|
||||
glGetUniformLocation (program, "ModelViewProjectionMatrix");
|
||||
NormalMatrix_location =
|
||||
glGetUniformLocation (program, "NormalMatrix");
|
||||
LightSourcePosition_location =
|
||||
glGetUniformLocation (program, "LightSourcePosition");
|
||||
MaterialColor_location =
|
||||
glGetUniformLocation (program, "MaterialColor");
|
||||
|
||||
/* Set the LightSourcePosition uniform which is constant throughout
|
||||
* the program */
|
||||
glUniform4fv (LightSourcePosition_location, 1, LightSourcePosition);
|
||||
|
||||
/* make the gears */
|
||||
gear1 = create_gear (1.0, 4.0, 1.0, 20, 0.7);
|
||||
gear2 = create_gear (0.5, 2.0, 2.0, 10, 0.7);
|
||||
gear3 = create_gear (1.3, 2.0, 0.5, 10, 0.7);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
Data data;
|
||||
CoglOnscreen *onscreen;
|
||||
CoglError *error = NULL;
|
||||
GSource *cogl_source;
|
||||
GMainLoop *loop;
|
||||
CoglRenderer *renderer;
|
||||
CoglDisplay *display;
|
||||
|
||||
renderer = cogl_renderer_new ();
|
||||
cogl_renderer_add_constraint (renderer,
|
||||
COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2);
|
||||
display = cogl_display_new (renderer, NULL);
|
||||
data.ctx = cogl_context_new (display, NULL);
|
||||
|
||||
onscreen = cogl_onscreen_new (data.ctx, 300, 300);
|
||||
cogl_onscreen_show (onscreen);
|
||||
data.fb = onscreen;
|
||||
|
||||
data.gles2_ctx = cogl_gles2_context_new (data.ctx, &error);
|
||||
if (!data.gles2_ctx)
|
||||
g_error ("Failed to create GLES2 context: %s\n", error->message);
|
||||
|
||||
/* Draw scene with GLES2 */
|
||||
if (!cogl_push_gles2_context (data.ctx,
|
||||
data.gles2_ctx,
|
||||
data.fb,
|
||||
data.fb,
|
||||
&error))
|
||||
{
|
||||
g_error ("Failed to push gles2 context: %s\n", error->message);
|
||||
}
|
||||
|
||||
gears_reshape (cogl_framebuffer_get_width (data.fb),
|
||||
cogl_framebuffer_get_height (data.fb));
|
||||
|
||||
/* Initialize the gears */
|
||||
gears_init();
|
||||
|
||||
cogl_pop_gles2_context (data.ctx);
|
||||
|
||||
cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);
|
||||
|
||||
g_source_attach (cogl_source, NULL);
|
||||
|
||||
cogl_onscreen_add_frame_callback (COGL_ONSCREEN (data.fb),
|
||||
frame_event_cb,
|
||||
&data,
|
||||
NULL); /* destroy notify */
|
||||
|
||||
g_idle_add (paint_cb, &data);
|
||||
|
||||
data.timer = g_timer_new ();
|
||||
data.frames = 0;
|
||||
data.last_elapsed = 0;
|
||||
|
||||
loop = g_main_loop_new (NULL, TRUE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct _Data
|
||||
{
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPrimitive *triangle;
|
||||
CoglPipeline *pipeline;
|
||||
|
||||
unsigned int redraw_idle;
|
||||
CoglBool is_dirty;
|
||||
CoglBool draw_ready;
|
||||
} Data;
|
||||
|
||||
static gboolean
|
||||
paint_cb (void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
data->redraw_idle = 0;
|
||||
data->is_dirty = FALSE;
|
||||
data->draw_ready = FALSE;
|
||||
|
||||
cogl_framebuffer_clear4f (data->fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
|
||||
cogl_primitive_draw (data->triangle,
|
||||
data->fb,
|
||||
data->pipeline);
|
||||
cogl_onscreen_swap_buffers (data->fb);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_redraw (Data *data)
|
||||
{
|
||||
if (data->is_dirty && data->draw_ready && data->redraw_idle == 0) {
|
||||
/* We'll draw on idle instead of drawing immediately so that
|
||||
* if Cogl reports multiple dirty rectangles we won't
|
||||
* redundantly draw multiple frames */
|
||||
data->redraw_idle = g_idle_add (paint_cb, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
frame_event_cb (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
if (event == COGL_FRAME_EVENT_SYNC) {
|
||||
data->draw_ready = TRUE;
|
||||
maybe_redraw (data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dirty_cb (CoglOnscreen *onscreen,
|
||||
const CoglOnscreenDirtyInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
data->is_dirty = TRUE;
|
||||
maybe_redraw (data);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
Data data;
|
||||
CoglOnscreen *onscreen;
|
||||
CoglError *error = NULL;
|
||||
CoglVertexP2C4 triangle_vertices[] = {
|
||||
{0, 0.7, 0xff, 0x00, 0x00, 0xff},
|
||||
{-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
|
||||
{0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
|
||||
};
|
||||
GSource *cogl_source;
|
||||
GMainLoop *loop;
|
||||
|
||||
data.redraw_idle = 0;
|
||||
data.is_dirty = FALSE;
|
||||
data.draw_ready = TRUE;
|
||||
|
||||
data.ctx = cogl_context_new (NULL, &error);
|
||||
if (!data.ctx) {
|
||||
fprintf (stderr, "Failed to create context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (data.ctx, 640, 480);
|
||||
cogl_onscreen_show (onscreen);
|
||||
data.fb = onscreen;
|
||||
|
||||
cogl_onscreen_set_resizable (onscreen, TRUE);
|
||||
|
||||
data.triangle = cogl_primitive_new_p2c4 (data.ctx,
|
||||
COGL_VERTICES_MODE_TRIANGLES,
|
||||
3, triangle_vertices);
|
||||
data.pipeline = cogl_pipeline_new (data.ctx);
|
||||
|
||||
cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);
|
||||
|
||||
g_source_attach (cogl_source, NULL);
|
||||
|
||||
cogl_onscreen_add_frame_callback (data.fb,
|
||||
frame_event_cb,
|
||||
&data,
|
||||
NULL); /* destroy notify */
|
||||
cogl_onscreen_add_dirty_callback (data.fb,
|
||||
dirty_cb,
|
||||
&data,
|
||||
NULL); /* destroy notify */
|
||||
|
||||
loop = g_main_loop_new (NULL, TRUE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,250 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct {
|
||||
CoglFeatureID feature;
|
||||
const char *short_description;
|
||||
const char *long_description;
|
||||
} features[] =
|
||||
{
|
||||
{
|
||||
COGL_FEATURE_ID_TEXTURE_NPOT_BASIC,
|
||||
"Non power of two textures (basic)",
|
||||
"The hardware supports non power of two textures, but you also "
|
||||
"need to check the COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP and "
|
||||
"COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT features to know if the "
|
||||
"hardware supports npot texture mipmaps or repeat modes other "
|
||||
"than COGL_RENDERER_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE respectively."
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP,
|
||||
"Non power of two textures (+ mipmap)",
|
||||
"Mipmapping is supported in conjuntion with non power of two "
|
||||
"textures."
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT,
|
||||
"Non power of two textures (+ repeat modes)",
|
||||
"Repeat modes other than "
|
||||
"COGL_RENDERER_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE are supported by "
|
||||
"the hardware in conjunction with non power of two textures."
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_TEXTURE_NPOT,
|
||||
"Non power of two textures (fully featured)",
|
||||
"Non power of two textures are supported by the hardware. This "
|
||||
"is a equivalent to the COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, "
|
||||
"COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP and "
|
||||
"COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT features combined."
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_TEXTURE_RECTANGLE,
|
||||
"Unnormalized coordinate, rectangle textures",
|
||||
"Support for rectangular textures with non-normalized texture "
|
||||
"coordinates."
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_TEXTURE_3D,
|
||||
"3D texture support",
|
||||
"3D texture support"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_OFFSCREEN,
|
||||
"Offscreen rendering support",
|
||||
"Offscreen rendering support"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE,
|
||||
"Offscreen rendering with multisampling support",
|
||||
"Offscreen rendering with multisampling support"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_ONSCREEN_MULTIPLE,
|
||||
"Multiple onscreen framebuffers supported",
|
||||
"Multiple onscreen framebuffers supported"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_GLSL,
|
||||
"GLSL support",
|
||||
"GLSL support"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_ARBFP,
|
||||
"ARBFP support",
|
||||
"ARBFP support"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_UNSIGNED_INT_INDICES,
|
||||
"Unsigned integer indices",
|
||||
"COGL_RENDERER_INDICES_TYPE_UNSIGNED_INT is supported in cogl_indices_new()."
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_DEPTH_RANGE,
|
||||
"cogl_pipeline_set_depth_range() support",
|
||||
"cogl_pipeline_set_depth_range() support",
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_POINT_SPRITE,
|
||||
"Point sprite coordinates",
|
||||
"cogl_pipeline_set_layer_point_sprite_coords_enabled() is supported"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_MAP_BUFFER_FOR_READ,
|
||||
"Mapping buffers for reading",
|
||||
"Mapping buffers for reading"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE,
|
||||
"Mapping buffers for writing",
|
||||
"Mapping buffers for writing"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_MIRRORED_REPEAT,
|
||||
"Mirrored repeat wrap modes",
|
||||
"Mirrored repeat wrap modes"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_GLES2_CONTEXT,
|
||||
"GLES2 API integration supported",
|
||||
"Support for creating a GLES2 context for using the GLES2 API in a "
|
||||
"way that's integrated with Cogl."
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_DEPTH_TEXTURE,
|
||||
"Depth Textures",
|
||||
"CoglFramebuffers can be configured to render their depth buffer into "
|
||||
"a texture"
|
||||
},
|
||||
{
|
||||
COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
|
||||
"Per-vertex point size",
|
||||
"cogl_point_size_in can be used as an attribute to specify a per-vertex "
|
||||
"point size"
|
||||
}
|
||||
};
|
||||
|
||||
static const char *
|
||||
get_winsys_name_for_id (CoglWinsysID winsys_id)
|
||||
{
|
||||
switch (winsys_id)
|
||||
{
|
||||
case COGL_WINSYS_ID_ANY:
|
||||
g_return_val_if_reached ("ERROR");
|
||||
case COGL_WINSYS_ID_STUB:
|
||||
return "Stub";
|
||||
case COGL_WINSYS_ID_GLX:
|
||||
return "GLX";
|
||||
case COGL_WINSYS_ID_EGL_XLIB:
|
||||
return "EGL + Xlib platform";
|
||||
case COGL_WINSYS_ID_EGL_KMS:
|
||||
return "EGL + KMS platform";
|
||||
}
|
||||
g_return_val_if_reached ("Unknown");
|
||||
}
|
||||
|
||||
static void
|
||||
feature_cb (CoglFeatureID feature, void *user_data)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizeof(features) / sizeof(features[0]); i++)
|
||||
{
|
||||
if (features[i].feature == feature)
|
||||
{
|
||||
printf (" » %s\n", features[i].short_description);
|
||||
return;
|
||||
}
|
||||
}
|
||||
printf (" » Unknown feature %d\n", feature);
|
||||
}
|
||||
|
||||
typedef struct _OutputState
|
||||
{
|
||||
int id;
|
||||
} OutputState;
|
||||
|
||||
static void
|
||||
output_cb (CoglOutput *output, void *user_data)
|
||||
{
|
||||
OutputState *state = user_data;
|
||||
const char *order;
|
||||
float refresh;
|
||||
|
||||
printf (" Output%d:\n", state->id++);
|
||||
printf (" » position = (%d, %d)\n",
|
||||
cogl_output_get_x (output),
|
||||
cogl_output_get_y (output));
|
||||
printf (" » resolution = %d x %d\n",
|
||||
cogl_output_get_width (output),
|
||||
cogl_output_get_height (output));
|
||||
printf (" » physical size = %dmm x %dmm\n",
|
||||
cogl_output_get_mm_width (output),
|
||||
cogl_output_get_mm_height (output));
|
||||
switch (cogl_output_get_subpixel_order (output))
|
||||
{
|
||||
case COGL_SUBPIXEL_ORDER_NONE:
|
||||
order = "non-standard";
|
||||
break;
|
||||
case COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB:
|
||||
order = "horizontal,rgb";
|
||||
break;
|
||||
case COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR:
|
||||
order = "horizontal,bgr";
|
||||
break;
|
||||
case COGL_SUBPIXEL_ORDER_VERTICAL_RGB:
|
||||
order = "vertical,rgb";
|
||||
break;
|
||||
case COGL_SUBPIXEL_ORDER_VERTICAL_BGR:
|
||||
order = "vertical,bgr";
|
||||
break;
|
||||
default:
|
||||
order = "unknown";
|
||||
break;
|
||||
}
|
||||
printf (" » sub pixel order = %s\n", order);
|
||||
|
||||
refresh = cogl_output_get_refresh_rate (output);
|
||||
if (refresh)
|
||||
printf (" » refresh = %f Hz\n", refresh);
|
||||
else
|
||||
printf (" » refresh = unknown\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
CoglRenderer *renderer;
|
||||
CoglDisplay *display;
|
||||
CoglContext *ctx;
|
||||
CoglError *error = NULL;
|
||||
CoglWinsysID winsys_id;
|
||||
const char *winsys_name;
|
||||
OutputState output_state;
|
||||
|
||||
#ifdef COGL_HAS_EMSCRIPTEN_SUPPORT
|
||||
ctx = cogl_sdl_context_new (SDL_USEREVENT, &error);
|
||||
#else
|
||||
ctx = cogl_context_new (NULL, &error);
|
||||
#endif
|
||||
if (!ctx) {
|
||||
fprintf (stderr, "Failed to create context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
display = cogl_context_get_display (ctx);
|
||||
renderer = cogl_display_get_renderer (display);
|
||||
winsys_id = cogl_renderer_get_winsys_id (renderer);
|
||||
winsys_name = get_winsys_name_for_id (winsys_id);
|
||||
g_print ("Renderer: %s\n\n", winsys_name);
|
||||
|
||||
g_print ("Features:\n");
|
||||
cogl_foreach_feature (ctx, feature_cb, NULL);
|
||||
|
||||
g_print ("Outputs:\n");
|
||||
output_state.id = 0;
|
||||
cogl_renderer_foreach_output (renderer, output_cb, &output_state);
|
||||
if (output_state.id == 0)
|
||||
printf (" Unknown\n");
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
CoglOnscreenTemplate *onscreen_template;
|
||||
CoglDisplay *display;
|
||||
CoglContext *ctx;
|
||||
CoglOnscreen *onscreen;
|
||||
CoglFramebuffer *fb;
|
||||
CoglError *error = NULL;
|
||||
CoglVertexP2C4 triangle_vertices[] = {
|
||||
{0, 0.7, 0xff, 0x00, 0x00, 0xff},
|
||||
{-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
|
||||
{0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
|
||||
};
|
||||
CoglPrimitive *triangle;
|
||||
CoglTexture *tex;
|
||||
CoglOffscreen *offscreen;
|
||||
CoglFramebuffer *offscreen_fb;
|
||||
CoglPipeline *pipeline;
|
||||
|
||||
onscreen_template = cogl_onscreen_template_new (NULL);
|
||||
cogl_onscreen_template_set_samples_per_pixel (onscreen_template, 4);
|
||||
display = cogl_display_new (NULL, onscreen_template);
|
||||
|
||||
if (!cogl_display_setup (display, &error))
|
||||
{
|
||||
fprintf (stderr, "Platform doesn't support onscreen 4x msaa rendering: %s\n",
|
||||
error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx = cogl_context_new (display, &error);
|
||||
if (!ctx)
|
||||
{
|
||||
fprintf (stderr, "Failed to create context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (ctx, 640, 480);
|
||||
fb = onscreen;
|
||||
|
||||
cogl_framebuffer_set_samples_per_pixel (fb, 4);
|
||||
|
||||
if (!cogl_framebuffer_allocate (fb, &error))
|
||||
{
|
||||
fprintf (stderr, "Failed to allocate 4x msaa offscreen framebuffer, "
|
||||
"disabling msaa for onscreen rendering: %s\n", error->message);
|
||||
cogl_error_free (error);
|
||||
cogl_framebuffer_set_samples_per_pixel (fb, 0);
|
||||
|
||||
error = NULL;
|
||||
if (!cogl_framebuffer_allocate (fb, &error))
|
||||
{
|
||||
fprintf (stderr, "Failed to allocate framebuffer: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
cogl_onscreen_show (onscreen);
|
||||
|
||||
tex = cogl_texture_2d_new_with_size (ctx, 320, 480);
|
||||
offscreen = cogl_offscreen_new_with_texture (tex);
|
||||
offscreen_fb = offscreen;
|
||||
cogl_framebuffer_set_samples_per_pixel (offscreen_fb, 4);
|
||||
if (!cogl_framebuffer_allocate (offscreen_fb, &error))
|
||||
{
|
||||
cogl_error_free (error);
|
||||
error = NULL;
|
||||
fprintf (stderr, "Failed to allocate 4x msaa offscreen framebuffer, "
|
||||
"disabling msaa for offscreen rendering");
|
||||
cogl_framebuffer_set_samples_per_pixel (offscreen_fb, 0);
|
||||
}
|
||||
|
||||
triangle = cogl_primitive_new_p2c4 (ctx, COGL_VERTICES_MODE_TRIANGLES,
|
||||
3, triangle_vertices);
|
||||
pipeline = cogl_pipeline_new (ctx);
|
||||
|
||||
for (;;) {
|
||||
CoglPollFD *poll_fds;
|
||||
int n_poll_fds;
|
||||
int64_t timeout;
|
||||
CoglPipeline *texture_pipeline;
|
||||
|
||||
cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
|
||||
|
||||
cogl_framebuffer_push_matrix (fb);
|
||||
cogl_framebuffer_scale (fb, 0.5, 1, 1);
|
||||
cogl_framebuffer_translate (fb, -1, 0, 0);
|
||||
cogl_primitive_draw (triangle, fb, pipeline);
|
||||
cogl_framebuffer_pop_matrix (fb);
|
||||
|
||||
cogl_primitive_draw (triangle, fb, pipeline);
|
||||
cogl_framebuffer_resolve_samples (offscreen_fb);
|
||||
|
||||
texture_pipeline = cogl_pipeline_new (ctx);
|
||||
cogl_pipeline_set_layer_texture (texture_pipeline, 0, tex);
|
||||
cogl_framebuffer_draw_rectangle (fb, texture_pipeline, 0, 1, 1, -1);
|
||||
cogl_object_unref (texture_pipeline);
|
||||
|
||||
cogl_onscreen_swap_buffers (onscreen);
|
||||
|
||||
cogl_poll_renderer_get_info (cogl_context_get_renderer (ctx),
|
||||
&poll_fds, &n_poll_fds, &timeout);
|
||||
g_poll ((GPollFD *) poll_fds, n_poll_fds, 0);
|
||||
cogl_poll_renderer_dispatch (cogl_context_get_renderer (ctx),
|
||||
poll_fds, n_poll_fds);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#define N_FIREWORKS 32
|
||||
/* Units per second per second */
|
||||
#define GRAVITY -1.5f
|
||||
|
||||
#define N_SPARKS (N_FIREWORKS * 32) /* Must be a power of two */
|
||||
#define TIME_PER_SPARK 0.01f /* in seconds */
|
||||
|
||||
#define TEXTURE_SIZE 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t red, green, blue, alpha;
|
||||
} Color;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float size;
|
||||
float x, y;
|
||||
float start_x, start_y;
|
||||
Color color;
|
||||
|
||||
/* Velocities are in units per second */
|
||||
float initial_x_velocity;
|
||||
float initial_y_velocity;
|
||||
|
||||
GTimer *timer;
|
||||
} Firework;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x, y;
|
||||
Color color;
|
||||
Color base_color;
|
||||
} Spark;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Firework fireworks[N_FIREWORKS];
|
||||
|
||||
int next_spark_num;
|
||||
Spark sparks[N_SPARKS];
|
||||
GTimer *last_spark_time;
|
||||
|
||||
CoglContext *context;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPipeline *pipeline;
|
||||
CoglPrimitive *primitive;
|
||||
CoglAttributeBuffer *attribute_buffer;
|
||||
} Data;
|
||||
|
||||
static CoglTexture *
|
||||
generate_round_texture (CoglContext *context)
|
||||
{
|
||||
uint8_t *p, *data;
|
||||
int x, y;
|
||||
CoglTexture2D *tex;
|
||||
|
||||
p = data = g_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4);
|
||||
|
||||
/* Generate a white circle which gets transparent towards the edges */
|
||||
for (y = 0; y < TEXTURE_SIZE; y++)
|
||||
for (x = 0; x < TEXTURE_SIZE; x++)
|
||||
{
|
||||
int dx = x - TEXTURE_SIZE / 2;
|
||||
int dy = y - TEXTURE_SIZE / 2;
|
||||
float value = sqrtf (dx * dx + dy * dy) * 255.0 / (TEXTURE_SIZE / 2);
|
||||
if (value > 255.0f)
|
||||
value = 255.0f;
|
||||
value = 255.0f - value;
|
||||
*(p++) = value;
|
||||
*(p++) = value;
|
||||
*(p++) = value;
|
||||
*(p++) = value;
|
||||
}
|
||||
|
||||
tex = cogl_texture_2d_new_from_data (context,
|
||||
TEXTURE_SIZE, TEXTURE_SIZE,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
||||
TEXTURE_SIZE * 4,
|
||||
data,
|
||||
NULL /* error */);
|
||||
|
||||
g_free (data);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
static void
|
||||
paint (Data *data)
|
||||
{
|
||||
int i;
|
||||
float diff_time;
|
||||
|
||||
/* Update all of the firework's positions */
|
||||
for (i = 0; i < N_FIREWORKS; i++)
|
||||
{
|
||||
Firework *firework = data->fireworks + i;
|
||||
|
||||
if ((fabsf (firework->x - firework->start_x) > 2.0f) ||
|
||||
firework->y < -1.0f)
|
||||
{
|
||||
firework->size = g_random_double_range (0.001f, 0.1f);
|
||||
firework->start_x = 1.0f + firework->size;
|
||||
firework->start_y = -1.0f;
|
||||
firework->initial_x_velocity = g_random_double_range (-0.1f, -2.0f);
|
||||
firework->initial_y_velocity = g_random_double_range (0.1f, 4.0f);
|
||||
g_timer_reset (firework->timer);
|
||||
|
||||
/* Pick a random color out of six */
|
||||
if (g_random_boolean ())
|
||||
{
|
||||
memset (&firework->color, 0, sizeof (Color));
|
||||
((uint8_t *) &firework->color)[g_random_int_range (0, 3)] = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (&firework->color, 255, sizeof (Color));
|
||||
((uint8_t *) &firework->color)[g_random_int_range (0, 3)] = 0;
|
||||
}
|
||||
firework->color.alpha = 255;
|
||||
|
||||
/* Fire some of the fireworks from the other side */
|
||||
if (g_random_boolean ())
|
||||
{
|
||||
firework->start_x = -firework->start_x;
|
||||
firework->initial_x_velocity = -firework->initial_x_velocity;
|
||||
}
|
||||
}
|
||||
|
||||
diff_time = g_timer_elapsed (firework->timer, NULL);
|
||||
|
||||
firework->x = (firework->start_x +
|
||||
firework->initial_x_velocity * diff_time);
|
||||
|
||||
firework->y = ((firework->initial_y_velocity * diff_time +
|
||||
0.5f * GRAVITY * diff_time * diff_time) +
|
||||
firework->start_y);
|
||||
}
|
||||
|
||||
diff_time = g_timer_elapsed (data->last_spark_time, NULL);
|
||||
if (diff_time < 0.0f || diff_time >= TIME_PER_SPARK)
|
||||
{
|
||||
/* Add a new spark for each firework, overwriting the oldest ones */
|
||||
for (i = 0; i < N_FIREWORKS; i++)
|
||||
{
|
||||
Spark *spark = data->sparks + data->next_spark_num;
|
||||
Firework *firework = data->fireworks + i;
|
||||
|
||||
spark->x = (firework->x +
|
||||
g_random_double_range (-firework->size / 2.0f,
|
||||
firework->size / 2.0f));
|
||||
spark->y = (firework->y +
|
||||
g_random_double_range (-firework->size / 2.0f,
|
||||
firework->size / 2.0f));
|
||||
spark->base_color = firework->color;
|
||||
|
||||
data->next_spark_num = (data->next_spark_num + 1) & (N_SPARKS - 1);
|
||||
}
|
||||
|
||||
/* Update the colour of each spark */
|
||||
for (i = 0; i < N_SPARKS; i++)
|
||||
{
|
||||
float color_value;
|
||||
|
||||
/* First spark is the oldest */
|
||||
Spark *spark = data->sparks + ((data->next_spark_num + i)
|
||||
& (N_SPARKS - 1));
|
||||
|
||||
color_value = i / (N_SPARKS - 1.0f);
|
||||
spark->color.red = spark->base_color.red * color_value;
|
||||
spark->color.green = spark->base_color.green * color_value;
|
||||
spark->color.blue = spark->base_color.blue * color_value;
|
||||
spark->color.alpha = 255.0f * color_value;
|
||||
}
|
||||
|
||||
g_timer_reset (data->last_spark_time);
|
||||
}
|
||||
|
||||
cogl_buffer_set_data (data->attribute_buffer,
|
||||
0, /* offset */
|
||||
data->sparks,
|
||||
sizeof (data->sparks));
|
||||
|
||||
cogl_framebuffer_clear4f (data->fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
|
||||
|
||||
cogl_primitive_draw (data->primitive,
|
||||
data->fb,
|
||||
data->pipeline);
|
||||
|
||||
cogl_onscreen_swap_buffers (data->fb);
|
||||
}
|
||||
|
||||
static void
|
||||
create_primitive (Data *data)
|
||||
{
|
||||
CoglAttribute *attributes[2];
|
||||
int i;
|
||||
|
||||
data->attribute_buffer =
|
||||
cogl_attribute_buffer_new_with_size (data->context,
|
||||
sizeof (data->sparks));
|
||||
cogl_buffer_set_update_hint (data->attribute_buffer,
|
||||
COGL_BUFFER_UPDATE_HINT_DYNAMIC);
|
||||
|
||||
attributes[0] = cogl_attribute_new (data->attribute_buffer,
|
||||
"cogl_position_in",
|
||||
sizeof (Spark),
|
||||
G_STRUCT_OFFSET (Spark, x),
|
||||
2, /* n_components */
|
||||
COGL_ATTRIBUTE_TYPE_FLOAT);
|
||||
attributes[1] = cogl_attribute_new (data->attribute_buffer,
|
||||
"cogl_color_in",
|
||||
sizeof (Spark),
|
||||
G_STRUCT_OFFSET (Spark, color),
|
||||
4, /* n_components */
|
||||
COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
|
||||
|
||||
data->primitive =
|
||||
cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_POINTS,
|
||||
N_SPARKS,
|
||||
attributes,
|
||||
G_N_ELEMENTS (attributes));
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (attributes); i++)
|
||||
cogl_object_unref (attributes[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
frame_event_cb (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
if (event == COGL_FRAME_EVENT_SYNC)
|
||||
paint (data);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
CoglTexture *tex;
|
||||
CoglOnscreen *onscreen;
|
||||
GSource *cogl_source;
|
||||
GMainLoop *loop;
|
||||
Data data;
|
||||
int i;
|
||||
|
||||
data.context = cogl_context_new (NULL, NULL);
|
||||
|
||||
create_primitive (&data);
|
||||
|
||||
data.pipeline = cogl_pipeline_new (data.context);
|
||||
data.last_spark_time = g_timer_new ();
|
||||
data.next_spark_num = 0;
|
||||
cogl_pipeline_set_point_size (data.pipeline, TEXTURE_SIZE);
|
||||
|
||||
tex = generate_round_texture (data.context);
|
||||
cogl_pipeline_set_layer_texture (data.pipeline, 0, tex);
|
||||
cogl_object_unref (tex);
|
||||
|
||||
cogl_pipeline_set_layer_point_sprite_coords_enabled (data.pipeline,
|
||||
0, /* layer */
|
||||
TRUE,
|
||||
NULL /* error */);
|
||||
|
||||
for (i = 0; i < N_FIREWORKS; i++)
|
||||
{
|
||||
data.fireworks[i].x = -FLT_MAX;
|
||||
data.fireworks[i].y = FLT_MAX;
|
||||
data.fireworks[i].size = 0.0f;
|
||||
data.fireworks[i].timer = g_timer_new ();
|
||||
}
|
||||
|
||||
for (i = 0; i < N_SPARKS; i++)
|
||||
{
|
||||
data.sparks[i].x = 2.0f;
|
||||
data.sparks[i].y = 2.0f;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (data.context, 800, 600);
|
||||
cogl_onscreen_show (onscreen);
|
||||
data.fb = onscreen;
|
||||
|
||||
cogl_source = cogl_glib_source_new (data.context, G_PRIORITY_DEFAULT);
|
||||
|
||||
g_source_attach (cogl_source, NULL);
|
||||
|
||||
cogl_onscreen_add_frame_callback (onscreen,
|
||||
frame_event_cb,
|
||||
&data,
|
||||
NULL /* destroy notify */);
|
||||
|
||||
loop = g_main_loop_new (NULL, TRUE);
|
||||
|
||||
paint (&data);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
g_source_destroy (cogl_source);
|
||||
|
||||
cogl_object_unref (data.pipeline);
|
||||
cogl_object_unref (data.attribute_buffer);
|
||||
cogl_object_unref (data.primitive);
|
||||
cogl_object_unref (onscreen);
|
||||
cogl_object_unref (data.context);
|
||||
|
||||
g_timer_destroy (data.last_spark_time);
|
||||
|
||||
for (i = 0; i < N_FIREWORKS; i++)
|
||||
g_timer_destroy (data.fireworks[i].timer);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct _Data
|
||||
{
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPrimitive *left_triangle;
|
||||
CoglPrimitive *right_triangle;
|
||||
CoglPipeline *pipeline;
|
||||
|
||||
unsigned int redraw_idle;
|
||||
CoglBool is_dirty;
|
||||
CoglBool draw_ready;
|
||||
} Data;
|
||||
|
||||
static gboolean
|
||||
paint_cb (void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
data->redraw_idle = 0;
|
||||
data->is_dirty = FALSE;
|
||||
data->draw_ready = FALSE;
|
||||
|
||||
cogl_framebuffer_set_stereo_mode (data->fb, COGL_STEREO_BOTH);
|
||||
cogl_framebuffer_clear4f (data->fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
|
||||
|
||||
cogl_framebuffer_set_stereo_mode (data->fb, COGL_STEREO_LEFT);
|
||||
cogl_primitive_draw (data->left_triangle,
|
||||
data->fb,
|
||||
data->pipeline);
|
||||
|
||||
if (cogl_framebuffer_get_is_stereo (data->fb))
|
||||
{
|
||||
cogl_framebuffer_set_stereo_mode (data->fb, COGL_STEREO_RIGHT);
|
||||
cogl_primitive_draw (data->right_triangle,
|
||||
data->fb,
|
||||
data->pipeline);
|
||||
}
|
||||
|
||||
cogl_onscreen_swap_buffers (data->fb);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_redraw (Data *data)
|
||||
{
|
||||
if (data->is_dirty && data->draw_ready && data->redraw_idle == 0) {
|
||||
/* We'll draw on idle instead of drawing immediately so that
|
||||
* if Cogl reports multiple dirty rectangles we won't
|
||||
* redundantly draw multiple frames */
|
||||
data->redraw_idle = g_idle_add (paint_cb, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
frame_event_cb (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
CoglFrameInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
if (event == COGL_FRAME_EVENT_SYNC) {
|
||||
data->draw_ready = TRUE;
|
||||
maybe_redraw (data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dirty_cb (CoglOnscreen *onscreen,
|
||||
const CoglOnscreenDirtyInfo *info,
|
||||
void *user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
data->is_dirty = TRUE;
|
||||
maybe_redraw (data);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
Data data;
|
||||
CoglRenderer *renderer;
|
||||
CoglOnscreenTemplate *onscreen_template;
|
||||
CoglDisplay *display;
|
||||
CoglOnscreen *onscreen;
|
||||
CoglError *error = NULL;
|
||||
CoglVertexP2C4 left_triangle_vertices[] = {
|
||||
{0.05, 0.7, 0xff, 0x00, 0x00, 0xff},
|
||||
{-0.65, -0.7, 0x00, 0xff, 0x00, 0xff},
|
||||
{0.75, -0.7, 0x00, 0x00, 0xff, 0xff}
|
||||
};
|
||||
CoglVertexP2C4 right_triangle_vertices[] = {
|
||||
{-0.05, 0.7, 0xff, 0x00, 0x00, 0xff},
|
||||
{-0.75, -0.7, 0x00, 0xff, 0x00, 0xff},
|
||||
{0.65, -0.7, 0x00, 0x00, 0xff, 0xff}
|
||||
};
|
||||
GSource *cogl_source;
|
||||
GMainLoop *loop;
|
||||
|
||||
data.redraw_idle = 0;
|
||||
data.is_dirty = FALSE;
|
||||
data.draw_ready = TRUE;
|
||||
|
||||
renderer = cogl_renderer_new ();
|
||||
onscreen_template = cogl_onscreen_template_new (NULL);
|
||||
cogl_onscreen_template_set_stereo_enabled (onscreen_template, TRUE);
|
||||
display = cogl_display_new (renderer, onscreen_template);
|
||||
|
||||
data.ctx = cogl_context_new (display, &error);
|
||||
if (!data.ctx) {
|
||||
fprintf (stderr, "Failed to create stereo context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (data.ctx, 640, 480);
|
||||
cogl_onscreen_show (onscreen);
|
||||
data.fb = onscreen;
|
||||
|
||||
cogl_onscreen_set_resizable (onscreen, TRUE);
|
||||
|
||||
data.left_triangle = cogl_primitive_new_p2c4 (data.ctx,
|
||||
COGL_VERTICES_MODE_TRIANGLES,
|
||||
3, left_triangle_vertices);
|
||||
data.right_triangle = cogl_primitive_new_p2c4 (data.ctx,
|
||||
COGL_VERTICES_MODE_TRIANGLES,
|
||||
3, right_triangle_vertices);
|
||||
data.pipeline = cogl_pipeline_new (data.ctx);
|
||||
|
||||
cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);
|
||||
|
||||
g_source_attach (cogl_source, NULL);
|
||||
|
||||
cogl_onscreen_add_frame_callback (data.fb,
|
||||
frame_event_cb,
|
||||
&data,
|
||||
NULL); /* destroy notify */
|
||||
cogl_onscreen_add_dirty_callback (data.fb,
|
||||
dirty_cb,
|
||||
&data,
|
||||
NULL); /* destroy notify */
|
||||
|
||||
loop = g_main_loop_new (NULL, TRUE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-xlib.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#define X11_FOREIGN_EVENT_MASK \
|
||||
(KeyPressMask | \
|
||||
KeyReleaseMask | \
|
||||
ButtonPressMask | \
|
||||
ButtonReleaseMask | \
|
||||
PointerMotionMask)
|
||||
|
||||
static void
|
||||
update_cogl_x11_event_mask (CoglOnscreen *onscreen,
|
||||
uint32_t event_mask,
|
||||
void *user_data)
|
||||
{
|
||||
Display *xdpy = user_data;
|
||||
XSetWindowAttributes attrs;
|
||||
uint32_t xwin;
|
||||
|
||||
attrs.event_mask = event_mask | X11_FOREIGN_EVENT_MASK;
|
||||
xwin = cogl_x11_onscreen_get_window_xid (onscreen);
|
||||
|
||||
XChangeWindowAttributes (xdpy,
|
||||
(Window)xwin,
|
||||
CWEventMask,
|
||||
&attrs);
|
||||
}
|
||||
|
||||
static void
|
||||
resize_handler (CoglOnscreen *onscreen,
|
||||
int width,
|
||||
int height,
|
||||
void *user_data)
|
||||
{
|
||||
CoglFramebuffer *fb = user_data;
|
||||
cogl_framebuffer_set_viewport (fb, width / 4, height / 4, width / 2, height / 2);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
Display *xdpy;
|
||||
CoglRenderer *renderer;
|
||||
CoglSwapChain *chain;
|
||||
CoglOnscreenTemplate *onscreen_template;
|
||||
CoglDisplay *display;
|
||||
CoglContext *ctx;
|
||||
CoglOnscreen *onscreen;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPipeline *pipeline;
|
||||
CoglError *error = NULL;
|
||||
uint32_t visual;
|
||||
XVisualInfo template, *xvisinfo;
|
||||
int visinfos_count;
|
||||
XSetWindowAttributes xattr;
|
||||
unsigned long mask;
|
||||
Window xwin;
|
||||
CoglVertexP2C4 triangle_vertices[] = {
|
||||
{0, 0.7, 0xff, 0x00, 0x00, 0xff},
|
||||
{-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
|
||||
{0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
|
||||
};
|
||||
CoglPrimitive *triangle;
|
||||
|
||||
|
||||
/* Since we want to test external ownership of the X display,
|
||||
* connect to X manually... */
|
||||
xdpy = XOpenDisplay (NULL);
|
||||
if (!xdpy)
|
||||
{
|
||||
fprintf (stderr, "Failed to open X Display\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Conceptually choose a GPU... */
|
||||
renderer = cogl_renderer_new ();
|
||||
/* FIXME: This should conceptually be part of the configuration of
|
||||
* a renderer. */
|
||||
cogl_xlib_renderer_set_foreign_display (renderer, xdpy);
|
||||
if (!cogl_renderer_connect (renderer, &error))
|
||||
{
|
||||
fprintf (stderr, "Failed to connect to a renderer: %s\n",
|
||||
error->message);
|
||||
}
|
||||
|
||||
chain = cogl_swap_chain_new ();
|
||||
cogl_swap_chain_set_has_alpha (chain, TRUE);
|
||||
|
||||
/* Conceptually declare upfront the kinds of windows we anticipate
|
||||
* creating so that when we configure the display pipeline we can avoid
|
||||
* having an impedance miss-match between the format of windows and the
|
||||
* format the display pipeline expects. */
|
||||
onscreen_template = cogl_onscreen_template_new (chain);
|
||||
cogl_object_unref (chain);
|
||||
|
||||
/* Conceptually setup a display pipeline */
|
||||
display = cogl_display_new (renderer, onscreen_template);
|
||||
cogl_object_unref (renderer);
|
||||
if (!cogl_display_setup (display, &error))
|
||||
{
|
||||
fprintf (stderr, "Failed to setup a display pipeline: %s\n",
|
||||
error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx = cogl_context_new (display, &error);
|
||||
if (!ctx)
|
||||
{
|
||||
fprintf (stderr, "Failed to create context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (ctx, 640, 480);
|
||||
|
||||
/* We want to test that Cogl can handle foreign X windows... */
|
||||
|
||||
visual = cogl_x11_onscreen_get_visual_xid (onscreen);
|
||||
if (!visual)
|
||||
{
|
||||
fprintf (stderr, "Failed to query an X visual suitable for the "
|
||||
"configured CoglOnscreen framebuffer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
template.visualid = visual;
|
||||
xvisinfo = XGetVisualInfo (xdpy, VisualIDMask, &template, &visinfos_count);
|
||||
|
||||
/* window attributes */
|
||||
xattr.background_pixel = WhitePixel (xdpy, DefaultScreen (xdpy));
|
||||
xattr.border_pixel = 0;
|
||||
xattr.colormap = XCreateColormap (xdpy,
|
||||
DefaultRootWindow (xdpy),
|
||||
xvisinfo->visual,
|
||||
AllocNone);
|
||||
mask = CWBorderPixel | CWColormap;
|
||||
|
||||
xwin = XCreateWindow (xdpy,
|
||||
DefaultRootWindow (xdpy),
|
||||
0, 0,
|
||||
800, 600,
|
||||
0,
|
||||
xvisinfo->depth,
|
||||
InputOutput,
|
||||
xvisinfo->visual,
|
||||
mask, &xattr);
|
||||
|
||||
XFree (xvisinfo);
|
||||
|
||||
cogl_x11_onscreen_set_foreign_window_xid (onscreen, xwin,
|
||||
update_cogl_x11_event_mask,
|
||||
xdpy);
|
||||
|
||||
XMapWindow (xdpy, xwin);
|
||||
|
||||
fb = onscreen;
|
||||
|
||||
cogl_onscreen_set_resizable (onscreen, TRUE);
|
||||
cogl_onscreen_add_resize_callback (onscreen, resize_handler, onscreen, NULL);
|
||||
|
||||
triangle = cogl_primitive_new_p2c4 (ctx, COGL_VERTICES_MODE_TRIANGLES,
|
||||
3, triangle_vertices);
|
||||
pipeline = cogl_pipeline_new (ctx);
|
||||
for (;;)
|
||||
{
|
||||
CoglPollFD *poll_fds;
|
||||
int n_poll_fds;
|
||||
int64_t timeout;
|
||||
|
||||
while (XPending (xdpy))
|
||||
{
|
||||
XEvent event;
|
||||
XNextEvent (xdpy, &event);
|
||||
switch (event.type)
|
||||
{
|
||||
case KeyRelease:
|
||||
case ButtonRelease:
|
||||
return 0;
|
||||
}
|
||||
cogl_xlib_renderer_handle_event (renderer, &event);
|
||||
}
|
||||
|
||||
/* After forwarding native events directly to Cogl you should
|
||||
* then allow Cogl to dispatch any corresponding event
|
||||
* callbacks, such as resize notification callbacks...
|
||||
*/
|
||||
cogl_poll_renderer_get_info (cogl_context_get_renderer (ctx),
|
||||
&poll_fds, &n_poll_fds, &timeout);
|
||||
g_poll ((GPollFD *) poll_fds, n_poll_fds, 0);
|
||||
cogl_poll_renderer_dispatch (cogl_context_get_renderer (ctx),
|
||||
poll_fds, n_poll_fds);
|
||||
|
||||
cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
|
||||
cogl_primitive_draw (triangle, fb, pipeline);
|
||||
cogl_onscreen_swap_buffers (onscreen);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,408 +0,0 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-xlib.h>
|
||||
#include <cogl/winsys/cogl-texture-pixmap-x11.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
#define X11_FOREIGN_EVENT_MASK \
|
||||
(KeyPressMask | \
|
||||
KeyReleaseMask | \
|
||||
ButtonPressMask | \
|
||||
ButtonReleaseMask | \
|
||||
PointerMotionMask)
|
||||
|
||||
#define TFP_XWIN_WIDTH 200
|
||||
#define TFP_XWIN_HEIGHT 200
|
||||
|
||||
static pid_t gears_pid = 0;
|
||||
|
||||
static void
|
||||
spawn_gears (CoglBool stereo)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0)
|
||||
execlp ("glxgears", "glxgears",
|
||||
stereo ? "-stereo" : NULL,
|
||||
NULL);
|
||||
|
||||
gears_pid = pid;
|
||||
}
|
||||
|
||||
static XID
|
||||
find_gears_toplevel (Display *xdpy,
|
||||
Window window)
|
||||
{
|
||||
Atom window_state = XInternAtom (xdpy, "WM_STATE", False);
|
||||
Atom type;
|
||||
int format;
|
||||
unsigned long n_items;
|
||||
unsigned long bytes_after;
|
||||
unsigned char *data;
|
||||
CoglBool result = FALSE;
|
||||
|
||||
if (window == None)
|
||||
window = DefaultRootWindow (xdpy);
|
||||
|
||||
XGetWindowProperty (xdpy, window, window_state,
|
||||
0, G_MAXLONG, False, window_state,
|
||||
&type, &format, &n_items, &bytes_after, &data);
|
||||
|
||||
if (type == window_state)
|
||||
{
|
||||
XFree (data);
|
||||
|
||||
XGetWindowProperty (xdpy, window, XA_WM_NAME,
|
||||
0, G_MAXLONG, False, XA_STRING,
|
||||
&type, &format, &n_items, &bytes_after, &data);
|
||||
|
||||
if (type == XA_STRING)
|
||||
{
|
||||
if (format == 8 && strcmp ((char *)data, "glxgears") == 0)
|
||||
result = window;
|
||||
|
||||
XFree (data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Window root, parent;
|
||||
Window *children;
|
||||
unsigned int n_children;
|
||||
unsigned int i;
|
||||
|
||||
XQueryTree (xdpy, window,
|
||||
&root, &parent, &children, &n_children);
|
||||
|
||||
for (i = 0; i < n_children; i++)
|
||||
{
|
||||
result = find_gears_toplevel (xdpy, children[i]);
|
||||
if (result != None)
|
||||
break;
|
||||
}
|
||||
|
||||
XFree (children);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
kill_gears (void)
|
||||
{
|
||||
kill (gears_pid, SIGTERM);
|
||||
}
|
||||
|
||||
static void
|
||||
update_cogl_x11_event_mask (CoglOnscreen *onscreen,
|
||||
uint32_t event_mask,
|
||||
void *user_data)
|
||||
{
|
||||
Display *xdpy = user_data;
|
||||
XSetWindowAttributes attrs;
|
||||
uint32_t xwin;
|
||||
|
||||
attrs.event_mask = event_mask | X11_FOREIGN_EVENT_MASK;
|
||||
xwin = cogl_x11_onscreen_get_window_xid (onscreen);
|
||||
|
||||
XChangeWindowAttributes (xdpy,
|
||||
(Window)xwin,
|
||||
CWEventMask,
|
||||
&attrs);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
Display *xdpy;
|
||||
int composite_error = 0, composite_event = 0;
|
||||
CoglRenderer *renderer;
|
||||
CoglSwapChain *chain;
|
||||
CoglOnscreenTemplate *onscreen_template;
|
||||
CoglDisplay *display;
|
||||
CoglContext *ctx;
|
||||
CoglOnscreen *onscreen;
|
||||
CoglFramebuffer *fb;
|
||||
CoglError *error = NULL;
|
||||
uint32_t visual;
|
||||
XVisualInfo template, *xvisinfo;
|
||||
int visinfos_count;
|
||||
XSetWindowAttributes xattr;
|
||||
unsigned long mask;
|
||||
Window xwin;
|
||||
Atom atom_wm_protocols;
|
||||
Atom atom_wm_delete_window;
|
||||
int screen;
|
||||
CoglBool gears = FALSE;
|
||||
CoglBool stereo = FALSE;
|
||||
Window tfp_xwin = None;
|
||||
Pixmap pixmap;
|
||||
CoglTexturePixmapX11 *tfp;
|
||||
CoglTexture *right_texture = NULL;
|
||||
GC gc = None;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp (argv[i], "--gears") == 0)
|
||||
gears = TRUE;
|
||||
else if (strcmp (argv[i], "--stereo") == 0)
|
||||
stereo = TRUE;
|
||||
else
|
||||
{
|
||||
g_printerr ("Usage: cogl-x11-tfp [--gears] [--stereo]\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
g_print ("NB: Don't use this example as a benchmark since there is "
|
||||
"no synchonization between X window updates and onscreen "
|
||||
"framebuffer updates!\n");
|
||||
|
||||
/* Since we want to test external ownership of the X display,
|
||||
* connect to X manually... */
|
||||
xdpy = XOpenDisplay (NULL);
|
||||
if (!xdpy)
|
||||
{
|
||||
fprintf (stderr, "Failed to open X Display\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
XSynchronize (xdpy, True);
|
||||
|
||||
if (XCompositeQueryExtension (xdpy, &composite_event, &composite_error))
|
||||
{
|
||||
int major = 0, minor = 0;
|
||||
if (XCompositeQueryVersion (xdpy, &major, &minor))
|
||||
{
|
||||
if (major != 0 || minor < 3)
|
||||
g_error ("Missing XComposite extension >= 0.3");
|
||||
}
|
||||
}
|
||||
|
||||
if (gears)
|
||||
{
|
||||
spawn_gears (stereo);
|
||||
while (TRUE)
|
||||
{
|
||||
tfp_xwin = find_gears_toplevel (xdpy, None);
|
||||
if (tfp_xwin != None)
|
||||
break;
|
||||
|
||||
g_usleep (10000);
|
||||
}
|
||||
}
|
||||
|
||||
/* Conceptually choose a GPU... */
|
||||
renderer = cogl_renderer_new ();
|
||||
/* FIXME: This should conceptually be part of the configuration of
|
||||
* a renderer. */
|
||||
cogl_xlib_renderer_set_foreign_display (renderer, xdpy);
|
||||
if (!cogl_renderer_connect (renderer, &error))
|
||||
{
|
||||
fprintf (stderr, "Failed to connect to a renderer: %s\n",
|
||||
error->message);
|
||||
}
|
||||
|
||||
chain = cogl_swap_chain_new ();
|
||||
cogl_swap_chain_set_has_alpha (chain, FALSE);
|
||||
|
||||
/* Conceptually declare upfront the kinds of windows we anticipate
|
||||
* creating so that when we configure the display pipeline we can avoid
|
||||
* having an impedance miss-match between the format of windows and the
|
||||
* format the display pipeline expects. */
|
||||
onscreen_template = cogl_onscreen_template_new (chain);
|
||||
if (stereo)
|
||||
cogl_onscreen_template_set_stereo_enabled (onscreen_template, TRUE);
|
||||
cogl_object_unref (chain);
|
||||
|
||||
/* Conceptually setup a display pipeline */
|
||||
display = cogl_display_new (renderer, onscreen_template);
|
||||
cogl_object_unref (renderer);
|
||||
if (!cogl_display_setup (display, &error))
|
||||
{
|
||||
fprintf (stderr, "Failed to setup a display pipeline: %s\n",
|
||||
error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx = cogl_context_new (display, &error);
|
||||
if (!ctx)
|
||||
{
|
||||
fprintf (stderr, "Failed to create context: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onscreen = cogl_onscreen_new (ctx, 640, 480);
|
||||
|
||||
/* We want to test that Cogl can handle foreign X windows... */
|
||||
|
||||
visual = cogl_x11_onscreen_get_visual_xid (onscreen);
|
||||
if (!visual)
|
||||
{
|
||||
fprintf (stderr, "Failed to query an X visual suitable for the "
|
||||
"configured CoglOnscreen framebuffer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
template.visualid = visual;
|
||||
xvisinfo = XGetVisualInfo (xdpy, VisualIDMask, &template, &visinfos_count);
|
||||
|
||||
/* window attributes */
|
||||
xattr.background_pixel = WhitePixel (xdpy, DefaultScreen (xdpy));
|
||||
xattr.border_pixel = 0;
|
||||
xattr.colormap = XCreateColormap (xdpy,
|
||||
DefaultRootWindow (xdpy),
|
||||
xvisinfo->visual,
|
||||
AllocNone);
|
||||
xattr.event_mask = StructureNotifyMask;
|
||||
mask = CWBorderPixel | CWColormap | CWEventMask;
|
||||
|
||||
xwin = XCreateWindow (xdpy,
|
||||
DefaultRootWindow (xdpy),
|
||||
0, 0,
|
||||
800, 600,
|
||||
0,
|
||||
xvisinfo->depth,
|
||||
InputOutput,
|
||||
xvisinfo->visual,
|
||||
mask, &xattr);
|
||||
|
||||
atom_wm_protocols = XInternAtom (xdpy, "WM_PROTOCOLS", False);
|
||||
atom_wm_delete_window = XInternAtom (xdpy, "WM_DELETE_WINDOW", False);
|
||||
XSetWMProtocols (xdpy, xwin, &atom_wm_delete_window, 1);
|
||||
|
||||
XFree (xvisinfo);
|
||||
|
||||
cogl_x11_onscreen_set_foreign_window_xid (onscreen, xwin,
|
||||
update_cogl_x11_event_mask,
|
||||
xdpy);
|
||||
|
||||
XMapWindow (xdpy, xwin);
|
||||
cogl_onscreen_show (onscreen);
|
||||
|
||||
screen = DefaultScreen (xdpy);
|
||||
|
||||
if (gears)
|
||||
{
|
||||
XCompositeRedirectWindow (xdpy, tfp_xwin, CompositeRedirectAutomatic);
|
||||
}
|
||||
else
|
||||
{
|
||||
XEvent xev;
|
||||
|
||||
XCompositeRedirectSubwindows (xdpy, xwin, CompositeRedirectManual);
|
||||
|
||||
tfp_xwin = XCreateSimpleWindow (xdpy, xwin,
|
||||
0, 0, TFP_XWIN_WIDTH, TFP_XWIN_HEIGHT,
|
||||
0,
|
||||
WhitePixel (xdpy, screen),
|
||||
WhitePixel (xdpy, screen));
|
||||
|
||||
XMapWindow (xdpy, tfp_xwin);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
XWindowEvent (xdpy, xwin, StructureNotifyMask, &xev);
|
||||
|
||||
if (xev.xany.type == MapNotify)
|
||||
break;
|
||||
}
|
||||
|
||||
gc = XCreateGC (xdpy, tfp_xwin, 0, NULL);
|
||||
}
|
||||
|
||||
pixmap = XCompositeNameWindowPixmap (xdpy, tfp_xwin);
|
||||
|
||||
if (stereo)
|
||||
{
|
||||
tfp = cogl_texture_pixmap_x11_new_left (ctx, pixmap, TRUE, &error);
|
||||
if (tfp)
|
||||
right_texture = cogl_texture_pixmap_x11_new_right (tfp);
|
||||
}
|
||||
else
|
||||
{
|
||||
tfp = cogl_texture_pixmap_x11_new (ctx, pixmap, TRUE, &error);
|
||||
}
|
||||
|
||||
if (!tfp)
|
||||
{
|
||||
fprintf (stderr, "Failed to create CoglTexturePixmapX11: %s",
|
||||
error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fb = onscreen;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned long pixel;
|
||||
CoglPipeline *pipeline;
|
||||
|
||||
while (XPending (xdpy))
|
||||
{
|
||||
XEvent event;
|
||||
KeySym keysym;
|
||||
XNextEvent (xdpy, &event);
|
||||
switch (event.type)
|
||||
{
|
||||
case KeyRelease:
|
||||
keysym = XLookupKeysym (&event.xkey, 0);
|
||||
if (keysym == XK_q || keysym == XK_Q || keysym == XK_Escape)
|
||||
goto out;
|
||||
break;
|
||||
case ClientMessage:
|
||||
if (event.xclient.message_type == atom_wm_protocols &&
|
||||
event.xclient.data.l[0] == atom_wm_delete_window)
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
cogl_xlib_renderer_handle_event (renderer, &event);
|
||||
}
|
||||
|
||||
if (!gears)
|
||||
{
|
||||
pixel =
|
||||
g_random_int_range (0, 255) << 24 |
|
||||
g_random_int_range (0, 255) << 16 |
|
||||
g_random_int_range (0, 255) << 8;
|
||||
g_random_int_range (0, 255);
|
||||
XSetForeground (xdpy, gc, pixel);
|
||||
XFillRectangle (xdpy, tfp_xwin, gc, 0, 0, TFP_XWIN_WIDTH, TFP_XWIN_HEIGHT);
|
||||
XFlush (xdpy);
|
||||
}
|
||||
|
||||
cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
|
||||
|
||||
pipeline = cogl_pipeline_new (ctx);
|
||||
|
||||
cogl_framebuffer_set_stereo_mode (onscreen, COGL_STEREO_LEFT);
|
||||
cogl_pipeline_set_layer_texture (pipeline, 0, tfp);
|
||||
cogl_framebuffer_draw_rectangle (fb, pipeline, -0.8, 0.8, 0.8, -0.8);
|
||||
|
||||
if (stereo)
|
||||
{
|
||||
cogl_framebuffer_set_stereo_mode (onscreen, COGL_STEREO_RIGHT);
|
||||
cogl_pipeline_set_layer_texture (pipeline, 0, right_texture);
|
||||
cogl_framebuffer_draw_rectangle (fb, pipeline, -0.8, 0.8, 0.8, -0.8);
|
||||
}
|
||||
|
||||
cogl_object_unref (pipeline);
|
||||
|
||||
cogl_onscreen_swap_buffers (onscreen);
|
||||
}
|
||||
|
||||
out:
|
||||
kill_gears ();
|
||||
return 0;
|
||||
}
|
1224
examples/cogland.c
1224
examples/cogland.c
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 168 KiB |
@ -1,19 +0,0 @@
|
||||
//"use strict";
|
||||
|
||||
var LibraryEXAMPLE = {
|
||||
$EXAMPLE__deps: ['$Browser'],
|
||||
$EXAMPLE: {
|
||||
receiveEvent: function(event) {
|
||||
Browser.mainLoop.resume();
|
||||
},
|
||||
},
|
||||
example_js_add_input_listener: function() {
|
||||
['mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll',
|
||||
'mousewheel', 'mouseout'].forEach(function(event) {
|
||||
Module['canvas'].addEventListener(event, EXAMPLE.receiveEvent, true);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
autoAddDeps(LibraryEXAMPLE, '$EXAMPLE');
|
||||
mergeInto(LibraryManager.library, LibraryEXAMPLE);
|
@ -1,18 +0,0 @@
|
||||
|
||||
#ifndef _EMSCRIPTEN_EXAMPLE_JS_H_
|
||||
#define _EMSCRIPTEN_EXAMPLE_JS_H_
|
||||
|
||||
/*
|
||||
* example_js_add_input_listener:
|
||||
*
|
||||
* Adds an input event listener to the browser's mainloop and whenever
|
||||
* input is received then the emscripten mainloop is resumed, if it
|
||||
* has been paused.
|
||||
*
|
||||
* This means we don't have to poll SDL for events and can instead go
|
||||
* to sleep waiting in the browser mainloop when there's no input and
|
||||
* nothing being animated.
|
||||
*/
|
||||
void example_js_add_input_listener (void);
|
||||
|
||||
#endif /* _EMSCRIPTEN_EXAMPLE_JS_H_ */
|
Loading…
x
Reference in New Issue
Block a user