×
Namespaces

Variants
Actions
(Difference between revisions)

Showing ads in OpenGL ES context

From Nokia Developer Wiki
Jump to: navigation, search
hamishwillee (Talk | contribs)
m (Hamishwillee - Fix typo)
hamishwillee (Talk | contribs)
m (Text replace - "<code cpp>" to "<code cpp-qt>")
 
(7 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category:Draft]]
+
[[Category:In-App Advertising]][[Category:3D]][[Category:Qt]][[Category:OpenGL ES]]
 +
{{FeaturedArticle|timestamp=20120610}}
 
{{Abstract|This article explains how to manually fetch banner advertisements from Inneractive, display them on the surface of a 3D cube using OpenGL, and then open a browser when a cube's side is clicked.}}  
 
{{Abstract|This article explains how to manually fetch banner advertisements from Inneractive, display them on the surface of a 3D cube using OpenGL, and then open a browser when a cube's side is clicked.}}  
  
 
{{ArticleMetaData <!-- v1.2 -->
 
{{ArticleMetaData <!-- v1.2 -->
|sourcecode= <!-- Link to example source code e.g. [[Media:The Code Example ZIP.zip]] -->
+
|sourcecode= [[Media:adcube.zip]]
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) -->
+
|installfile= [[Media:adcube_installer.sis]]
 
|devices= <!-- Devices tested against - e.g. ''devices=Nokia 6131 NFC, Nokia C7-00'') -->
 
|devices= <!-- Devices tested against - e.g. ''devices=Nokia 6131 NFC, Nokia C7-00'') -->
 
|sdk= Qt SDK 4.7.4<!-- SDK(s) built and tested against (e.g. [http://linktosdkdownload/ Qt SDK 1.1.4]) -->
 
|sdk= Qt SDK 4.7.4<!-- SDK(s) built and tested against (e.g. [http://linktosdkdownload/ Qt SDK 1.1.4]) -->
Line 27: Line 28:
 
== Introduction ==
 
== Introduction ==
  
There are several ways to make money with your application. One that is currently quite interesting especially for smaller developers is advertising. Currently, there are no built-in advertisement platform for Symbian devices, but there is a third-party solution officially recommended by Nokia: [http://inner-active.com Inneractive]. They provide a wide variety of different SDKs which can be quite easily be integrated for your application. Inneractive does not currently have any solution for using their SDK within 3D content. However, they do provide a simple and robust HTTP-protocol for custom purposes. This article/example deploys that SDK and explains howto use it in a QtOpenGL Symbian^3 application.
+
There are several ways to make money with your application. One that is currently quite interesting, especially for smaller developers, is advertising. Currently, there are no built-in advertisement platform for Symbian devices, but there is a third-party solution officially recommended by Nokia: [http://inner-active.com Inneractive]. They provide a wide variety of different SDKs which can be quite easily be integrated for your application.  
  
 +
While Inneractive allows you to apply normal 2D advertising to your 3D app, there is no support for "3D" advertising - using an advert in a custom way within 3D - content (for example as a texture on your 3d shape like in this example). However, they do provide a simple and robust HTTP-protocol for fetching advertisement data, which can be used for this purpose. This article/example deploys that SDK and explains how to use it in a QtOpenGL Symbian^3 application.
  
== The example applcation ==  
+
== The example application ==  
  
[[File:1.png|240px]]
+
[[File:Ogl-es_1.png|240px]]
[[File:2.png|240px]]
+
[[File:Ogl-es 2.png|240px]]
[[File:3.png|240px]]
+
[[File:Ogl-es 3.png|240px]]
  
 
=== IAEngine ===  
 
=== IAEngine ===  
 
The Inneractive's server SDK is completely implemented in this class. The main princible is that the object owns one {{Qapiname|QNetworkAccessManager}}, which it uses to fetch new advertisements to be stored in-class linked list of {{Icode|IACapsule}}'s which will contain the advertisement information. {{Icode|IAEngine}} is meant to be as simple as possible as seen from it's very simple interface:
 
The Inneractive's server SDK is completely implemented in this class. The main princible is that the object owns one {{Qapiname|QNetworkAccessManager}}, which it uses to fetch new advertisements to be stored in-class linked list of {{Icode|IACapsule}}'s which will contain the advertisement information. {{Icode|IAEngine}} is meant to be as simple as possible as seen from it's very simple interface:
  
<code cpp>
+
<code cpp-qt>
 
bool requestAd();
 
bool requestAd();
 
int getCapsuleCount();
 
int getCapsuleCount();
Line 51: Line 53:
  
 
More detailed description of Inneractive's server API can be found as a PDF document from their webpages after creating an account.
 
More detailed description of Inneractive's server API can be found as a PDF document from their webpages after creating an account.
 
  
 
=== IACapsule ===
 
=== IACapsule ===
 
The {{Icode|IACapsule}} is just a holder for a single advertisement's information. {{Icode|IAEngine}} creates these and fills them when it's requests complete. It's properties are public for easy access.
 
The {{Icode|IACapsule}} is just a holder for a single advertisement's information. {{Icode|IAEngine}} creates these and fills them when it's requests complete. It's properties are public for easy access.
  
<code cpp>
+
<code cpp-qt>
 
bool m_failed;              // true if some requests for this ad have been failed
 
bool m_failed;              // true if some requests for this ad have been failed
 
QString text;              // Text string associated with this Ad
 
QString text;              // Text string associated with this Ad
Line 63: Line 64:
 
QImage m_image;            // Fetched and decoded image for displaying
 
QImage m_image;            // Fetched and decoded image for displaying
 
</code>
 
</code>
 
  
 
=== XMLE ===
 
=== XMLE ===
Line 100: Line 100:
  
 
The corresponding transformation can be done like this:
 
The corresponding transformation can be done like this:
<code cpp>
+
<code cpp-qt>
 
void Widget::transformVector( QVector3D source, QVector3D &target )
 
void Widget::transformVector( QVector3D source, QVector3D &target )
 
{
 
{
Line 109: Line 109:
 
}
 
}
 
</code>
 
</code>
 
 
  
 
=== Backface culling ===  
 
=== Backface culling ===  
 
There are several methods implementing backface culling. I have always used just a 2D cross-product which, in my opinion, is the best and simplest:
 
There are several methods implementing backface culling. I have always used just a 2D cross-product which, in my opinion, is the best and simplest:
  
<code cpp>
+
<code cpp-qt>
 
QVector3D tTemp[4]; // Quad screen coordinates
 
QVector3D tTemp[4]; // Quad screen coordinates
 
// Any 2D vector between 2 points of the quad
 
// Any 2D vector between 2 points of the quad
Line 128: Line 126:
  
 
if crosstest is below zero, the quad is facing away from the camera.  Other '''backface culling''' methods can be found around from the Internet.
 
if crosstest is below zero, the quad is facing away from the camera.  Other '''backface culling''' methods can be found around from the Internet.
 
  
 
=== Inside a quad ===
 
=== Inside a quad ===
 
The principle used by this example can be extended very easily to cover all convex polygons and quite easily to cover convex-polygons as well. In the name of simplicity, the following function only works with quads.
 
The principle used by this example can be extended very easily to cover all convex polygons and quite easily to cover convex-polygons as well. In the name of simplicity, the following function only works with quads.
  
<code cpp>
+
<code cpp-qt>
 
bool Widget::pointInsideQuad( float x, float y, QVector3D *quad )
 
bool Widget::pointInsideQuad( float x, float y, QVector3D *quad )
 
{
 
{
Line 179: Line 176:
  
 
Function interpolates each edge of a quad according the points y -coordinate. If y is between edge lines a xedge is calculated by interpolating the edge's x-coordinate according the y. After x-edge calculation, if there are two of them, the x-coordinate is checked weither it's between these x edges or not. If it is, coordinate is inside the quad.
 
Function interpolates each edge of a quad according the points y -coordinate. If y is between edge lines a xedge is calculated by interpolating the edge's x-coordinate according the y. After x-edge calculation, if there are two of them, the x-coordinate is checked weither it's between these x edges or not. If it is, coordinate is inside the quad.
 +
 +
== Downloads ==
 +
 +
* [[Media:adcube.zip]] - Symbian installation file
 +
* [[Media:adcube_installer.sis]] - source files
  
 
== Summary ==
 
== Summary ==
  
It is not difficult to implement a custom advertisement-fetching nor make textures out of the banners. For an actual application, the most challenging part would be howto intellectually use the advertisements so that they can be interacted by the user without affecting the applicaitons main functionality too much.
+
It is not difficult to implement a custom advertisement-fetching nor make textures out of the banners. The challenging job is to decide how to use advertisements appropriately - so that they don't impact the applications main functionality. The "custom advertising" - part (IAEngine.h / IAEngine.cpp and IACapsule.h) can be taken from this example and used in any kind of app that needs to display a custom ad.

Latest revision as of 04:18, 11 October 2012

Featured Article
10 Jun
2012

This article explains how to manually fetch banner advertisements from Inneractive, display them on the surface of a 3D cube using OpenGL, and then open a browser when a cube's side is clicked.

Article Metadata
Code Example
Source file: Media:adcube.zip
Installation file: Media:adcube_installer.sis
Tested with
SDK: Qt SDK 4.7.4
Compatibility
Platform(s): Symbian^3 and later
Device(s): OpenGL required (all current Symbian^3 devices except Nokia 500
Dependencies: Inneractive's server Api
Article
Keywords: custom advertisement opengl es context ad texture picker
Created: tuohirv (25 May 2012)
Last edited: hamishwillee (11 Oct 2012)

Contents

[edit] Introduction

There are several ways to make money with your application. One that is currently quite interesting, especially for smaller developers, is advertising. Currently, there are no built-in advertisement platform for Symbian devices, but there is a third-party solution officially recommended by Nokia: Inneractive. They provide a wide variety of different SDKs which can be quite easily be integrated for your application.

While Inneractive allows you to apply normal 2D advertising to your 3D app, there is no support for "3D" advertising - using an advert in a custom way within 3D - content (for example as a texture on your 3d shape like in this example). However, they do provide a simple and robust HTTP-protocol for fetching advertisement data, which can be used for this purpose. This article/example deploys that SDK and explains how to use it in a QtOpenGL Symbian^3 application.

[edit] The example application

Ogl-es 1.png Ogl-es 2.png Ogl-es 3.png

[edit] IAEngine

The Inneractive's server SDK is completely implemented in this class. The main princible is that the object owns one QNetworkAccessManager, which it uses to fetch new advertisements to be stored in-class linked list of IACapsule's which will contain the advertisement information. IAEngine is meant to be as simple as possible as seen from it's very simple interface:

bool requestAd();
int getCapsuleCount();
IACapsule *getCapsule( int index );
void releaseCapsules();

requestAd() starts a fetching of a new advertisement IF NO REQUEST currently exists (only one at the time). getCapsuleCount returns the size of a in-class IACapsule list; how many advertisements we currently have stored. getCapsule returns a requested capsule by index for an application to use anyway it wants and releaseCapsules destroys the whole list.

When a new advertisement is requested, IAEngine sends a HTTP request for it and waits for answer. When the answer arrives, new IACapsule is built and filled with the information of the reply. The actual advertisement banner is not contained by the initial reply so another HTTP-requedst must be made to fetch it. This means that the IACapsule is alive and available before it's banner image is fetched. When using the advertisements, an application should take this to consideration as well.

More detailed description of Inneractive's server API can be found as a PDF document from their webpages after creating an account.

[edit] IACapsule

The IACapsule is just a holder for a single advertisement's information. IAEngine creates these and fills them when it's requests complete. It's properties are public for easy access.

bool m_failed;              // true if some requests for this ad have been failed
QString text; // Text string associated with this Ad
QString targetUrl; // Url to launch when this Ad is "clicked"
QString imageUrl; // Url to image (banner) of this Ad
QImage m_image; // Fetched and decoded image for displaying

[edit] XMLE

TODO: This will be changed to Qt SDK's own XML parser. For fast developement purposes I've been using my own, simplest possible XML parser XMLE. The code is as platform independent as possible (It has Qt bindings only to QByteArray and QIODevice). It parses small XML chunks very fast and in a very practical memory structure. For this example, XMLE is used for reading the specific information from the data required from Inneractive's server API.

[edit] Widget

"As-simple-as-possible" QGLWidget based OpenGL ES 2.0 cube-renderer with minimal vertex / fragment shaders. The most complex part of it is the quad-picking required for knowing which side of the cube user has clicked. It will be explained in separate chapter later.

Widget owns a IAEngine which it calls to update it's advertisements until the amount of capsules reaches 6 (each side of the cube have it's own advertisement. The advertisements are burned in a single QImage with QPainter so only one texture is used for the entire cube. This QImage / GL texture is updated whenever advertisement list is changed. The advertisements are placed in a texture from top to bottom each of them using the whole width of the texture.


[edit] Picking a quad

Since this example is working with a cube. I've decided to use quads in the picking instead of triangles. However the princible can be easily extended to triangles. Since this example only has 6 quads, the picking code is not optimized but tried to keep as simple as possible.

The main princible is that when click arrives application does similar transformation on CPU side for the cube's vertices than OpenGL ES does when rendering. These screen coordinates are then used to see if the click-coordinate is inside a quad or not.

[edit] Deploying view / projection transformation manually

The vertex shader in this example uses separate orientation and projection matrices to make the transformation more clean. The vertex - shader looks like this:

attribute highp vec4 vertex;
attribute highp vec2 uv;
uniform mediump mat4 matrix;
uniform mediump mat4 proj;
varying highp vec4 frag_pos;
varying mediump vec2 texCoord;
void main(void)
{
frag_pos = matrix * vertex;
texCoord = uv;
gl_Position = proj*frag_pos;
}

The corresponding transformation can be done like this:

void Widget::transformVector( QVector3D source, QVector3D &target )
{
QVector4D trans = m_projection * (m_orientation*QVector4D( source, 1.0f));
target = QVector3D( trans.x() / (NEARPLANE+trans.z()) * width()/2 + width()/2,
-trans.y() / (NEARPLANE+trans.z()) * height()/2 + height()/2,
trans.z() );
}

[edit] Backface culling

There are several methods implementing backface culling. I have always used just a 2D cross-product which, in my opinion, is the best and simplest:

QVector3D tTemp[4];		// Quad screen coordinates
// Any 2D vector between 2 points of the quad
float tx1 = tTemp[3].x() - tTemp[0].x();
float ty1 = tTemp[3].y() - tTemp[0].y();
// Any other 2D vector between 2 points of the quad
float tx2 = tTemp[1].x() - tTemp[0].x();
float ty2 = tTemp[1].y() - tTemp[0].y();
// Cross product
float crosstest = tx1*ty2 - ty1*tx2;

if crosstest is below zero, the quad is facing away from the camera. Other backface culling methods can be found around from the Internet.

[edit] Inside a quad

The principle used by this example can be extended very easily to cover all convex polygons and quite easily to cover convex-polygons as well. In the name of simplicity, the following function only works with quads.

bool Widget::pointInsideQuad( float x, float y, QVector3D *quad )
{
int edgecount=0;
float xedges[2];
int p1, p2;
int point=0;
const int edgePoints[] = {0,1,2,3,0,2,1,3};
 
while (point<4) {
p1 = edgePoints[point*2+0];
p2 = edgePoints[point*2+1];
 
// Order the points so p1.y is always smaller than p2.y
if (quad[p1].y()>quad[p2].y()) {
int temp = p2;
p2 = p1;
p1 = temp;
}
 
// y between the points.
if (y>=quad[p1].y() && y<quad[p2].y() ) {
float ylength = (quad[p2].y() - quad[p1].y());
if (ylength==0.0f) ylength = 0.0000001f; // Prevent division by zero
// Interpolate xedge according y
xedges[edgecount] = quad[p1].x() + (quad[p2].x() - quad[p1].x()) *
( y-quad[p1].y() ) / ylength;
edgecount++;
if (edgecount==2) break;
}
 
point++;
}
// If the coordinate is between left and right edges, it's inside the quad.
if (edgecount==2) { // must be 2
if (xedges[0]<xedges[1]) {
if (x>=xedges[0] && x<xedges[1]) return true;
} else {
if (x>=xedges[1] && x<xedges[0]) return true;
}
}
return false;
}

Function interpolates each edge of a quad according the points y -coordinate. If y is between edge lines a xedge is calculated by interpolating the edge's x-coordinate according the y. After x-edge calculation, if there are two of them, the x-coordinate is checked weither it's between these x edges or not. If it is, coordinate is inside the quad.

[edit] Downloads

[edit] Summary

It is not difficult to implement a custom advertisement-fetching nor make textures out of the banners. The challenging job is to decide how to use advertisements appropriately - so that they don't impact the applications main functionality. The "custom advertising" - part (IAEngine.h / IAEngine.cpp and IACapsule.h) can be taken from this example and used in any kind of app that needs to display a custom ad.

This page was last modified on 11 October 2012, at 04:18.
92 page views in the last 30 days.
×