Update contrib.
2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
14 * Description: Background implementation
22 * \brief Background implementation
25 #ifndef M3G_CORE_INCLUDE
26 # error included by m3g_core.c; do not compile separately.
29 #include "m3g_background.h"
30 #include "m3g_image.h"
31 #include "m3g_memory.h"
32 #include "m3g_animationtrack.h"
33 #include "m3g_rendercontext.h"
35 /*----------------------------------------------------------------------
37 *--------------------------------------------------------------------*/
41 * \brief Destroys this Background object.
43 * \param obj Background object
45 static void m3gDestroyBackground(Object *obj)
47 Background *background = (Background *) obj;
48 M3G_VALIDATE_OBJECT(background);
50 M3G_ASSIGN_REF(background->image, NULL);
51 m3gDestroyObject(obj);
56 * \brief Applies background color and image
57 * using a textured quad.
59 * \param ctx render context
60 * \param background Background object
62 static void m3gApplyBackground(RenderContext *ctx, Background *background)
64 GLbitfield glBits = 0;
67 if (background->depthClearEnable) {
68 glBits |= GL_DEPTH_BUFFER_BIT;
71 /* Skip color buffer clearing if the background image
72 * fills the whole viewport. This is guaranteed to happen
73 * if the crop rectangle is non-zero and both X and Y
74 * wrapping modes are REPEAT. */
76 if (background->colorClearEnable) {
77 if (background->image == NULL ||
78 background->crop.width == 0 ||
79 background->crop.height == 0 ||
80 background->modeX == M3G_BORDER ||
81 background->modeY == M3G_BORDER)
83 glBits |= GL_COLOR_BUFFER_BIT;
84 m3gGLColor(background->color, temp);
85 glClearColorx(temp[0], temp[1], temp[2], temp[3]);
89 /* Clear color and/or depth buffer (or neither) */
92 /* Apply background image using a quad that
95 if (background->colorClearEnable &&
96 background->image != NULL &&
97 background->crop.width != 0 &&
98 background->crop.height != 0)
101 /* Texture coordinates */
102 M3Gshort texvert[4 * 2];
103 /* Quad that fills the viewport */
104 M3Gint vert[4 * 3] = { -65536, 65536, 0,
108 Rect rImage, rIntersection;
112 /* Get power of two image */
113 imagePow2 = m3gGetPowerOfTwoImage(background->image);
114 /* If NULL -> out of memory */
121 rImage.width = m3gGetWidth(background->image);
122 rImage.height = m3gGetHeight(background->image);
124 /* Intersection of source image and crop rectangle */
125 intersects = m3gIntersectRectangle(&rIntersection, &rImage, &background->crop);
127 /* Setup X vertices and texture S coordinates */
128 if (background->modeX == M3G_BORDER) {
129 /* If both modes are border and no intersection ->
131 if (background->modeY == M3G_BORDER && !intersects) {
135 texvert[0 * 2 + 0] = (M3Gshort) rIntersection.x;
136 texvert[1 * 2 + 0] = (M3Gshort) rIntersection.x;
137 texvert[2 * 2 + 0] = (M3Gshort) (rIntersection.x + rIntersection.width);
138 texvert[3 * 2 + 0] = (M3Gshort) (rIntersection.x + rIntersection.width);
140 vert[0 * 3 + 0] = -65536 + 2 * 65536 * (rIntersection.x - background->crop.x) / background->crop.width;
141 vert[1 * 3 + 0] = vert[0 * 3 + 0];
142 vert[2 * 3 + 0] = vert[0 * 3 + 0] + 2 * 65536 * rIntersection.width / background->crop.width;
143 vert[3 * 3 + 0] = vert[2 * 3 + 0];
146 /* In repeat mode texture coordinates are directly crop rectangle coordinates */
147 texvert[0 * 2 + 0] = (M3Gshort) background->crop.x;
148 texvert[1 * 2 + 0] = (M3Gshort) background->crop.x;
149 texvert[2 * 2 + 0] = (M3Gshort) (background->crop.x + background->crop.width);
150 texvert[3 * 2 + 0] = (M3Gshort) (background->crop.x + background->crop.width);
153 /* Setup Y vertices and texture T coordinates */
154 if (background->modeY == M3G_BORDER) {
155 texvert[0 * 2 + 1] = (M3Gshort) rIntersection.y;
156 texvert[1 * 2 + 1] = (M3Gshort) (rIntersection.y + rIntersection.height);
157 texvert[2 * 2 + 1] = (M3Gshort) rIntersection.y;
158 texvert[3 * 2 + 1] = (M3Gshort) (rIntersection.y + rIntersection.height);
161 vert[0 * 3 + 1] = 65536 - 2 * 65536 * (rIntersection.y - background->crop.y) / background->crop.height;
162 vert[1 * 3 + 1] = vert[0 * 3 + 1] - 2 * 65536 * rIntersection.height / background->crop.height;
163 vert[2 * 3 + 1] = vert[0 * 3 + 1];
164 vert[3 * 3 + 1] = vert[1 * 3 + 1];
167 /* In repeat mode texture coordinates are directly crop rectangle coordinates */
168 texvert[0 * 2 + 1] = (M3Gshort) background->crop.y;
169 texvert[1 * 2 + 1] = (M3Gshort) (background->crop.y + background->crop.height);
170 texvert[2 * 2 + 1] = (M3Gshort) background->crop.y;
171 texvert[3 * 2 + 1] = (M3Gshort) (background->crop.y + background->crop.height);
174 /* Disable unwanted state and depth writes */
175 m3gApplyAppearance(NULL, ctx, 0);
176 glDepthMask(GL_FALSE);
178 /* Disable color array, normals and textures*/
179 glDisableClientState(GL_COLOR_ARRAY);
180 glDisableClientState(GL_NORMAL_ARRAY);
182 /* Background image to texture unit 0 */
183 glClientActiveTexture(GL_TEXTURE0);
184 glActiveTexture(GL_TEXTURE0);
185 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
186 glTexCoordPointer(2, GL_SHORT, 0, texvert);
187 glEnable(GL_TEXTURE_2D);
188 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, (GLfixed) GL_REPLACE);
189 m3gBindTextureImage(imagePow2,
190 M3G_FILTER_BASE_LEVEL,
191 m3gIsAccelerated(ctx) ? M3G_FILTER_LINEAR : M3G_FILTER_NEAREST);
194 if (background->modeX == M3G_REPEAT) {
195 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
198 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
201 if (background->modeY == M3G_REPEAT) {
202 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
205 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
208 /* Texture matrix scale */
209 glMatrixMode(GL_TEXTURE);
211 glScalef( m3gRcp((M3Gfloat)m3gGetWidth(background->image)),
212 m3gRcp((M3Gfloat)m3gGetHeight(background->image)),
214 glMatrixMode(GL_MODELVIEW);
217 glEnableClientState(GL_VERTEX_ARRAY);
218 glVertexPointer(3, GL_FIXED, 0, vert);
220 /* Set up an identity modelview and projection */
221 m3gPushScreenSpace(ctx, M3G_FALSE);
223 /* Load indices -> draws the background */
224 M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_NGL_DRAW);
225 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
226 M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_NGL_DRAW);
229 m3gReleaseTextureImage(imagePow2);
236 * \brief Overloaded Object3D method.
238 * \param property animation property
239 * \retval M3G_TRUE property supported
240 * \retval M3G_FALSE property not supported
242 static M3Gbool m3gBackgroundIsCompatible(M3Gint property)
250 return m3gObjectIsCompatible(property);
256 * \brief Overloaded Object3D method.
258 * \param self Background object
259 * \param property animation property
260 * \param valueSize size of value array
261 * \param value value array
263 static void m3gBackgroundUpdateProperty(Object *self,
266 const M3Gfloat *value)
268 Background *background = (Background *)self;
269 M3G_VALIDATE_OBJECT(background);
270 M3G_ASSERT_PTR(value);
274 M3G_ASSERT(valueSize >= 1);
275 background->color = m3gAlpha1f(value[0])
276 & (background->color | M3G_ALPHA_MASK);
279 M3G_ASSERT(valueSize >= 3);
280 background->color = m3gColor3f(value[0], value[1], value[2])
281 & (background->color | M3G_RGB_MASK);
284 M3G_ASSERT(valueSize >= 2);
285 background->crop.x = m3gRoundToInt(value[0]);
286 background->crop.y = m3gRoundToInt(value[1]);
288 M3G_ASSERT(valueSize >= 4);
289 background->crop.width =
290 (value[2] < 0) ? 0 : m3gRoundToInt(value[2]);
291 background->crop.height =
292 (value[3] < 0) ? 0 : m3gRoundToInt(value[3]);
296 m3gObjectUpdateProperty(self, property, valueSize, value);
302 * \brief Overloaded Object3D method.
304 * \param self Background object
305 * \param references array of reference objects
306 * \return number of references
308 static M3Gint m3gBackgroundDoGetReferences(Object *self, Object **references)
310 Background *bg = (Background *)self;
311 M3Gint num = m3gObjectDoGetReferences(self, references);
312 if (bg->image != NULL) {
313 if (references != NULL)
314 references[num] = (Object *)bg->image;
322 * \brief Overloaded Object3D method.
324 static Object *m3gBackgroundFindID(Object *self, M3Gint userID)
326 Background *bg = (Background *)self;
327 Object *found = m3gObjectFindID(self, userID);
329 if (!found && bg->image) {
330 found = m3gFindID((Object*) bg->image, userID);
337 * \brief Overloaded Object3D method.
339 * \param originalObj original Background object
340 * \param cloneObj pointer to cloned Background object
341 * \param pairs array for all object-duplicate pairs
342 * \param numPairs number of pairs
344 static M3Gbool m3gBackgroundDuplicate(const Object *originalObj,
349 Background *original = (Background *)originalObj;
350 Background *clone = (Background *)m3gCreateBackground(originalObj->interface);
351 *cloneObj = (Object *)clone;
352 if (*cloneObj == NULL) {
356 if (m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
357 clone->color = original->color;
358 clone->modeX = original->modeX;
359 clone->modeY = original->modeY;
360 clone->crop = original->crop;
361 clone->colorClearEnable = original->colorClearEnable;
362 clone->depthClearEnable = original->depthClearEnable;
363 M3G_ASSIGN_REF(clone->image, original->image);
373 * \brief Initializes a Background object. See specification
374 * for default values.
376 * \param m3g M3G interface
377 * \param background Background object
379 static void m3gInitBackground(Interface *m3g, Background *background)
381 /* Background is derived from Object */
382 m3gInitObject(&background->object, m3g, M3G_CLASS_BACKGROUND);
384 background->modeX = M3G_BORDER;
385 background->modeY = M3G_BORDER;
386 background->colorClearEnable = M3G_TRUE;
387 background->depthClearEnable = M3G_TRUE;
390 /*----------------------------------------------------------------------
391 * Virtual function table
392 *--------------------------------------------------------------------*/
394 static const ObjectVFTable m3gvf_Background = {
395 m3gObjectApplyAnimation,
396 m3gBackgroundIsCompatible,
397 m3gBackgroundUpdateProperty,
398 m3gBackgroundDoGetReferences,
400 m3gBackgroundDuplicate,
405 /*----------------------------------------------------------------------
406 * Public API functions
407 *--------------------------------------------------------------------*/
410 * \brief Creates a Background object.
412 * \param interface M3G interface
413 * \retval Background new Background object
414 * \retval NULL Background creating failed
417 /*@access M3GInterface@*/
418 /*@access M3Gobject@*/
419 M3G_API M3GBackground m3gCreateBackground(M3GInterface interface)
421 Interface *m3g = (Interface *) interface;
422 M3G_VALIDATE_INTERFACE(m3g);
425 Background *background = m3gAllocZ(m3g, sizeof(Background));
427 if (background != NULL) {
428 m3gInitBackground(m3g, background);
431 return (M3GBackground) background;
436 * \brief Sets background color.
438 * \param handle Background object
439 * \param ARGB background color as ARGB
442 /*@access M3Gobject@*/
443 M3G_API void m3gSetBgColor(M3GBackground handle, M3Guint ARGB)
445 Background *background = (Background *) handle;
446 M3G_VALIDATE_OBJECT(background);
448 background->color = ARGB;
452 * \brief Sets background image x and y mode.
454 * \param handle Background object
455 * \param modeX Image X mode
456 * \param modeY Image Y mode
459 /*@access M3Gobject@*/
460 M3G_API void m3gSetBgMode(M3GBackground handle, M3Gint modeX, M3Gint modeY)
462 Background *background = (Background *) handle;
463 M3G_VALIDATE_OBJECT(background);
465 /* Check for errors */
466 if (modeX < M3G_BORDER || modeX > M3G_REPEAT ||
467 modeY < M3G_BORDER || modeY > M3G_REPEAT) {
468 m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
472 background->modeX = modeX;
473 background->modeY = modeY;
477 * \brief Sets background image crop rectangle.
479 * \param handle Background object
480 * \param cropX crop upper left x
481 * \param cropY crop upper left y
482 * \param width crop width
483 * \param height crop height
486 /*@access M3Gobject@*/
487 M3G_API void m3gSetBgCrop(M3GBackground handle,
488 M3Gint cropX, M3Gint cropY,
489 M3Gint width, M3Gint height)
491 Background *background = (Background *) handle;
492 M3G_VALIDATE_OBJECT(background);
494 /* Check for errors */
495 if (width < 0 || height < 0) {
496 m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
500 background->crop.x = cropX;
501 background->crop.y = cropY;
502 background->crop.width = width;
503 background->crop.height = height;
507 * \brief Sets background image.
509 * \param handle Background object
510 * \param hImage Image2D object or NULL
513 /*@access M3Gobject@*/
514 M3G_API void m3gSetBgImage(M3GBackground handle, M3GImage hImage)
516 Background *background = (Background *) handle;
517 Image *image = (Image *)hImage;
518 M3G_VALIDATE_OBJECT(background);
521 /* Check allowed formats */
522 if (m3gGetFormat(image) != M3G_RGB &&
523 m3gGetFormat(image) != M3G_RGBA) {
524 m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
528 background->crop.x = 0;
529 background->crop.y = 0;
530 background->crop.width = m3gGetWidth(image);
531 background->crop.height = m3gGetHeight(image);
534 M3G_ASSIGN_REF(background->image, image);
538 * \brief Gets background image.
540 * \param handle Background object
541 * \return Image2D object or NULL
544 /*@access M3GObject@*/
545 M3G_API M3GImage m3gGetBgImage(M3GBackground handle)
547 Background *bg = (Background *) handle;
548 M3G_VALIDATE_OBJECT(bg);
550 return (M3GImage) bg->image;
554 * \brief Gets background color as ARGB.
556 * \param handle Background object
560 /*@access M3Gobject@*/
561 M3G_API M3Guint m3gGetBgColor(M3GBackground handle)
563 Background *background = (Background *) handle;
564 M3G_VALIDATE_OBJECT(background);
566 return background->color;
570 * \brief Gets background image x or y mode.
572 * \param handle Background object
573 * \param which which mode to return
576 * \return image x or y mode
579 /*@access M3Gobject@*/
580 M3G_API M3Gint m3gGetBgMode(M3GBackground handle, M3Gint which)
582 Background *background = (Background *) handle;
583 M3G_VALIDATE_OBJECT(background);
587 return background->modeX;
590 return background->modeY;
595 * \brief Gets background image crop parameter.
597 * \param handle Background object
598 * \param which which crop parameter to return
601 * \arg M3G_GET_CROPWIDTH
602 * \arg M3G_GET_CROPHEIGHT
603 * \return image crop parameter
606 /*@access M3Gobject@*/
607 M3G_API M3Gint m3gGetBgCrop(M3GBackground handle, M3Gint which)
609 Background *background = (Background *) handle;
610 M3G_VALIDATE_OBJECT(background);
614 return background->crop.x;
616 return background->crop.y;
617 case M3G_GET_CROPWIDTH:
618 return background->crop.width;
619 case M3G_GET_CROPHEIGHT:
621 return background->crop.height;
626 * \brief Sets background color or depth clear enable.
628 * \param handle Background object
629 * \param which which clear to enable
630 * \arg M3G_SETGET_COLORCLEAR
631 * \arg M3G_SETGET_DEPTHCLEAR
632 * \param enable clear enable/disable
635 /*@access M3Gobject@*/
636 M3G_API void m3gSetBgEnable(M3GBackground handle, M3Gint which, M3Gbool enable)
638 Background *background = (Background *) handle;
639 M3G_VALIDATE_OBJECT(background);
642 case M3G_SETGET_COLORCLEAR:
643 background->colorClearEnable = enable;
645 case M3G_SETGET_DEPTHCLEAR:
647 background->depthClearEnable = enable;
653 * \brief Gets background color or depth clear enable.
655 * \param handle Background object
656 * \param which which clear to return
657 * \arg M3G_SETGET_COLORCLEAR
658 * \arg M3G_SETGET_DEPTHCLEAR
659 * \return clear enabled
662 /*@access M3Gobject@*/
663 M3G_API M3Gbool m3gIsBgEnabled(M3GBackground handle, M3Gint which)
665 Background *background = (Background *) handle;
666 M3G_VALIDATE_OBJECT(background);
669 case M3G_SETGET_COLORCLEAR:
670 return background->colorClearEnable;
671 case M3G_SETGET_DEPTHCLEAR:
673 return background->depthClearEnable;