First public contribution.
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: Appearance implementation
22 * \brief Appearance implementation
25 #ifndef M3G_CORE_INCLUDE
26 # error included by m3g_core.c; do not compile separately.
29 #include "m3g_appearance.h"
30 #include "m3g_vertexbuffer.h"
32 /*----------------------------------------------------------------------
34 *--------------------------------------------------------------------*/
38 * \brief Applies default appearance values to OpenGL.
40 static void m3gApplyAppearanceDefaults(RenderContext *ctx)
43 m3gApplyCompositingMode(NULL, ctx);
44 m3gApplyPolygonMode(NULL);
45 m3gApplyMaterial(NULL, 0x10000);
48 for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
49 glActiveTexture(GL_TEXTURE0 + i);
50 glDisable(GL_TEXTURE_2D);
56 * \brief Generate a hash number for a pointer
58 static M3Guint m3gGenPointerHash(const void *ptr)
60 M3Guint p = ((M3Guint) ptr) >> 2;
61 M3Guint key = p ^ (p >> 5) ^ (p >> 10) ^ (p >> 15) ^ (p >> 20) ^ (p >> 25);
67 * \brief Generate a quick hash bit pattern for the textures of this
70 static M3Guint m3gGen12BitTextureHash(const Appearance *app)
76 for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
77 const Texture *tex = app->texture[i];
79 key ^= (m3gGenPointerHash(m3gGetTextureImage((M3GTexture)tex)) >> i) << 6;
80 key ^= (m3gGenPointerHash(tex) >> i) & 0x3Fu;
83 return key & ((1u<<12)-1);
88 * \brief Generate the sorting key for render queue
90 * Sort key is a combination of user settable layer and
91 * blending mode. Blended objects are always drawn last.
93 * \param appearance Appearance object
96 static void m3gRegenerateSortKey(Appearance *appearance)
99 M3G_VALIDATE_OBJECT(appearance);
101 /*------------------------------------------------------------
102 * First do the mandatory sorting by layer index and blending
103 * state; this currently uses the top eight bits, 31..24
104 *-----------------------------------------------------------*/
106 key = (appearance->layer - M3G_APPEARANCE_MIN_LAYER)
107 << (33 - M3G_APPEARANCE_HARD_SORT_BITS);
109 /* NOTE the blending state bit is not set here, but dynamically in
110 * m3gGetAppearanceSortKey; this way we do not need to implement
111 * signaling from CompositingMode to Appearance when the blending
114 /*-----------------------------------------------------------------
115 * The rest of the bits, 23..0, affect performance only; ideally,
116 * these should be sorted so that the more expensive state is in the
117 * higher bits, but this is largely dependent on the hardware
118 *----------------------------------------------------------------*/
120 /* Texturing changes are often expensive in graphics hardware, so
121 * we put a hash of the texture objects into the top twelve
124 * NOTE we do not currently update this if a texture image
125 * changes, but that shouldn't happen too often and only has
126 * relatively minor performance implications
129 key |= m3gGen12BitTextureHash(appearance) << 12;
131 /* Use the rest of the bits for the various components; depth
132 * function changes are another potentially costly operation, so
135 key |= (m3gGenPointerHash(appearance->compositingMode) & 0x0Fu) << 8;
136 key |= (m3gGenPointerHash(appearance->material) & 0x07u) << 5;
137 key |= (m3gGenPointerHash(appearance->polygonMode) & 0x07u) << 2;
138 key |= (m3gGenPointerHash(appearance->fog) & 0x03u);
140 /* Store the final value */
141 appearance->sortKey = key;
144 /*----------------------------------------------------------------------
146 *--------------------------------------------------------------------*/
150 * \brief Destroys this Appearance object.
152 * \param obj Appearance object
154 static void m3gDestroyAppearance(Object *obj)
157 Appearance *appearance = (Appearance *) obj;
158 M3G_VALIDATE_OBJECT(appearance);
160 M3G_ASSIGN_REF(appearance->compositingMode, NULL);
161 M3G_ASSIGN_REF(appearance->fog, NULL);
162 M3G_ASSIGN_REF(appearance->material, NULL);
163 M3G_ASSIGN_REF(appearance->polygonMode, NULL);
164 for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
165 M3G_ASSIGN_REF(appearance->texture[i], NULL);
168 m3gDestroyObject(obj);
173 * \brief Applies Apperance settings to current OpenGL state
175 * \note m3gReleaseTextures must be called when no longer using this,
176 * to properly reset texture usage counters and unmap the texture
179 * \param appearance Appearance object
180 * \param alphaFactor alpha factor as 1.16 fixed point
182 static void m3gApplyAppearance(const Appearance *appearance,
188 if (appearance != NULL) {
191 # if defined(M3G_NGL_TEXTURE_API)
192 m3gLockMemory(M3G_INTERFACE(appearance)); /* for textures */
195 m3gApplyCompositingMode(appearance->compositingMode, ctx);
196 m3gApplyPolygonMode(appearance->polygonMode);
197 m3gApplyMaterial(appearance->material, alphaFactor);
198 m3gApplyFog(appearance->fog);
200 for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
201 Texture *tex = appearance->texture[i];
202 glActiveTexture(GL_TEXTURE0 + i);
204 glEnable(GL_TEXTURE_2D);
205 m3gBindTexture(appearance->texture[i]);
208 glDisable(GL_TEXTURE_2D);
213 m3gApplyAppearanceDefaults(ctx);
221 * \brief Release the textures bound for this appearance
223 static void m3gReleaseTextures(const Appearance *appearance)
225 if (appearance != NULL) {
228 for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
229 Texture *tex = appearance->texture[i];
231 m3gReleaseTexture(tex);
235 # if defined(M3G_NGL_TEXTURE_API)
236 m3gUnlockMemory(M3G_INTERFACE(appearance));
243 * \brief Overloaded Object3D method.
245 * \param self Appearance object
246 * \param time current world time
247 * \return minimum validity
249 static M3Gint m3gAppearanceApplyAnimation(Object *self, M3Gint time) {
250 M3Gint i, validity, minValidity = 0x7fffffff;
251 Appearance *appearance = (Appearance *)self;
252 M3G_VALIDATE_OBJECT(appearance);
254 if (appearance->compositingMode != NULL) {
255 validity = M3G_VFUNC(Object, appearance->compositingMode, applyAnimation)((Object *)appearance->compositingMode, time);
256 minValidity = (validity < minValidity ? validity : minValidity);
258 if (appearance->fog != NULL) {
259 validity = M3G_VFUNC(Object, appearance->fog, applyAnimation)((Object *)appearance->fog, time);
260 minValidity = (validity < minValidity ? validity : minValidity);
262 if (appearance->material != NULL) {
263 validity = M3G_VFUNC(Object, appearance->material, applyAnimation)((Object *)appearance->material, time);
264 minValidity = (validity < minValidity ? validity : minValidity);
266 for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
267 if (appearance->texture[i] != NULL) {
268 validity = M3G_VFUNC(Object, appearance->texture[i], applyAnimation)((Object *)appearance->texture[i], time);
269 minValidity = (validity < minValidity ? validity : minValidity);
273 /* no animations can target an Appearance directly, so we need
274 not call super.applyAnimation() here. */
280 * \brief Overloaded Object3D method.
282 static Object *m3gAppearanceFindID(Object *self, M3Gint userID)
285 Appearance *app = (Appearance *)self;
286 Object *found = m3gObjectFindID(self, userID);
288 if (!found && app->compositingMode) {
289 found = m3gFindID((Object*) app->compositingMode, userID);
291 if (!found && app->polygonMode) {
292 found = m3gFindID((Object*) app->polygonMode, userID);
294 if (!found && app->fog) {
295 found = m3gFindID((Object*) app->fog, userID);
297 if (!found && app->material) {
298 found = m3gFindID((Object*) app->material, userID);
300 for (i = 0; !found && i < M3G_NUM_TEXTURE_UNITS; ++i) {
301 if (app->texture[i]) {
302 found = m3gFindID((Object*) app->texture[i], userID);
310 * \brief Overloaded Object3D method.
312 * \param self Appearance object
313 * \param references array of reference objects
314 * \return number of references
316 static M3Gint m3gAppearanceDoGetReferences(Object *self, Object **references)
318 Appearance *app = (Appearance *)self;
319 M3Gint i, num = m3gObjectDoGetReferences(self, references);
320 if (app->compositingMode != NULL) {
321 if (references != NULL)
322 references[num] = (Object *)app->compositingMode;
325 if (app->polygonMode != NULL) {
326 if (references != NULL)
327 references[num] = (Object *)app->polygonMode;
330 if (app->fog != NULL) {
331 if (references != NULL)
332 references[num] = (Object *)app->fog;
335 if (app->material != NULL) {
336 if (references != NULL)
337 references[num] = (Object *)app->material;
340 for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
341 if (app->texture[i] != NULL) {
342 if (references != NULL)
343 references[num] = (Object *)app->texture[i];
353 * \brief Overloaded Object3D method.
355 * \param originalObj original Appearance object
356 * \param cloneObj pointer to cloned Appearance object
357 * \param pairs array for all object-duplicate pairs
358 * \param numPairs number of pairs
360 static M3Gbool m3gAppearanceDuplicate(const Object *originalObj,
366 Appearance *original = (Appearance *)originalObj;
367 Appearance *clone = (Appearance *)m3gCreateAppearance(originalObj->interface);
368 *cloneObj = (Object *)clone;
369 if (*cloneObj == NULL) {
373 if (m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
374 clone->layer = original->layer;
376 M3G_ASSIGN_REF(clone->compositingMode, original->compositingMode);
377 M3G_ASSIGN_REF(clone->fog, original->fog);
378 M3G_ASSIGN_REF(clone->polygonMode, original->polygonMode);
379 M3G_ASSIGN_REF(clone->material, original->material);
380 for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
381 M3G_ASSIGN_REF(clone->texture[i], original->texture[i]);
384 m3gRegenerateSortKey(clone);
393 /*----------------------------------------------------------------------
394 * Virtual function table
395 *--------------------------------------------------------------------*/
397 static const ObjectVFTable m3gvf_Appearance = {
398 m3gAppearanceApplyAnimation,
399 m3gObjectIsCompatible,
400 m3gObjectUpdateProperty,
401 m3gAppearanceDoGetReferences,
403 m3gAppearanceDuplicate,
408 /*----------------------------------------------------------------------
409 * Public API functions
410 *--------------------------------------------------------------------*/
413 * \brief Creates a new Appearance with default values
415 * \param hInterface M3G interface
416 * \retval Appearance new Appearance object
417 * \retval NULL Appearance creating failed
419 /*@access M3GInterface@*/
420 /*@access M3GAppearance@*/
421 M3G_API M3GAppearance m3gCreateAppearance(M3GInterface hInterface)
423 Interface *m3g = (Interface *) hInterface;
424 M3G_VALIDATE_INTERFACE(m3g);
426 Appearance *appearance = m3gAllocZ(m3g, sizeof(Appearance));
428 if (appearance != NULL) {
429 m3gInitObject(&appearance->object, m3g, M3G_CLASS_APPEARANCE);
430 m3gRegenerateSortKey(appearance);
433 return (M3GAppearance) appearance;
438 * \brief Get compositing mode
440 * \param hAppearance Appearance object
441 * \return CompositingMode object
443 M3G_API M3GCompositingMode m3gGetCompositingMode(M3GAppearance hAppearance)
445 const Appearance *appearance = (const Appearance *) hAppearance;
446 M3G_VALIDATE_OBJECT(appearance);
447 return (M3GCompositingMode)(appearance->compositingMode);
453 * \param hAppearance Appearance object
456 M3G_API M3GFog m3gGetFog(M3GAppearance hAppearance)
458 const Appearance *appearance = (const Appearance *) hAppearance;
459 M3G_VALIDATE_OBJECT(appearance);
460 return (M3GFog)(appearance->fog);
464 * \brief Get material
466 * \param hAppearance Appearance object
467 * \return Material object
469 M3G_API M3GMaterial m3gGetMaterial(M3GAppearance hAppearance)
471 const Appearance *appearance = (const Appearance *) hAppearance;
472 M3G_VALIDATE_OBJECT(appearance);
473 return (M3GMaterial)(appearance->material);
477 * \brief Get polygon mode
479 * \param hAppearance Appearance object
480 * \return PolygonMode object
482 M3G_API M3GPolygonMode m3gGetPolygonMode(M3GAppearance hAppearance)
484 const Appearance *appearance = (const Appearance *) hAppearance;
485 M3G_VALIDATE_OBJECT(appearance);
486 return (M3GPolygonMode)(appearance->polygonMode);
492 * \param hAppearance Appearance object
493 * \param unit texturing unit
494 * \return Texture2D object
496 M3G_API M3GTexture m3gGetTexture(M3GAppearance hAppearance, M3Gint unit)
498 const Appearance *appearance = (const Appearance *) hAppearance;
499 M3G_VALIDATE_OBJECT(appearance);
500 if (!m3gInRange(unit, 0, M3G_NUM_TEXTURE_UNITS - 1)) {
501 m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX);
502 return (M3GTexture) NULL;
504 return (M3GTexture)(appearance->texture[unit]);
510 * \param hAppearance Appearance object
511 * \return layer number
513 M3G_API M3Gint m3gGetLayer(M3GAppearance hAppearance)
515 const Appearance *appearance = (const Appearance *) hAppearance;
516 M3G_VALIDATE_OBJECT(appearance);
517 return appearance->layer;
521 * \brief Set compositing mode
523 * \param hAppearance Appearance object
524 * \param hMode CompositingMode object
526 M3G_API void m3gSetCompositingMode(M3GAppearance hAppearance,
527 M3GCompositingMode hMode)
529 Appearance *appearance = (Appearance *) hAppearance;
530 CompositingMode *mode = (CompositingMode *) hMode;
531 M3G_VALIDATE_OBJECT(appearance);
533 M3G_ASSIGN_REF(appearance->compositingMode, mode);
535 m3gRegenerateSortKey(appearance);
539 * \brief Set polygon mode
541 * \param hAppearance Appearance object
542 * \param hMode PolygonMode object
544 M3G_API void m3gSetPolygonMode(M3GAppearance hAppearance,
545 M3GPolygonMode hMode)
547 Appearance *appearance = (Appearance *) hAppearance;
548 PolygonMode *mode = (PolygonMode *) hMode;
549 M3G_VALIDATE_OBJECT(appearance);
551 M3G_ASSIGN_REF(appearance->polygonMode, mode);
553 m3gRegenerateSortKey(appearance);
559 * \param hAppearance Appearance object
560 * \param layer layer number
562 M3G_API void m3gSetLayer(M3GAppearance hAppearance, M3Gint layer)
564 Appearance *appearance = (Appearance *) hAppearance;
565 M3G_VALIDATE_OBJECT(appearance);
567 /* Check for errors */
568 if (!m3gInRange(layer, M3G_APPEARANCE_MIN_LAYER, M3G_APPEARANCE_MAX_LAYER)) {
569 m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX);
573 appearance->layer = (M3Gshort) layer;
575 m3gRegenerateSortKey(appearance);
579 * \brief Set material
581 * \param hAppearance Appearance object
582 * \param hMaterial Material object
584 M3G_API void m3gSetMaterial(M3GAppearance hAppearance,
585 M3GMaterial hMaterial)
587 Appearance *appearance = (Appearance *) hAppearance;
588 Material *material = (Material *) hMaterial;
589 M3G_VALIDATE_OBJECT(appearance);
591 M3G_ASSIGN_REF(appearance->material, material);
593 if (material != NULL) {
594 appearance->vertexMask |= (M3Gushort)M3G_NORMAL_BIT;
597 appearance->vertexMask &= ~(M3Gushort)M3G_NORMAL_BIT;
600 m3gRegenerateSortKey(appearance);
606 * \param hAppearance Appearance object
607 * \param unit texturing unit
608 * \param hTexture Texture2D object
610 M3G_API void m3gSetTexture(M3GAppearance hAppearance,
611 M3Gint unit, M3GTexture hTexture)
613 Appearance *appearance = (Appearance *) hAppearance;
614 Texture *texture = (Texture *) hTexture;
615 M3G_VALIDATE_OBJECT(appearance);
617 if (!m3gInRange(unit, 0, M3G_NUM_TEXTURE_UNITS - 1)) {
618 m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX);
622 M3G_ASSIGN_REF(appearance->texture[unit], texture);
624 if (texture != NULL) {
625 appearance->vertexMask |= (M3Gushort) (M3G_TEXCOORD0_BIT << unit);
628 appearance->vertexMask &= (M3Gushort) ~(M3G_TEXCOORD0_BIT << unit);
631 m3gRegenerateSortKey(appearance);
637 * \param hAppearance Appearance object
638 * \param hFog Fog object
640 M3G_API void m3gSetFog(M3GAppearance hAppearance, M3GFog hFog)
642 Appearance *appearance = (Appearance *) hAppearance;
643 M3G_VALIDATE_OBJECT(appearance);
645 M3G_ASSIGN_REF(appearance->fog, hFog);
647 m3gRegenerateSortKey(appearance);