├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── README.md
├── ic_launcher-web.png
├── libs
└── android-support-v4.jar
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ ├── ic_launcher.png
│ ├── pic1.png
│ ├── picture1.jpg
│ ├── picture2.jpg
│ └── picture3.jpg
├── drawable-ldpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── layout
│ └── activity_gl.xml
├── menu
│ └── activity_gl.xml
├── raw
│ ├── _fragment_shader.glsl
│ ├── _vertex_shader.glsl
│ ├── blurring_fragment_shader.glsl
│ ├── edge_detect_fragment_shader.glsl
│ ├── emboss_fragment_shader.glsl
│ ├── filter_fragment_shader.glsl
│ ├── flip_fragment_shader.glsl
│ ├── hueshift_fragment_shader.glsl
│ ├── luminance_fragment_shader.glsl
│ ├── negative_fragment_shader.glsl
│ ├── toon_fragment_shader.glsl
│ ├── twirl_fragment_shader.glsl
│ └── warp_fragment_shader.glsl
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
└── values
│ ├── strings.xml
│ └── styles.xml
└── src
└── com
└── research
└── gltest
├── GLActivity.java
├── GLLayer.java
├── RawResourceReader.java
├── ShaderHelper.java
└── TextureHelper.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Eclipse project files
19 | .classpath
20 | .project
21 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | GLtest
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##Having Fun: Image Processing with OpenGL ES Fragment Shaders
2 | By [LittleCheeseCake](http://littlecheesecake.me)
3 |
4 | I have taken a very long time to get myself familiar with OpenGL ES Shaders. Finally I made some codes run and got some results that looked nice. The main area I want to explore is to use shaders to perform general purpose GPU computation (GPGPU). Here I summarize some image manipulation examples from the very popular textbook Graphics Shaders: theory and practice by Bailey and Cunningham[1]. The examples are made to be running on the Android phone.
5 |
6 | ###I) Texture mapping using OpenGL ES 2.0
7 |
8 | Here[2] is a good online tutorial to get start with on OpenGL ES 2.0 for Android. A simple project of texture mapping is created. It basically maps an bitmap image to a square fragment that fits into the window size of the device. The fun things I am going to do start from this stage.
9 |
10 | 
11 |
12 | ###II) Basic Concepts
13 |
14 | GLSL deals with images by treating them as textures and using texture access and manipulation to set the color of each pixel in the color buffer. This texture file may be treated as an image raster by working with each texel individually. Since any OpenGL texture has texture coordinates ranging from 0.0 to 1.0, the coordinates of the center of the image are vec(0.5, 0.5) and you can increment texture coordinates by 1./ResS or 1./ResT to move from one texel to another horizontally or vertically. ResS and ResT are the sizes of the displayed image in pixel.
15 |
16 | ###III) Working with Fragment Shaders
17 |
18 | The Fragment Shader is responsible for the per texel processing. The manipulation of the image pixels are handled merely using Fragment Shaders. Here is the simple fragment shader that just displays the texture:
19 |
20 | ```c
21 | precision mediump float;
22 | uniform sampler2D u_Texture;
23 | varying vec2 v_TexCoordinate;
24 |
25 | void main()
26 | {
27 | gl_FragColor = (texture2D(u_Texture, v_TexCoordinate));
28 | }
29 | ```
30 |
31 | ####i) Color/Brightness/Hue
32 |
33 | __Luminance__: luminance is defined as a linear combination of red, green and blue. The weight vector is a `const: vec3(0.2125, 0.7154, 0.0721).`
34 |
35 | ```c
36 | uniform sampler2D u_Texture;
37 | varying vec2 v_TexCoordinate;
38 | void main()
39 |
40 | {
41 | const vec3 W = vec3(0.2125, 0.1754, 0.0721);
42 | vec3 irgb = texture2D(u_Texture, v_TexCoordinate).rgb;
43 | float luminance = dot(irgb, W);
44 | gl_FragColor = vec4(luminance, luminance, luminance, 1.);
45 | }
46 | ```
47 |
48 | 
49 |
50 | __Hue shifting__: the RGB is first converted into the HSV color space, the hue shifting is just a adjustment of the h value in degree.The code is a bit long, check it out in the source code directory.
51 |
52 | 
53 |
54 |
55 | __Negative__: negative is obtained by subtracting the color of each pixel from the white
56 |
57 | ```c
58 | precision mediump float;
59 | uniform sampler2D u_Texture;
60 | varying vec2 v_TexCoordinate;
61 |
62 | void main()
63 | {
64 | float T = 1.0;
65 | vec2 st = v_TexCoordinate.st;
66 | vec3 irgb = texture2D(u_Texture, st).rgb;
67 | vec3 neg = vec3(1., 1., 1.)-irgb;
68 | gl_FragColor = vec4(mix(irgb,neg, T), 1.);
69 | }
70 | ```
71 |
72 | 
73 |
74 | __Brightness__: add or subtract black can be used to adjust the brightness of the image
75 |
76 | ```c
77 | precision mediump float;
78 | uniform sampler2D u_Texture;
79 | varying vec2 v_TexCoordinate;
80 | void main()
81 | {
82 | float T = 2.0;
83 | vec2 st = v_TexCoordinate.st;
84 | vec3 irgb = texture2D(u_Texture, st).rgb;
85 | vec3 black = vec3(0., 0., 0.);
86 | gl_FragColor = vec4(mix(black, irgb, T), 1.);
87 | }
88 | ```
89 |
90 | 
91 |
92 | __Contrast__: use a gray image as a base image, and mix with the color image. It can be made either move the color component towards the gray or away from. That is how the contrast is adjusted.
93 |
94 | ```c
95 | precision mediump float;
96 | uniform sampler2D u_Texture;
97 | varying vec2 v_TexCoordinate;
98 |
99 | void main()
100 | {
101 | float T = 2.0;
102 | vec2 st = v_TexCoordinate.st;
103 | vec3 irgb = texture2D(u_Texture, st).rgb;
104 | vec3 target = vec3(0.5, 0.5, 0.5);
105 | gl_FragColor = vec4(mix(target, irgb, T), 1.);
106 | }
107 | ```
108 |
109 | 
110 |
111 | __Saturation__: mix the color and grayscale image from the luminance example, can obtain a saturated image
112 |
113 | ```c
114 | precision mediump float;
115 | uniform sampler2D u_Texture;
116 | varying vec2 v_TexCoordinate;
117 | const vec3 W = vec3(0.2125, 0.7154, 0.0721);
118 |
119 | void main()
120 | {
121 | float T = 0.5;
122 | vec2 st = v_TexCoordinate.st;
123 | vec3 irgb = texture2D(u_Texture, st).rgb;
124 | float luminance = dot(irgb, W);
125 | vec3 target = vec3(luminance, luminance, luminance);
126 | gl_FragColor = vec4(mix(target, irgb, T), 1.);
127 | }
128 | ```
129 |
130 | 
131 |
132 | ####ii) Warping/Distortion
133 |
134 | The __twirl__ transformation rotates the image around a given anchor point(xc, yc) by an angle that varies across the space from a value alpha at the center, decreasing linearly with the radial distance as it proceeds toward a limiting radius r. There are lots of other transformation worthy being tried.
135 |
136 | 
137 |
138 | ####iii) Image processing/vision
139 |
140 | __Edge detection__: Sobel filter[3] is used for edge detection. The manipulation of neighboring pixels are required. Here we need to know the exact width and height of the texture displayed in pixel. However I haven't figure out how to do this. So I cheated a bit, just use the screen height (720 px in this case) since the image is assumed to fit in the window, which is not exactly true.
141 |
142 | 
143 |
144 | __Blurring__: 3x3 Gaussian filter s used for blurring in this case. The result is not a obvious since a small radius is used.
145 |
146 | 
147 |
148 | ####iv) Artistic Effect
149 |
150 | __Embossing__: the embossing image is obtained from applying the edge detection luminanced image and highlighting the images differently depending on the edges' angle.
151 |
152 |
153 | 
154 |
155 | __Toon__ like image: steps includes -Calculate the luminance of each pixel, apply the Sobel filter to detect edge and get a magnitude, if magnitude is larger than the threshold, color the pixel black, else quantize the pixel's color.
156 |
157 |
158 | 
159 |
160 |
161 | ###Closure:
162 |
163 | These are all simple image manipulations that can be easily done by software like Photoshop. The interesting thing is that it is now running on the GPU of the embedded devices. The advances of GPGPU might not be seen from here, but I will try to do some efficiency evaluations and continue with my "serious" research to see how it will help.
164 |
165 | [1]:http://books.google.com.sg/books/about/Graphics_Shaders.html?id=29YSpc-aOlgC&redir_esc=y
166 | [2]:http://www.learnopengles.com/android-lesson-four-introducing-basic-texturing/
167 | [3]:http://homepages.inf.ed.ac.uk/rbf/HIPR2/sobel.htm
168 |
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/ic_launcher-web.png
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-15
15 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/pic1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/res/drawable-hdpi/pic1.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/picture1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/res/drawable-hdpi/picture1.jpg
--------------------------------------------------------------------------------
/res/drawable-hdpi/picture2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/res/drawable-hdpi/picture2.jpg
--------------------------------------------------------------------------------
/res/drawable-hdpi/picture3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/res/drawable-hdpi/picture3.jpg
--------------------------------------------------------------------------------
/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulu/GLtext/2b41ea3213b21048fc42b605fb1d8bc731544c7c/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/layout/activity_gl.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/res/menu/activity_gl.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/res/raw/_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform sampler2D u_Texture;
3 | varying vec2 v_TexCoordinate;
4 |
5 | void main()
6 | {
7 | gl_FragColor = (texture2D(u_Texture, v_TexCoordinate));
8 | }
--------------------------------------------------------------------------------
/res/raw/_vertex_shader.glsl:
--------------------------------------------------------------------------------
1 | uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix.
2 |
3 | attribute vec4 a_Position; // Per-vertex position information we will pass in.
4 | attribute vec2 a_TexCoordinate; // Per-vertex texture coordinate information we will pass in.
5 |
6 | varying vec2 v_TexCoordinate; // This will be passed into the fragment shader.
7 |
8 | // The entry point for our vertex shader.
9 | void main()
10 | {
11 | // Pass through the texture coordinate.
12 | v_TexCoordinate = a_TexCoordinate;
13 |
14 | // gl_Position is a special variable used to store the final position.
15 | // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
16 | gl_Position = u_MVPMatrix * a_Position;
17 | }
--------------------------------------------------------------------------------
/res/raw/blurring_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform sampler2D u_Texture;
3 | varying vec2 v_TexCoordinate;
4 |
5 | void main()
6 | {
7 | vec3 irgb = texture2D(u_Texture, v_TexCoordinate).rgb;
8 | float ResS = 720.;
9 | float ResT = 720.;
10 |
11 | vec2 stp0 = vec2(1./ResS, 0.);
12 | vec2 st0p = vec2(0., 1./ResT);
13 | vec2 stpp = vec2(1./ResS, 1./ResT);
14 | vec2 stpm = vec2(1./ResS, -1./ResT);
15 |
16 | vec3 i00 = texture2D(u_Texture, v_TexCoordinate).rgb;
17 | vec3 im1m1 = texture2D(u_Texture, v_TexCoordinate-stpp).rgb;
18 | vec3 ip1p1 = texture2D(u_Texture, v_TexCoordinate+stpp).rgb;
19 | vec3 im1p1 = texture2D(u_Texture, v_TexCoordinate-stpm).rgb;
20 | vec3 ip1m1 = texture2D(u_Texture, v_TexCoordinate+stpm).rgb;
21 | vec3 im10 = texture2D(u_Texture, v_TexCoordinate-stp0).rgb;
22 | vec3 ip10 = texture2D(u_Texture, v_TexCoordinate+stp0).rgb;
23 | vec3 i0m1 = texture2D(u_Texture, v_TexCoordinate-st0p).rgb;
24 | vec3 i0p1 = texture2D(u_Texture, v_TexCoordinate+st0p).rgb;
25 |
26 | vec3 target = vec3(0., 0., 0.);
27 | target += 1.*(im1m1+ip1m1+ip1p1+im1p1);
28 | target += 2.*(im10+ip10+i0p1);
29 | target += 4.*(i00);
30 | target /= 16.;
31 | gl_FragColor = vec4(target, 1.);
32 | }
--------------------------------------------------------------------------------
/res/raw/edge_detect_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform sampler2D u_Texture;
3 | varying vec2 v_TexCoordinate;
4 |
5 | void main()
6 | {
7 | vec3 irgb = texture2D(u_Texture, v_TexCoordinate).rgb;
8 | float ResS = 720.;
9 | float ResT = 720.;
10 |
11 | vec2 stp0 = vec2(1./ResS, 0.);
12 | vec2 st0p = vec2(0., 1./ResT);
13 | vec2 stpp = vec2(1./ResS, 1./ResT);
14 | vec2 stpm = vec2(1./ResS, -1./ResT);
15 |
16 | const vec3 W = vec3(0.2125, 0.7154, 0.0721);
17 | float i00 = dot(texture2D(u_Texture, v_TexCoordinate).rgb, W);
18 | float im1m1 = dot(texture2D(u_Texture, v_TexCoordinate-stpp).rgb, W);
19 | float ip1p1 = dot(texture2D(u_Texture, v_TexCoordinate+stpp).rgb, W);
20 | float im1p1 = dot(texture2D(u_Texture, v_TexCoordinate-stpm).rgb, W);
21 | float ip1m1 = dot(texture2D(u_Texture, v_TexCoordinate+stpm).rgb, W);
22 | float im10 = dot(texture2D(u_Texture, v_TexCoordinate-stp0).rgb, W);
23 | float ip10 = dot(texture2D(u_Texture, v_TexCoordinate+stp0).rgb, W);
24 | float i0m1 = dot(texture2D(u_Texture, v_TexCoordinate-st0p).rgb, W);
25 | float i0p1 = dot(texture2D(u_Texture, v_TexCoordinate+st0p).rgb, W);
26 | float h = -1.*im1p1 - 2.*i0p1 - 1.*ip1p1 + 1.*im1m1 + 2.*i0m1 + 1.*ip1m1;
27 | float v = -1.*im1m1 - 2.*im10 - 1.*im1p1 + 1.*ip1m1 + 2.*ip10 + 1.*ip1p1;
28 |
29 | float mag = length(vec2(h, v));
30 | vec3 target = vec3(mag, mag, mag);
31 | gl_FragColor = vec4(mix(irgb, target, 1.0),1.);
32 | }
--------------------------------------------------------------------------------
/res/raw/emboss_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform sampler2D u_Texture;
3 | varying vec2 v_TexCoordinate;
4 |
5 | void main()
6 | {
7 | vec3 irgb = texture2D(u_Texture, v_TexCoordinate).rgb;
8 | float ResS = 720.;
9 | float ResT = 720.;
10 |
11 | vec2 stp0 = vec2(1./ResS, 0.);
12 | vec2 stpp = vec2(1./ResS, 1./ResT);
13 | vec3 c00 = texture2D(u_Texture, v_TexCoordinate).rgb;
14 | vec3 cp1p1 = texture2D(u_Texture, v_TexCoordinate + stpp).rgb;
15 |
16 | vec3 diffs = c00 - cp1p1;
17 | float max = diffs.r;
18 | if(abs(diffs.g)>abs(max)) max = diffs.g;
19 | if(abs(diffs.b)>abs(max)) max = diffs.b;
20 |
21 | float gray = clamp(max + .5, 0., 1.);
22 | vec3 color = vec3(gray, gray, gray);
23 |
24 | gl_FragColor = vec4(mix(color,c00, 0.1), 1.);
25 | }
--------------------------------------------------------------------------------
/res/raw/filter_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform sampler2D u_Texture0;
3 | uniform sampler2D u_Texture1;
4 | varying vec2 v_TexCoordinate;
5 |
6 | void main()
7 | {
8 | vec4 baseColor;
9 | vec4 filterColor;
10 |
11 | baseColor = texture2D(u_Texture0, v_TexCoordinate);
12 | filterColor = texture2D(u_Texture1, v_TexCoordinate);
13 |
14 | gl_FragColor = baseColor*(filterColor+0.25);
15 | }
--------------------------------------------------------------------------------
/res/raw/flip_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float; // Set the default precision to medium. We don't need as high of a
2 | // precision in the fragment shader.
3 |
4 | uniform sampler2D u_Texture; // The input texture.
5 |
6 | varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment
7 |
8 | void main()
9 | {
10 | vec2 st = v_TexCoordinate.st;
11 | st.s = 1. - st.s;
12 | st.t = 1. - st.t;
13 |
14 | vec3 irgb = texture2D(u_Texture, st).rgb;
15 | gl_FragColor = vec4(irgb, 1.);
16 | }
--------------------------------------------------------------------------------
/res/raw/hueshift_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float; // Set the default precision to medium. We don't need as high of a
2 | // precision in the fragment shader.
3 |
4 | uniform sampler2D u_Texture; // The input texture.
5 |
6 | varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment
7 |
8 | const float shift = 90.;
9 |
10 | vec3 convertRGB2HSV(vec3 rgbcolor){
11 | float h, s, v;
12 |
13 | float r = rgbcolor.r;
14 | float g = rgbcolor.g;
15 | float b = rgbcolor.b;
16 | v = max(r, max(g, b));
17 | float maxval = v;
18 | float minval = min(r, min(g,b));
19 |
20 | if(maxval == 0.)
21 | s = 0.0;
22 | else
23 | s = (maxval - minval)/maxval;
24 |
25 | if(s == 0.)
26 | h = 0.;
27 | else{
28 | float delta = maxval - minval;
29 |
30 | if(r == maxval)
31 | h = (g-b)/delta;
32 | else
33 | if(g == maxval)
34 | h = 2.0 + (b-r)/delta;
35 | else
36 | if(b == maxval)
37 | h = 4.0 + (r-g)/delta;
38 |
39 | h*= 60.;
40 | if( h < 0.0)
41 | h += 360.;
42 | }
43 |
44 | return vec3(h, s, v);
45 | }
46 |
47 | vec3 convertHSV2RGB(vec3 hsvcolor)
48 | {
49 | float h = hsvcolor.x;
50 | float s = hsvcolor.y;
51 | float v = hsvcolor.z;
52 |
53 | if(s == 0.0)
54 | {
55 | return vec3(v,v,v);
56 | }
57 |
58 | else{
59 | if(h > 360.0) h = 360.0;
60 | if(h < 0.0) h = 0.0;
61 |
62 | h /= shift;
63 | int k = int(h);
64 | float f = h - float(k);
65 | float p = v*(1.0-s);
66 | float q = v*(1.0-(s*f));
67 | float t = v*(1.0-(s*(1.0-f)));
68 |
69 | vec3 target;
70 | if(k==0) target = vec3(v,t,p);
71 | if(k==1) target = vec3(q,v,p);
72 | if(k==2) target = vec3(p,v,t);
73 | if(k==3) target = vec3(p,q,v);
74 | if(k==4) target = vec3(t,p,v);
75 | if(k==5) target = vec3(v,p,q);
76 |
77 | return target;
78 | }
79 | }
80 |
81 | void main()
82 | {
83 | //angle of the hue shifting
84 | float T = 70.0;
85 |
86 | vec3 irgb = texture2D(u_Texture, v_TexCoordinate).rgb;
87 | vec3 ihsv = convertRGB2HSV(irgb);
88 | ihsv.x += T;
89 | if(ihsv.x > 360.) ihsv.x -= 360.;
90 | if(ihsv.x < 0.) ihsv.x += 360.;
91 | irgb = convertHSV2RGB(ihsv);
92 | gl_FragColor = vec4(irgb, 1.);
93 | }
94 |
--------------------------------------------------------------------------------
/res/raw/luminance_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float; // Set the default precision to medium. We don't need as high of a
2 | // precision in the fragment shader.
3 |
4 | uniform sampler2D u_Texture; // The input texture.
5 |
6 | varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment.
7 |
8 | // The entry point for our fragment shader.
9 | void main()
10 | {
11 | //wegith constant
12 | const vec3 W = vec3(0.2125, 0.1754, 0.0721);
13 |
14 | //get rgb color from texture
15 | vec3 irgb = texture2D(u_Texture, v_TexCoordinate).rgb;
16 |
17 | //get luminance
18 | float luminance = dot(irgb, W);
19 |
20 | //output the pixel
21 | gl_FragColor = vec4(luminance, luminance, luminance, 1.);
22 | }
23 |
--------------------------------------------------------------------------------
/res/raw/negative_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float; // Set the default precision to medium. We don't need as high of a
2 | // precision in the fragment shader.
3 |
4 | uniform sampler2D u_Texture; // The input texture.
5 |
6 | varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment
7 | const vec3 W = vec3(0.2125, 0.7154, 0.0721);
8 |
9 | void main()
10 | {
11 | float T = 0.5;
12 |
13 | vec2 st = v_TexCoordinate.st;
14 | vec3 irgb = texture2D(u_Texture, st).rgb;
15 |
16 | float luminance = dot(irgb, W);
17 | vec3 target = vec3(luminance, luminance, luminance);
18 |
19 | gl_FragColor = vec4(mix(target, irgb, T), 1.);
20 | }
--------------------------------------------------------------------------------
/res/raw/toon_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float; // Set the default precision to medium. We don't need as high of a
2 | // precision in the fragment shader.
3 |
4 | uniform sampler2D u_Texture; // The input texture.
5 |
6 | varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment
7 |
8 | void main()
9 | {
10 | float ResS = 720.;
11 | float ResT = 720.;
12 | float MagTol = .5;
13 | float Quantize = 10.;
14 |
15 | vec3 irgb = texture2D(u_Texture, v_TexCoordinate).rgb;
16 | vec2 stp0 = vec2(1./ResS, 0.);
17 | vec2 st0p = vec2(0., 1./ResT);
18 | vec2 stpp = vec2(1./ResS, 1./ResT);
19 | vec2 stpm = vec2(1./ResS, -1./ResT);
20 |
21 | const vec3 W = vec3(0.2125, 0.7154, 0.0721);
22 | float i00 = dot(texture2D(u_Texture, v_TexCoordinate).rgb, W);
23 | float im1m1 = dot(texture2D(u_Texture, v_TexCoordinate-stpp).rgb, W);
24 | float ip1p1 = dot(texture2D(u_Texture, v_TexCoordinate+stpp).rgb, W);
25 | float im1p1 = dot(texture2D(u_Texture, v_TexCoordinate-stpm).rgb, W);
26 | float ip1m1 = dot(texture2D(u_Texture, v_TexCoordinate+stpm).rgb, W);
27 | float im10 = dot(texture2D(u_Texture, v_TexCoordinate-stp0).rgb, W);
28 | float ip10 = dot(texture2D(u_Texture, v_TexCoordinate+stp0).rgb, W);
29 | float i0m1 = dot(texture2D(u_Texture, v_TexCoordinate-st0p).rgb, W);
30 | float i0p1 = dot(texture2D(u_Texture, v_TexCoordinate+st0p).rgb, W);
31 |
32 | //H and V sobel filters
33 | float h = -1.*im1p1 - 2.*i0p1 - 1.*ip1p1 + 1.*im1m1 + 2.*i0m1 + 1.*ip1m1;
34 | float v = -1.*im1m1 - 2.*im10 - 1.*im1p1 + 1.*ip1m1 + 2.*ip10 + 1.*ip1p1;
35 | float mag = length(vec2(h, v));
36 |
37 | if(mag > MagTol){
38 | gl_FragColor = vec4(0., 0., 0., 1.);
39 | }else{
40 | irgb.rgb *= Quantize;
41 | irgb.rgb += vec3(.5,.5,.5);
42 | ivec3 intrgb = ivec3(irgb.rgb);
43 | irgb.rgb = vec3(intrgb)/Quantize;
44 | gl_FragColor = vec4(irgb, 1.);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/res/raw/twirl_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float; // Set the default precision to medium. We don't need as high of a
2 | // precision in the fragment shader.
3 |
4 | uniform sampler2D u_Texture; // The input texture.
5 |
6 | varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment
7 |
8 |
9 | void main()
10 | {
11 | float Res = 720.;
12 | float D = -80.;
13 | float R = 0.3;
14 |
15 | vec2 st = v_TexCoordinate.st;
16 | float Radius = Res * R;
17 | vec2 xy = Res * st;
18 |
19 | vec2 dxy = xy - Res/2.;
20 | float r = length(dxy);
21 | float beta = atan(dxy.y, dxy.x) + radians(D)*(Radius - r)/Radius;
22 |
23 | vec2 xy1 = xy;
24 | if(r <= Radius)
25 | {
26 | xy1.s = Res/2. + r*vec2(cos(beta)).s;
27 | xy1.t = Res/2. + r*vec2(sin(beta)).t;
28 | }
29 | st = xy1/Res;
30 |
31 | vec3 irgb = texture2D(u_Texture, st).rgb;
32 | gl_FragColor = vec4(irgb, 1.);
33 | }
--------------------------------------------------------------------------------
/res/raw/warp_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float; // Set the default precision to medium. We don't need as high of a
2 | // precision in the fragment shader.
3 |
4 | uniform sampler2D u_Texture; // The input texture.
5 |
6 | varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment
7 | const float PI = 3.14159265;
8 |
9 | void main()
10 | {
11 | float T = 0.2;
12 | vec2 st = v_TexCoordinate.st;
13 | vec2 xy = st;
14 | xy = 2.*xy - 1.;
15 | xy += T*sin(PI*xy);
16 | st = (xy + 1.)/2.;
17 |
18 | vec3 irgb = texture2D(u_Texture, st).rgb;
19 | gl_FragColor = vec4(irgb, 1.);
20 | }
--------------------------------------------------------------------------------
/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | GLtest
5 | Hello world!
6 | Settings
7 |
8 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/src/com/research/gltest/GLActivity.java:
--------------------------------------------------------------------------------
1 | package com.research.gltest;
2 |
3 | import android.opengl.GLSurfaceView;
4 | import android.os.Bundle;
5 | import android.app.Activity;
6 | import android.content.pm.ActivityInfo;
7 | import android.view.Menu;
8 | import android.view.MenuItem;
9 | import android.view.Window;
10 |
11 | public class GLActivity extends Activity {
12 | GLSurfaceView mView;
13 | private MenuItem mItemCapture0;
14 | private MenuItem mItemCapture1;
15 | private MenuItem mItemCapture2;
16 | private MenuItem mItemCapture3;
17 | private MenuItem mItemCapture4;
18 | private MenuItem mItemCapture5;
19 | private MenuItem mItemCapture6;
20 | private MenuItem mItemCapture7;
21 | private MenuItem mItemCapture8;
22 | private MenuItem mItemCapture9;
23 | private MenuItem mItemCapture10;
24 | private MenuItem mItemCapture11;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
30 | requestWindowFeature(Window.FEATURE_NO_TITLE);
31 |
32 | mView = new GLSurfaceView(this);
33 | mView.setEGLContextClientVersion(2);
34 | mView.setRenderer(new GLLayer(this));
35 |
36 | setContentView(mView);
37 | }
38 |
39 | /** Called when the activity is first created. */
40 | @Override
41 | public void onResume() {
42 | super.onResume();
43 | mView.onResume();
44 |
45 | }
46 | protected void onPause() {
47 | super.onPause();
48 | mView.onPause();
49 | }
50 |
51 | /**menu button setup*/
52 | @Override
53 | public boolean onCreateOptionsMenu(Menu menu) {
54 | mItemCapture0 = menu.add("origin");
55 | mItemCapture1 = menu.add("blurring");
56 | mItemCapture2= menu.add("edge_detect");
57 | mItemCapture3 = menu.add("emboss");
58 | mItemCapture4 = menu.add("filter");
59 | mItemCapture5 = menu.add("flip");
60 | mItemCapture6= menu.add("hue");
61 | mItemCapture7 = menu.add("luminance");
62 | mItemCapture8 = menu.add("negative");
63 | mItemCapture9= menu.add("toon");
64 | mItemCapture10 = menu.add("twirl");
65 | mItemCapture11 = menu.add("warp");
66 | return true;
67 |
68 | }
69 | @Override
70 | public boolean onOptionsItemSelected(MenuItem item) {
71 | if (item == mItemCapture0){
72 | GLLayer.shader_selection = 0;
73 | return true;
74 | }
75 | if (item == mItemCapture1){
76 | GLLayer.shader_selection = GLLayer.BLUR;
77 | return true;
78 | }
79 | if (item == mItemCapture2){
80 | GLLayer.shader_selection = GLLayer.EDGE;
81 | return true;
82 | }
83 | if (item == mItemCapture3){
84 | GLLayer.shader_selection = GLLayer.EMBOSS;
85 | return true;
86 | }
87 | if (item == mItemCapture4){
88 | GLLayer.shader_selection = GLLayer.FILTER;
89 | return true;
90 | }
91 | if (item == mItemCapture5){
92 | GLLayer.shader_selection = GLLayer.FLIP;
93 | return true;
94 | }
95 | if (item == mItemCapture6){
96 | GLLayer.shader_selection = GLLayer.HUE;
97 | return true;
98 | }
99 | if (item == mItemCapture7){
100 | GLLayer.shader_selection = GLLayer.LUM;
101 | return true;
102 | }
103 | if (item == mItemCapture8){
104 | GLLayer.shader_selection = GLLayer.NEG;
105 | return true;
106 | }
107 | if (item == mItemCapture9){
108 | GLLayer.shader_selection = GLLayer.TOON;
109 | return true;
110 | }
111 | if (item == mItemCapture10){
112 | GLLayer.shader_selection = GLLayer.TWIRL;
113 | return true;
114 | }
115 | if (item == mItemCapture11){
116 | GLLayer.shader_selection = GLLayer.WARP;
117 | return true;
118 | }
119 |
120 | return false;
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/src/com/research/gltest/GLLayer.java:
--------------------------------------------------------------------------------
1 | package com.research.gltest;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.nio.ByteOrder;
5 | import java.nio.FloatBuffer;
6 |
7 | import javax.microedition.khronos.egl.EGLConfig;
8 | import javax.microedition.khronos.opengles.GL10;
9 |
10 | import android.content.Context;
11 | import android.opengl.GLES20;
12 | import android.opengl.GLSurfaceView;
13 | import android.opengl.Matrix;
14 |
15 | public class GLLayer implements GLSurfaceView.Renderer {
16 | /**
17 | * This class implements our custom renderer. Note that the GL10 parameter
18 | * passed in is unused for OpenGL ES 2.0 renderers -- the static class
19 | * GLES20 is used instead.
20 | */
21 | private final Context mActivityContext;
22 |
23 | /**
24 | * Store the model matrix. This matrix is used to move models from object
25 | * space (where each model can be thought of being located at the center of
26 | * the universe) to world space.
27 | */
28 | private float[] mModelMatrix = new float[16];
29 |
30 | /**
31 | * Store the view matrix. This can be thought of as our camera. This matrix
32 | * transforms world space to eye space; it positions things relative to our
33 | * eye.
34 | */
35 | private float[] mViewMatrix = new float[16];
36 |
37 | /**
38 | * Store the projection matrix. This is used to project the scene onto a 2D
39 | * viewport.
40 | */
41 | private float[] mProjectionMatrix = new float[16];
42 |
43 | /**
44 | * Allocate storage for the final combined matrix. This will be passed into
45 | * the shader program.
46 | */
47 | private float[] mMVPMatrix = new float[16];
48 |
49 | /** Store our model data in a float buffer. */
50 | private final FloatBuffer mCubePositions;
51 | private final FloatBuffer mCubeColors;
52 | private final FloatBuffer mCubeTextureCoordinates;
53 |
54 | /** This will be used to pass in the transformation matrix. */
55 | private int mMVPMatrixHandle;
56 |
57 | /** This will be used to pass in the texture. */
58 | private int mTextureUniformHandle0;
59 | private int mTextureUniformHandle1;
60 |
61 | /** This will be used to pass in model position information. */
62 | private int mPositionHandle;
63 |
64 | /** This will be used to pass in model color information. */
65 | // private int mColorHandle;
66 |
67 | /** This will be used to pass in model texture coordinate information. */
68 | private int mTextureCoordinateHandle;
69 |
70 | /** How many bytes per float. */
71 | private final int mBytesPerFloat = 4;
72 |
73 | /** Size of the position data in elements. */
74 | private final int mPositionDataSize = 3;
75 |
76 | /** Size of the color data in elements. */
77 | // private final int mColorDataSize = 4;
78 |
79 | /** Size of the texture coordinate data in elements. */
80 | private final int mTextureCoordinateDataSize = 2;
81 |
82 | /** This is a handle to our cube shading program. */
83 | private int mProgramHandle;
84 |
85 | /** This is a handle to our texture data. */
86 | private int mTextureDataHandle0;
87 | private int mTextureDataHandle1;
88 |
89 | /**
90 | * Shader Titles
91 | */
92 | static public int shader_selection = 0;
93 | static public final int BLUR = 1;
94 | static public final int EDGE = 2;
95 | static public final int EMBOSS = 3;
96 | static public final int FILTER = 4;
97 | static public final int FLIP = 5;
98 | static public final int HUE = 6;
99 | static public final int LUM = 7;
100 | static public final int NEG = 8;
101 | static public final int TOON = 9;
102 | static public final int TWIRL = 10;
103 | static public final int WARP = 11;
104 | //and more ...
105 |
106 | /**
107 | * Initialize the model data.
108 | */
109 | public GLLayer(final Context activityContext) {
110 | mActivityContext = activityContext;
111 |
112 | // Define points for a cube.
113 |
114 | // X, Y, Z
115 | final float[] cubePositionData = {
116 | // In OpenGL counter-clockwise winding is default. This means
117 | // that when we look at a triangle,
118 | // if the points are counter-clockwise we are looking at the
119 | // "front". If not we are looking at
120 | // the back. OpenGL has an optimization where all back-facing
121 | // triangles are culled, since they
122 | // usually represent the backside of an object and aren't
123 | // visible anyways.
124 |
125 | // Front face
126 | -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
127 | -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
128 |
129 | // R, G, B, A
130 | final float[] cubeColorData = {
131 | // Front face (red)
132 | 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
133 | 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
134 | 1.0f, 0.0f, 0.0f, 1.0f };
135 |
136 | // X, Y, Z
137 | // The normal is used in light calculations and is a vector which points
138 | // orthogonal to the plane of the surface. For a cube model, the normals
139 | // should be orthogonal to the points of each face.
140 |
141 | // S, T (or X, Y)
142 | // Texture coordinate data.
143 | // Because images have a Y axis pointing downward (values increase as
144 | // you move down the image) while
145 | // OpenGL has a Y axis pointing upward, we adjust for that here by
146 | // flipping the Y axis.
147 | // What's more is that the texture coordinates are the same for every
148 | // face.
149 | final float[] cubeTextureCoordinateData = {
150 | // Front face
151 | 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
152 | 1.0f, 0.0f };
153 |
154 | // Initialize the buffers.
155 | mCubePositions = ByteBuffer
156 | .allocateDirect(cubePositionData.length * mBytesPerFloat)
157 | .order(ByteOrder.nativeOrder()).asFloatBuffer();
158 | mCubePositions.put(cubePositionData).position(0);
159 |
160 | mCubeColors = ByteBuffer
161 | .allocateDirect(cubeColorData.length * mBytesPerFloat)
162 | .order(ByteOrder.nativeOrder()).asFloatBuffer();
163 | mCubeColors.put(cubeColorData).position(0);
164 |
165 | mCubeTextureCoordinates = ByteBuffer
166 | .allocateDirect(
167 | cubeTextureCoordinateData.length * mBytesPerFloat)
168 | .order(ByteOrder.nativeOrder()).asFloatBuffer();
169 | mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);
170 | }
171 |
172 | protected String getVertexShader() {
173 | return RawResourceReader.readTextFileFromRawResource(mActivityContext,
174 | R.raw._vertex_shader);
175 | }
176 |
177 | protected String getFragmentShader() {
178 | int id;
179 | switch (shader_selection){
180 | case BLUR: id = R.raw.blurring_fragment_shader; break;
181 | case EDGE: id = R.raw.edge_detect_fragment_shader;break;
182 | case EMBOSS: id = R.raw.emboss_fragment_shader;break;
183 | case FILTER: id = R.raw.filter_fragment_shader;break;
184 | case FLIP: id = R.raw.flip_fragment_shader;break;
185 | case HUE: id = R.raw.hueshift_fragment_shader;break;
186 | case LUM: id = R.raw.luminance_fragment_shader;break;
187 | case NEG: id = R.raw.negative_fragment_shader;break;
188 | case TOON: id = R.raw.toon_fragment_shader;break;
189 | case TWIRL: id = R.raw.twirl_fragment_shader;break;
190 | case WARP: id = R.raw.warp_fragment_shader;break;
191 | default: id = R.raw._fragment_shader;break;
192 | }
193 |
194 | return RawResourceReader.readTextFileFromRawResource(mActivityContext, id);
195 | }
196 |
197 | @Override
198 | public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
199 | // Set the background clear color to black.
200 | GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
201 |
202 | // Use culling to remove back faces.
203 | GLES20.glEnable(GLES20.GL_CULL_FACE);
204 |
205 | // Enable depth testing
206 | GLES20.glEnable(GLES20.GL_DEPTH_TEST);
207 |
208 | // The below glEnable() call is a holdover from OpenGL ES 1, and is not
209 | // needed in OpenGL ES 2.
210 | // Enable texture mapping
211 | // GLES20.glEnable(GLES20.GL_TEXTURE_2D);
212 |
213 | // Position the eye in front of the origin.
214 | final float eyeX = 0.0f;
215 | final float eyeY = 0.0f;
216 | final float eyeZ = -0.5f;
217 |
218 | // We are looking toward the distance
219 | final float lookX = 0.0f;
220 | final float lookY = 0.0f;
221 | final float lookZ = -5.0f;
222 |
223 | // Set our up vector. This is where our head would be pointing were we
224 | // holding the camera.
225 | final float upX = 0.0f;
226 | final float upY = 1.0f;
227 | final float upZ = 0.0f;
228 |
229 | // Set the view matrix. This matrix can be said to represent the camera
230 | // position.
231 | // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination
232 | // of a model and
233 | // view matrix. In OpenGL 2, we can keep track of these matrices
234 | // separately if we choose.
235 | Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY,
236 | lookZ, upX, upY, upZ);
237 |
238 |
239 | // Load the texture
240 | mTextureDataHandle0 = TextureHelper.loadTexture(mActivityContext,
241 | R.drawable.picture2);
242 |
243 | // Load the texture
244 | mTextureDataHandle1 = TextureHelper.loadTexture(mActivityContext,
245 | R.drawable.picture3);
246 | }
247 |
248 | @Override
249 | public void onSurfaceChanged(GL10 glUnused, int width, int height) {
250 | // Set the OpenGL viewport to the same size as the surface.
251 | GLES20.glViewport(0, 0, width, height);
252 |
253 | // Create a new perspective projection matrix. The height will stay the
254 | // same
255 | // while the width will vary as per aspect ratio.
256 | final float ratio = (float) width / height;
257 | final float left = -ratio;
258 | final float right = ratio;
259 | final float bottom = -1.0f;
260 | final float top = 1.0f;
261 | final float near = 1.0f;
262 | final float far = 10.0f;
263 |
264 | Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
265 | }
266 |
267 | @Override
268 | public void onDrawFrame(GL10 glUnused) {
269 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
270 | final String vertexShader = getVertexShader();
271 | final String fragmentShader = getFragmentShader();
272 |
273 | final int vertexShaderHandle = ShaderHelper.compileShader(
274 | GLES20.GL_VERTEX_SHADER, vertexShader);
275 | final int fragmentShaderHandle = ShaderHelper.compileShader(
276 | GLES20.GL_FRAGMENT_SHADER, fragmentShader);
277 |
278 | mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle,
279 | fragmentShaderHandle, new String[] { "a_Position",
280 | "a_TexCoordinate" });
281 |
282 | // Set our per-vertex lighting program.
283 | GLES20.glUseProgram(mProgramHandle);
284 |
285 | // Set program handles for cube drawing.
286 | mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle,
287 | "u_MVPMatrix");
288 | mTextureUniformHandle0 = GLES20.glGetUniformLocation(mProgramHandle,
289 | "u_Texture0");
290 | mTextureUniformHandle1 = GLES20.glGetUniformLocation(mProgramHandle,
291 | "u_Texture1");
292 | mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle,
293 | "a_Position");
294 | mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle,
295 | "a_TexCoordinate");
296 |
297 | /**
298 | * First texture map
299 | */
300 | // Set the active texture0 unit to texture unit 0.
301 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
302 |
303 | // Bind the texture to this unit.
304 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle0);
305 |
306 | // Tell the texture uniform sampler to use this texture in the shader by
307 | // binding to texture unit 0.
308 | GLES20.glUniform1i(mTextureUniformHandle0, 0);
309 |
310 | /**
311 | * Second texture map
312 | */
313 | // Set the active texture1 unit to texture unit 1.
314 | GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
315 |
316 | // Bind the texture to this unit.
317 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle1);
318 |
319 | // Tell the texture uniform sampler to use this texture in the shader by
320 | // binding to texture unit 1.
321 | GLES20.glUniform1i(mTextureUniformHandle1, 1);
322 |
323 | // Draw some cubes.
324 | Matrix.setIdentityM(mModelMatrix, 0);
325 | Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -3.2f);
326 | Matrix.rotateM(mModelMatrix, 0, 0.0f, 1.0f, 1.0f, 0.0f);
327 | drawCube();
328 | }
329 |
330 | /**
331 | * Draws a cube.
332 | */
333 | private void drawCube() {
334 | // Pass in the position information
335 | mCubePositions.position(0);
336 | GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize,
337 | GLES20.GL_FLOAT, false, 0, mCubePositions);
338 |
339 | GLES20.glEnableVertexAttribArray(mPositionHandle);
340 |
341 | // Pass in the texture coordinate information
342 | mCubeTextureCoordinates.position(0);
343 | GLES20.glVertexAttribPointer(mTextureCoordinateHandle,
344 | mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0,
345 | mCubeTextureCoordinates);
346 |
347 | GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
348 |
349 | // This multiplies the view matrix by the model matrix, and stores the
350 | // result in the MVP matrix
351 | // (which currently contains model * view).
352 | Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
353 |
354 | // This multiplies the modelview matrix by the projection matrix, and
355 | // stores the result in the MVP matrix
356 | // (which now contains model * view * projection).
357 | Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
358 |
359 | // Pass in the combined matrix.
360 | GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
361 |
362 | // Draw the cube.
363 | GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
364 | }
365 | }
366 |
--------------------------------------------------------------------------------
/src/com/research/gltest/RawResourceReader.java:
--------------------------------------------------------------------------------
1 | package com.research.gltest;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.InputStreamReader;
7 |
8 | import android.content.Context;
9 |
10 | public class RawResourceReader
11 | {
12 | public static String readTextFileFromRawResource(final Context context,
13 | final int resourceId)
14 | {
15 | final InputStream inputStream = context.getResources().openRawResource(
16 | resourceId);
17 | final InputStreamReader inputStreamReader = new InputStreamReader(
18 | inputStream);
19 | final BufferedReader bufferedReader = new BufferedReader(
20 | inputStreamReader);
21 |
22 | String nextLine;
23 | final StringBuilder body = new StringBuilder();
24 |
25 | try
26 | {
27 | while ((nextLine = bufferedReader.readLine()) != null)
28 | {
29 | body.append(nextLine);
30 | body.append('\n');
31 | }
32 | }
33 | catch (IOException e)
34 | {
35 | return null;
36 | }
37 |
38 | return body.toString();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/com/research/gltest/ShaderHelper.java:
--------------------------------------------------------------------------------
1 | package com.research.gltest;
2 |
3 | import android.opengl.GLES20;
4 | import android.util.Log;
5 |
6 | public class ShaderHelper
7 | {
8 | private static final String TAG = "ShaderHelper";
9 |
10 | /**
11 | * Helper function to compile a shader.
12 | *
13 | * @param shaderType The shader type.
14 | * @param shaderSource The shader source code.
15 | * @return An OpenGL handle to the shader.
16 | */
17 | public static int compileShader(final int shaderType, final String shaderSource)
18 | {
19 | int shaderHandle = GLES20.glCreateShader(shaderType);
20 |
21 | if (shaderHandle != 0)
22 | {
23 | // Pass in the shader source.
24 | GLES20.glShaderSource(shaderHandle, shaderSource);
25 |
26 | // Compile the shader.
27 | GLES20.glCompileShader(shaderHandle);
28 |
29 | // Get the compilation status.
30 | final int[] compileStatus = new int[1];
31 | GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
32 |
33 | // If the compilation failed, delete the shader.
34 | if (compileStatus[0] == 0)
35 | {
36 | Log.e(TAG, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shaderHandle));
37 | GLES20.glDeleteShader(shaderHandle);
38 | shaderHandle = 0;
39 | }
40 | }
41 |
42 | if (shaderHandle == 0)
43 | {
44 | throw new RuntimeException("Error creating shader.");
45 | }
46 |
47 | return shaderHandle;
48 | }
49 |
50 | /**
51 | * Helper function to compile and link a program.
52 | *
53 | * @param vertexShaderHandle An OpenGL handle to an already-compiled vertex shader.
54 | * @param fragmentShaderHandle An OpenGL handle to an already-compiled fragment shader.
55 | * @param attributes Attributes that need to be bound to the program.
56 | * @return An OpenGL handle to the program.
57 | */
58 | public static int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes)
59 | {
60 | int programHandle = GLES20.glCreateProgram();
61 |
62 | if (programHandle != 0)
63 | {
64 | // Bind the vertex shader to the program.
65 | GLES20.glAttachShader(programHandle, vertexShaderHandle);
66 |
67 | // Bind the fragment shader to the program.
68 | GLES20.glAttachShader(programHandle, fragmentShaderHandle);
69 |
70 | // Bind attributes
71 | if (attributes != null)
72 | {
73 | final int size = attributes.length;
74 | for (int i = 0; i < size; i++)
75 | {
76 | GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
77 | }
78 | }
79 |
80 | // Link the two shaders together into a program.
81 | GLES20.glLinkProgram(programHandle);
82 |
83 | // Get the link status.
84 | final int[] linkStatus = new int[1];
85 | GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
86 |
87 | // If the link failed, delete the program.
88 | if (linkStatus[0] == 0)
89 | {
90 | Log.e(TAG, "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle));
91 | GLES20.glDeleteProgram(programHandle);
92 | programHandle = 0;
93 | }
94 | }
95 |
96 | if (programHandle == 0)
97 | {
98 | throw new RuntimeException("Error creating program.");
99 | }
100 |
101 | return programHandle;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/com/research/gltest/TextureHelper.java:
--------------------------------------------------------------------------------
1 | package com.research.gltest;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.opengl.GLES20;
7 | import android.opengl.GLUtils;
8 |
9 | public class TextureHelper
10 | {
11 | public static int loadTexture(final Context context, final int resourceId)
12 | {
13 | final int[] textureHandle = new int[1];
14 |
15 | GLES20.glGenTextures(1, textureHandle, 0);
16 |
17 | if (textureHandle[0] != 0)
18 | {
19 | final BitmapFactory.Options options = new BitmapFactory.Options();
20 | options.inScaled = false; // No pre-scaling
21 |
22 | // Read in the resource
23 | final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
24 |
25 | // Bind to the texture in OpenGL
26 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
27 |
28 | // Set filtering
29 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
30 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
31 |
32 | // Load the bitmap into the bound texture.
33 | GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
34 |
35 | // Recycle the bitmap, since its data has been loaded into OpenGL.
36 | bitmap.recycle();
37 | }
38 |
39 | if (textureHandle[0] == 0)
40 | {
41 | throw new RuntimeException("Error loading texture.");
42 | }
43 |
44 | return textureHandle[0];
45 | }
46 | }
47 |
--------------------------------------------------------------------------------