|
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include "tdirectgdieglcontent_cube.h" |
|
17 #include "tdisplaymode_mapping.h" |
|
18 #include <fbs.h> |
|
19 #include <graphics/sgimage_sw.h> |
|
20 #include <graphics/fbsdefs.h> |
|
21 |
|
22 // CONSTANTS |
|
23 /** Camera parameters */ |
|
24 const TInt KCameraDistance = 100; |
|
25 const TReal32 KFrustumLeft = -1.f; //left vertical clipping plane |
|
26 const TReal32 KFrustumRight = 1.f; //right vertical clipping plane |
|
27 const TReal32 KFrustumBottom = -1.f;//bottom horizontal clipping plane |
|
28 const TReal32 KFrustumTop = 1.f; //top horizontal clipping plane |
|
29 const TReal32 KFrustumNear = 3.f; //near depth clipping plane |
|
30 const TReal32 KFrustumFar = 1000.f; //far depth clipping plane |
|
31 |
|
32 /* Define vertice coordinates for the cube |
|
33 Duplication of vertices needed for texturing every surface of the cube */ |
|
34 static const GLbyte KVertices[24 * 3] = |
|
35 { |
|
36 /* top */ |
|
37 -1, 1, 1, |
|
38 1, 1, 1, |
|
39 1, -1, 1, |
|
40 -1, -1, 1, |
|
41 |
|
42 /* front */ |
|
43 1, 1, 1, |
|
44 1, 1, -1, |
|
45 1, -1, -1, |
|
46 1, -1, 1, |
|
47 |
|
48 /* right */ |
|
49 -1, 1, 1, |
|
50 -1, 1, -1, |
|
51 1, 1, -1, |
|
52 1, 1, 1, |
|
53 |
|
54 /* left */ |
|
55 1, -1, 1, |
|
56 1, -1, -1, |
|
57 -1, -1, -1, |
|
58 -1, -1, 1, |
|
59 |
|
60 /* back */ |
|
61 -1, -1, 1, |
|
62 -1, -1, -1, |
|
63 -1, 1, -1, |
|
64 -1, 1, 1, |
|
65 |
|
66 /* bottom */ |
|
67 -1, 1, -1, |
|
68 1, 1, -1, |
|
69 1, -1, -1, |
|
70 -1, -1, -1 |
|
71 }; |
|
72 |
|
73 /** |
|
74 Indices for drawing the triangles. |
|
75 The color of the triangle is determined by |
|
76 the color of the last vertex of the triangle. |
|
77 */ |
|
78 static const GLubyte KTriangles[12 * 3] = |
|
79 { |
|
80 /* top */ |
|
81 1,0,3, |
|
82 1,3,2, |
|
83 |
|
84 /* front */ |
|
85 5,4,7, |
|
86 5,7,6, |
|
87 |
|
88 /* right */ |
|
89 9,8,11, |
|
90 9,11,10, |
|
91 |
|
92 /* left */ |
|
93 13,12,15, |
|
94 13,15,14, |
|
95 |
|
96 /* back */ |
|
97 17,16,19, |
|
98 17,19,18, |
|
99 |
|
100 /* bottom */ |
|
101 21,22,23, |
|
102 21,23,20 |
|
103 }; |
|
104 |
|
105 /* Macro for changing the input texture coordinate values from |
|
106 GLubyte [0,255] to GLbyte [-128,127]. See more info below. */ |
|
107 #define tex(u,v) (GLbyte)( (u) - 128 ) , (GLbyte)( (v) - 128 ) |
|
108 |
|
109 /* Input texture coordinates for each of the object vertices. |
|
110 The coordinates are given in GLbyte [-128,127] format. |
|
111 Since the texture picture coordinates are between values |
|
112 [0,255] for both width and height, we have defined a macro |
|
113 to change the input coordinates into a appropriate form. |
|
114 It is easier to think the texture coordinates as corresponding |
|
115 image pixel coordinates. This alone is not enough because |
|
116 if texture coordinates are not given between values [0,1], |
|
117 texture wrapping will occur. Therefore we need to |
|
118 scale the texture coordinates with appropriate texture matrix, |
|
119 which is defined in AppInit(). */ |
|
120 static const GLbyte KTexCoords[24 * 2] = |
|
121 { |
|
122 /* top */ |
|
123 tex(0,0), |
|
124 tex(255,0), |
|
125 tex(255,255), |
|
126 tex(0,255), |
|
127 |
|
128 /* front */ |
|
129 tex(0,255), |
|
130 tex(127,255), |
|
131 tex(127,127), |
|
132 tex(0,127), |
|
133 |
|
134 /* right */ |
|
135 tex(127,255), |
|
136 tex(255,255), |
|
137 tex(255,127), |
|
138 tex(127,127), |
|
139 |
|
140 /* left */ |
|
141 tex(0,127), |
|
142 tex(127,127), |
|
143 tex(127,0), |
|
144 tex(0,0), |
|
145 |
|
146 /* back */ |
|
147 tex(127,127), |
|
148 tex(255,127), |
|
149 tex(255,0), |
|
150 tex(127,0), |
|
151 |
|
152 /* bottom */ |
|
153 tex(255,255), |
|
154 tex(255,0), |
|
155 tex(0,0), |
|
156 tex(0,255) |
|
157 }; |
|
158 |
|
159 /** |
|
160 Static constructor. |
|
161 @param aPixelFormat Pixel format of pixmap buffer. |
|
162 @param aSize Size of pixmap buffer. |
|
163 */ |
|
164 CGLCube* CGLCube::NewL(TUidPixelFormat aPixelFormat, const TSize& aSize) |
|
165 { |
|
166 CGLCube* self = NewLC(aPixelFormat, aSize); |
|
167 CleanupStack::Pop(self); |
|
168 return self; |
|
169 } |
|
170 |
|
171 CGLCube* CGLCube::NewLC(TUidPixelFormat aPixelFormat, const TSize& aSize) |
|
172 { |
|
173 CGLCube* self = new(ELeave) CGLCube(); |
|
174 CleanupStack::PushL(self); |
|
175 self->ConstructL(aPixelFormat, aSize); |
|
176 return self; |
|
177 } |
|
178 |
|
179 /** |
|
180 1st phase constructor |
|
181 */ |
|
182 CGLCube::CGLCube() |
|
183 { |
|
184 } |
|
185 |
|
186 /** |
|
187 2nd phase constructor |
|
188 @param aPixelFormat Pixel format of pixmap buffer. |
|
189 @param aSize Size of pixmap buffer. |
|
190 */ |
|
191 void CGLCube::ConstructL(TUidPixelFormat aPixelFormat, const TSize& aSize) |
|
192 { |
|
193 // init graphic environment |
|
194 User::LeaveIfError(SgDriver::Open()); |
|
195 FbsStartup(); |
|
196 User::LeaveIfError(RFbsSession::Connect()); |
|
197 InitEglL(aPixelFormat, aSize); |
|
198 } |
|
199 |
|
200 /** |
|
201 Destructor |
|
202 */ |
|
203 CGLCube::~CGLCube() |
|
204 { |
|
205 // deinit gfx environment |
|
206 DeInitEgl(); |
|
207 SgDriver::Close(); |
|
208 RFbsSession::Disconnect(); |
|
209 } |
|
210 |
|
211 /** |
|
212 Egl environment initialisation for pixmap surface rendering. |
|
213 @param aPixelFormat Pixel format of pixmap buffer. |
|
214 @param aSize Size of pixmap buffer. |
|
215 */ |
|
216 void CGLCube::InitEglL(TUidPixelFormat aPixelFormat, const TSize& aSize) |
|
217 { |
|
218 // Get the display for drawing graphics |
|
219 iEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
|
220 if(iEglDisplay == NULL) |
|
221 { |
|
222 _LIT(KGetDisplayFailed, "eglGetDisplay failed"); |
|
223 User::Panic(KGetDisplayFailed, 0); |
|
224 } |
|
225 |
|
226 // Initialize display |
|
227 if(eglInitialize(iEglDisplay, NULL, NULL) == EGL_FALSE) |
|
228 { |
|
229 _LIT(KInitializeFailed, "eglInitialize failed"); |
|
230 User::Panic(KInitializeFailed, 0); |
|
231 } |
|
232 |
|
233 // switch api to GLES |
|
234 eglBindAPI(EGL_OPENGL_ES_API); |
|
235 |
|
236 iImageInfo.iSizeInPixels = aSize; |
|
237 iImageInfo.iPixelFormat = aPixelFormat; |
|
238 iImageInfo.iCpuAccess = ESgCpuAccessNone; |
|
239 iImageInfo.iUsage = ESgUsageOpenGlesTarget|ESgUsageDirectGdiSource; |
|
240 iImageInfo.iShareable = ETrue; |
|
241 iImageInfo.iScreenId = KSgScreenIdMain; |
|
242 |
|
243 for(TInt i=0; i<KEglContentBuffers; i++) |
|
244 { |
|
245 User::LeaveIfError(iImages[i].Create(iImageInfo, NULL, 0)); |
|
246 |
|
247 EGLint numOfConfigs = 0; |
|
248 |
|
249 // Define properties for the wanted EGLSurface |
|
250 const EGLint attribList[] = |
|
251 { |
|
252 EGL_MATCH_NATIVE_PIXMAP, (EGLint)&iImages[i], |
|
253 EGL_SURFACE_TYPE, EGL_PIXMAP_BIT, |
|
254 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, |
|
255 EGL_NONE |
|
256 }; |
|
257 |
|
258 // Choose an EGLConfig that best matches to the properties in attribList |
|
259 if(eglChooseConfig(iEglDisplay, attribList, &iConfig, 1, &numOfConfigs) == EGL_FALSE) |
|
260 { |
|
261 _LIT(KChooseConfigFailed, "eglChooseConfig failed"); |
|
262 User::Panic(KChooseConfigFailed, 0); |
|
263 } |
|
264 |
|
265 const EGLint ppixmapAttribs[] = { EGL_NONE }; |
|
266 iEglSurfaces[i] = eglCreatePixmapSurface(iEglDisplay, iConfig, &iImages[i], ppixmapAttribs); |
|
267 if(iEglSurfaces[i] == NULL) |
|
268 { |
|
269 _LIT(KCreatePixmapSurfaceFailed, "eglCreatePixmapSurface failed"); |
|
270 User::Panic(KCreatePixmapSurfaceFailed, 0); |
|
271 } |
|
272 } |
|
273 iEglContext = eglCreateContext(iEglDisplay, iConfig, EGL_NO_CONTEXT, NULL); |
|
274 if(iEglContext == NULL) |
|
275 { |
|
276 _LIT(KCreateContextFailed, "eglCreateContext failed"); |
|
277 User::Panic(KCreateContextFailed, 0); |
|
278 } |
|
279 |
|
280 if(eglMakeCurrent(iEglDisplay, iEglSurfaces[iCurrentImage], iEglSurfaces[iCurrentImage], iEglContext) == EGL_FALSE) |
|
281 { |
|
282 _LIT(KMakeCurrentFailed, "eglMakeCurrent failed"); |
|
283 User::Panic(KMakeCurrentFailed, 0); |
|
284 } |
|
285 |
|
286 // Prepare texture map (shaded chessboard) |
|
287 GLubyte* texData = new(ELeave) GLubyte[64*64*4]; |
|
288 for(TInt i=0; i<64; i++) |
|
289 { |
|
290 for(TInt j=0; j<64; j++) |
|
291 { |
|
292 if((i&8)^(j&8)) // switch 'white' and 'black' fields |
|
293 { |
|
294 texData[i*64*4+j*4+0] = i*4; // r |
|
295 texData[i*64*4+j*4+1] = j*4; // g |
|
296 texData[i*64*4+j*4+2] = (i+j)*2; // b |
|
297 } |
|
298 else |
|
299 { |
|
300 texData[i*64*4+j*4+0] = 255-i*4; // r |
|
301 texData[i*64*4+j*4+1] = 255-j*4; // g |
|
302 texData[i*64*4+j*4+2] = 255-(i+j)*2; // b |
|
303 } |
|
304 texData[i*64*4+j*4+3] = 255; // alpha |
|
305 } |
|
306 } |
|
307 |
|
308 // Generate texture |
|
309 glEnable(GL_TEXTURE_2D); |
|
310 glGenTextures(1, &iTexId); |
|
311 glBindTexture(GL_TEXTURE_2D, iTexId); |
|
312 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
313 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
314 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData); |
|
315 delete [] texData; |
|
316 } |
|
317 |
|
318 /** |
|
319 Egl environment destroying. |
|
320 */ |
|
321 void CGLCube::DeInitEgl() |
|
322 { |
|
323 glDeleteTextures(1, &iTexId); |
|
324 eglMakeCurrent(iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
|
325 eglDestroyContext(iEglDisplay, iEglContext); |
|
326 for(TInt i=0; i<KEglContentBuffers; i++) |
|
327 { |
|
328 eglDestroySurface(iEglDisplay, iEglSurfaces[i]); |
|
329 iImages[i].Close(); |
|
330 } |
|
331 eglTerminate(iEglDisplay); |
|
332 eglReleaseThread(); |
|
333 } |
|
334 |
|
335 /** |
|
336 Render frame of spinning cube. |
|
337 @param aFrame Number of frame to render. |
|
338 */ |
|
339 void CGLCube::Render(TInt aFrame) |
|
340 { |
|
341 if(eglMakeCurrent(iEglDisplay, iEglSurfaces[iCurrentImage], iEglSurfaces[iCurrentImage], iEglContext) == EGL_FALSE) |
|
342 { |
|
343 _LIT(KMakeCurrentFailed, "eglMakeCurrent failed"); |
|
344 User::Panic(KMakeCurrentFailed, 0); |
|
345 } |
|
346 |
|
347 // Set the screen background color. |
|
348 glClearColor(0.f, 0.f, 0.f, 1.f); |
|
349 |
|
350 // Enable back face culling, texturing, and normalization. |
|
351 glEnable(GL_CULL_FACE); |
|
352 glEnable(GL_TEXTURE_2D); |
|
353 glEnable(GL_NORMALIZE); |
|
354 |
|
355 // Initialize viewport and projection. |
|
356 glViewport(0, 0, iImageInfo.iSizeInPixels.iWidth, iImageInfo.iSizeInPixels.iHeight); |
|
357 |
|
358 // Calculate the view frustrum |
|
359 GLfloat aspectRatio = (GLfloat)(iImageInfo.iSizeInPixels.iWidth) / (GLfloat)(iImageInfo.iSizeInPixels.iHeight); |
|
360 glMatrixMode(GL_PROJECTION); |
|
361 glLoadIdentity(); |
|
362 glFrustumf(KFrustumLeft * aspectRatio, KFrustumRight * aspectRatio, |
|
363 KFrustumBottom, KFrustumTop, |
|
364 KFrustumNear, KFrustumFar); |
|
365 |
|
366 /* Initialize appropriate texture matrix. First we have to translate the |
|
367 input texture coordinate values to be within a range of [0,255]. Hence |
|
368 we translate the x- and y-coordinate values by 128. Recall that the |
|
369 values in nokTexCoords are between [-128,127], now they are in a range |
|
370 of [0,255]. After that we scale the values by 1/255 to make the values |
|
371 to be in range [0,1]. */ |
|
372 glMatrixMode(GL_TEXTURE); |
|
373 glLoadIdentity(); |
|
374 glScalef(1.0f/255.0f, 1.0f/255.0f, 1.0f); |
|
375 glTranslatef(128.0f, 128.0f, 0.0f); |
|
376 |
|
377 // Remember to change the matrix mode to modelview. |
|
378 glMatrixMode(GL_MODELVIEW); |
|
379 |
|
380 // Enable vertex and texture arrays. |
|
381 glEnableClientState(GL_VERTEX_ARRAY); |
|
382 glEnableClientState(GL_TEXTURE_COORD_ARRAY); |
|
383 |
|
384 // Set array pointers. |
|
385 glVertexPointer(3, GL_BYTE, 0, KVertices); |
|
386 glTexCoordPointer(2, GL_BYTE, 0, KTexCoords); |
|
387 |
|
388 // Set the initial shading mode |
|
389 glShadeModel(GL_FLAT); |
|
390 |
|
391 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE); |
|
392 |
|
393 glClear(GL_COLOR_BUFFER_BIT); |
|
394 |
|
395 // Animate and draw box |
|
396 glLoadIdentity(); |
|
397 glTranslatex(0 , 0 , -KCameraDistance << 16); |
|
398 glRotatex(aFrame << 18, 1 << 16, 0 , 0 ); |
|
399 glRotatex(aFrame << 17, 0 , 1 << 16, 0 ); |
|
400 glRotatex(aFrame << 16, 0 , 0 , 1 << 16); |
|
401 glScalex(20 << 16, 20 << 16, 20 << 16); |
|
402 |
|
403 glBindTexture(GL_TEXTURE_2D, iTexId); |
|
404 glDrawElements(GL_TRIANGLES, 12 * 3, GL_UNSIGNED_BYTE, KTriangles); |
|
405 |
|
406 iLastImage = iCurrentImage; |
|
407 } |
|
408 |
|
409 /** |
|
410 Get image id of current frame. Current image to render is switch to next. |
|
411 @param aId Reference to drawable id class to store image id. |
|
412 */ |
|
413 void CGLCube::GetImage(TSgDrawableId& aId) |
|
414 { |
|
415 // finish rendering |
|
416 glFinish(); |
|
417 |
|
418 aId = iImages[iLastImage].Id(); |
|
419 // switch to next buffer to prevent overdraw of image by asynchronous rendering |
|
420 if(iLastImage == iCurrentImage) |
|
421 { |
|
422 iCurrentImage = (iCurrentImage+1)%KEglContentBuffers; |
|
423 } |
|
424 } |