drop examples
This commit is contained in:
parent
8366fd5438
commit
a9e1130244
@ -14,7 +14,7 @@ if BUILD_COGL_GLES2
|
|||||||
SUBDIRS += cogl-gles2
|
SUBDIRS += cogl-gles2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SUBDIRS += tests examples po
|
SUBDIRS += tests po
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I build/autotools ${ACLOCAL_FLAGS}
|
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 ============================================================
|
||||||
dnl Determine which drivers and window systems we can support
|
dnl Determine which drivers and window systems we can support
|
||||||
dnl ============================================================
|
dnl ============================================================
|
||||||
@ -1091,7 +1080,6 @@ cogl-path/cogl-path-2.0-experimental.pc
|
|||||||
cogl-gles2/Makefile
|
cogl-gles2/Makefile
|
||||||
cogl-gles2/cogl-gles2-1.0.pc
|
cogl-gles2/cogl-gles2-1.0.pc
|
||||||
cogl-gles2/cogl-gles2-2.0-experimental.pc
|
cogl-gles2/cogl-gles2-2.0-experimental.pc
|
||||||
examples/Makefile
|
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
tests/config.env
|
tests/config.env
|
||||||
tests/conform/Makefile
|
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