ui_node_model.c

Go to the documentation of this file.
00001 
00010 /*
00011 Copyright (C) 2002-2010 UFO: Alien Invasion.
00012 
00013 This program is free software; you can redistribute it and/or
00014 modify it under the terms of the GNU General Public License
00015 as published by the Free Software Foundation; either version 2
00016 of the License, or (at your option) any later version.
00017 
00018 This program is distributed in the hope that it will be useful,
00019 but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00021 
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License
00025 along with this program; if not, write to the Free Software
00026 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00027 
00028 */
00029 
00030 #include "../ui_main.h"
00031 #include "../ui_internal.h"
00032 #include "../ui_nodes.h"
00033 #include "../ui_parse.h"
00034 #include "../ui_input.h"
00035 #include "../ui_internal.h"
00036 #include "ui_node_model.h"
00037 #include "ui_node_abstractnode.h"
00038 
00039 #include "../../client.h"
00040 #include "../../renderer/r_draw.h"
00041 #include "../../renderer/r_mesh.h"
00042 #include "../../renderer/r_mesh_anim.h"
00043 
00044 #define EXTRADATA_TYPE modelExtraData_t
00045 #define EXTRADATA(node) UI_EXTRADATA(node, EXTRADATA_TYPE)
00046 
00047 #define ROTATE_SPEED    0.5
00048 #define MAX_OLDREFVALUE MAX_VAR
00049 
00050 static const uiBehaviour_t const *localBehaviour;
00051 
00057 uiModel_t *UI_GetUIModel (const char *modelName)
00058 {
00059     int i;
00060     uiModel_t *m;
00061 
00062     for (i = 0; i < ui_global.numModels; i++) {
00063         m = &ui_global.models[i];
00064         if (!strncmp(m->id, modelName, MAX_VAR))
00065             return m;
00066     }
00067     return NULL;
00068 }
00069 
00070 static void UI_ListUIModels_f (void)
00071 {
00072     int i;
00073 
00074     /* search for UI models with same name */
00075     Com_Printf("UI models: %i\n", ui_global.numModels);
00076     for (i = 0; i < ui_global.numModels; i++)
00077         Com_Printf("id: %s\n...model: %s\n...need: %s\n\n", ui_global.models[i].id, ui_global.models[i].model, ui_global.models[i].need);
00078 }
00079 
00080 static void UI_ModelNodeDraw (uiNode_t *node)
00081 {
00082     const char* ref = UI_GetReferenceString(node, EXTRADATA(node).model);
00083     char source[MAX_VAR];
00084     if (ref == NULL || ref[0] == '\0')
00085         source[0] = '\0';
00086     else
00087         Q_strncpyz(source, ref, sizeof(source));
00088     UI_DrawModelNode(node, source);
00089 }
00090 
00091 static vec3_t nullVector = {0, 0, 0};
00092 
00097 static inline void UI_InitModelInfoView (uiNode_t *node, modelInfo_t *mi, uiModel_t *model)
00098 {
00099     vec3_t nodeorigin;
00100     UI_GetNodeAbsPos(node, nodeorigin);
00101     nodeorigin[0] += node->size[0] / 2 + EXTRADATA(node).origin[0];
00102     nodeorigin[1] += node->size[1] / 2 + EXTRADATA(node).origin[1];
00103     nodeorigin[2] = EXTRADATA(node).origin[2];
00104 
00105     VectorCopy(EXTRADATA(node).scale, mi->scale);
00106     VectorCopy(EXTRADATA(node).angles, mi->angles);
00107     VectorCopy(nodeorigin, mi->origin);
00108 
00109     VectorCopy(nullVector, mi->center);
00110 }
00111 
00115 static void UI_DrawModelNodeWithUIModel (uiNode_t *node, const char *source, modelInfo_t *mi, uiModel_t *model)
00116 {
00117     qboolean autoScaleComputed = qfalse;
00118     vec3_t autoScale;
00119     vec3_t autoCenter;
00120 
00121     while (model) {
00122         /* no animation */
00123         mi->frame = 0;
00124         mi->oldframe = 0;
00125         mi->backlerp = 0;
00126 
00127         assert(model->model);
00128         mi->model = R_RegisterModelShort(model->model);
00129         if (!mi->model) {
00130             model = model->next;
00131             continue;
00132         }
00133 
00134         mi->skin = model->skin;
00135         mi->name = model->model;
00136 
00137         /* set mi pointers to model */
00138         mi->origin = model->origin;
00139         mi->angles = model->angles;
00140         mi->center = model->center;
00141         mi->color = model->color;
00142         mi->scale = model->scale;
00143 
00144         if (model->tag && model->parent) {
00145             /* tag and parent defined */
00146             uiModel_t *parentModel;
00147             modelInfo_t pmi;
00148             vec3_t pmiorigin;
00149             animState_t *as;
00150             /* place this model part on an already existing model tag */
00151             parentModel = UI_GetUIModel(model->parent);
00152             if (!parentModel) {
00153                 Com_Printf("UI Model: Could not get the model '%s'\n", model->parent);
00154                 break;
00155             }
00156             pmi.model = R_RegisterModelShort(parentModel->model);
00157             if (!pmi.model) {
00158                 Com_Printf("UI Model: Could not get the model '%s'\n", parentModel->model);
00159                 break;
00160             }
00161 
00162             pmi.name = parentModel->model;
00163 
00164             pmi.origin = pmiorigin;
00165             pmi.angles = parentModel->angles;
00166             pmi.scale = parentModel->scale;
00167             pmi.center = parentModel->center;
00168             pmi.color = parentModel->color;
00169 
00170             pmi.origin[0] = parentModel->origin[0] + mi->origin[0];
00171             pmi.origin[1] = parentModel->origin[1] + mi->origin[1];
00172             pmi.origin[2] = parentModel->origin[2];
00173             /* don't count window offset twice for tagged models */
00174             mi->origin[0] -= node->root->pos[0];
00175             mi->origin[1] -= node->root->pos[1];
00176 
00177             /* autoscale? */
00178             if (EXTRADATA(node).autoscale) {
00179                 if (!autoScaleComputed)
00180                     Sys_Error("Wrong order of model nodes - the tag and parent model node must be after the base model node");
00181                 pmi.scale = autoScale;
00182                 pmi.center = autoCenter;
00183             }
00184 
00185             as = &parentModel->animState;
00186             if (!as)
00187                 Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", pmi.name, parentModel->anim);
00188             pmi.frame = as->frame;
00189             pmi.oldframe = as->oldframe;
00190             pmi.backlerp = as->backlerp;
00191 
00192             R_DrawModelDirect(mi, &pmi, model->tag);
00193         } else {
00194             /* no tag and no parent means - base model or single model */
00195             const char *ref;
00196             UI_InitModelInfoView(node, mi, model);
00197             Vector4Copy(node->color, mi->color);
00198 
00199             /* compute the scale and center for the first model.
00200              * it think its the bigger of composite models.
00201              * All next elements use the same result
00202              */
00203             if (EXTRADATA(node).autoscale) {
00204                 if (!autoScaleComputed) {
00205                     vec2_t size;
00206                     size[0] = node->size[0] - node->padding;
00207                     size[1] = node->size[1] - node->padding;
00208                     R_ModelAutoScale(size, mi, autoScale, autoCenter);
00209                     autoScaleComputed = qtrue;
00210                 } else {
00211                     mi->scale = autoScale;
00212                     mi->center = autoCenter;
00213                 }
00214             }
00215 
00216             /* get the animation given by node properties */
00217             if (EXTRADATA(node).animation && *(char *) EXTRADATA(node).animation) {
00218                 ref = UI_GetReferenceString(node, EXTRADATA(node).animation);
00219             /* otherwise use the standard animation from UI model definition */
00220             } else
00221                 ref = model->anim;
00222 
00223             /* only base models have animations */
00224             if (ref && *ref) {
00225                 animState_t *as = &model->animState;
00226                 const char *anim = R_AnimGetName(as, mi->model);
00227                 /* initial animation or animation change */
00228                 if (!anim || (anim && strncmp(anim, ref, MAX_VAR)))
00229                     R_AnimChange(as, mi->model, ref);
00230                 else
00231                     R_AnimRun(as, mi->model, cls.frametime * 1000);
00232 
00233                 mi->frame = as->frame;
00234                 mi->oldframe = as->oldframe;
00235                 mi->backlerp = as->backlerp;
00236             }
00237             R_DrawModelDirect(mi, NULL, NULL);
00238         }
00239 
00240         /* next */
00241         model = model->next;
00242     }
00243 }
00244 
00248 void UI_DrawModelNode (uiNode_t *node, const char *source)
00249 {
00250     modelInfo_t mi;
00251     uiModel_t *model;
00252     vec3_t nodeorigin;
00253     vec3_t autoScale;
00254     vec3_t autoCenter;
00255 
00256     assert(UI_NodeInstanceOf(node, "model"));           
00258     if (source[0] == '\0')
00259         return;
00260 
00261     model = UI_GetUIModel(source);
00262     /* direct model name - no UI model definition */
00263     if (!model) {
00264         /* prevent the searching for a model def in the next frame */
00265         mi.model = R_RegisterModelShort(source);
00266         mi.name = source;
00267         if (!mi.model) {
00268             Com_Printf("Could not find model '%s'\n", source);
00269             return;
00270         }
00271     }
00272 
00273     /* compute the absolute origin ('origin' property is relative to the node center) */
00274     UI_GetNodeAbsPos(node, nodeorigin);
00275     R_CleanupDepthBuffer(nodeorigin[0], nodeorigin[1], node->size[0], node->size[1]);
00276     if (EXTRADATA(node).clipOverflow)
00277         R_PushClipRect(nodeorigin[0], nodeorigin[1], node->size[0], node->size[1]);
00278     nodeorigin[0] += node->size[0] / 2 + EXTRADATA(node).origin[0];
00279     nodeorigin[1] += node->size[1] / 2 + EXTRADATA(node).origin[1];
00280     nodeorigin[2] = EXTRADATA(node).origin[2];
00281 
00282     mi.origin = nodeorigin;
00283     mi.angles = EXTRADATA(node).angles;
00284     mi.scale = EXTRADATA(node).scale;
00285     mi.center = nullVector;
00286     mi.color = node->color;
00287     mi.mesh = 0;
00288 
00289     /* special case to draw models with UI model */
00290     if (model) {
00291         UI_DrawModelNodeWithUIModel(node, source, &mi, model);
00292         if (EXTRADATA(node).clipOverflow)
00293             R_PopClipRect();
00294         return;
00295     }
00296 
00297     /* if the node is linked to a parent, the parent will display it */
00298     if (EXTRADATA(node).tag) {
00299         if (EXTRADATA(node).clipOverflow)
00300             R_PopClipRect();
00301         return;
00302     }
00303 
00304     /* autoscale? */
00305     if (EXTRADATA(node).autoscale) {
00306         vec2_t size;
00307         size[0] = node->size[0] - node->padding;
00308         size[1] = node->size[1] - node->padding;
00309         R_ModelAutoScale(size, &mi, autoScale, autoCenter);
00310     }
00311 
00312     /* no animation */
00313     mi.frame = 0;
00314     mi.oldframe = 0;
00315     mi.backlerp = 0;
00316 
00317     /* get skin */
00318     if (EXTRADATA(node).skin && *(char *) EXTRADATA(node).skin)
00319         mi.skin = atoi(UI_GetReferenceString(node, EXTRADATA(node).skin));
00320     else
00321         mi.skin = 0;
00322 
00323     /* do animations */
00324     if (EXTRADATA(node).animation && *(char *) EXTRADATA(node).animation) {
00325         animState_t *as;
00326         const char *ref;
00327         ref = UI_GetReferenceString(node, EXTRADATA(node).animation);
00328 
00329         /* check whether the cvar value changed */
00330         if (strncmp(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE)) {
00331             Q_strncpyz(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE);
00332             /* model has changed but mem is already reserved in pool */
00333             if (EXTRADATA(node).animationState) {
00334                 Mem_Free(EXTRADATA(node).animationState);
00335                 EXTRADATA(node).animationState = NULL;
00336             }
00337         }
00338         if (!EXTRADATA(node).animationState) {
00339             as = (animState_t *) Mem_PoolAlloc(sizeof(*as), cl_genericPool, 0);
00340             if (!as)
00341                 Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref);
00342             R_AnimChange(as, mi.model, ref);
00343             EXTRADATA(node).animationState = as;
00344         } else {
00345             const char *anim;
00346             /* change anim if needed */
00347             as = EXTRADATA(node).animationState;
00348             if (!as)
00349                 Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref);
00350             anim = R_AnimGetName(as, mi.model);
00351             if (anim && strcmp(anim, ref))
00352                 R_AnimChange(as, mi.model, ref);
00353             R_AnimRun(as, mi.model, cls.frametime * 1000);
00354         }
00355 
00356         mi.frame = as->frame;
00357         mi.oldframe = as->oldframe;
00358         mi.backlerp = as->backlerp;
00359     }
00360 
00361     /* draw the main model on the node */
00362     R_DrawModelDirect(&mi, NULL, NULL);
00363 
00364     /* draw all childs */
00365     if (node->firstChild) {
00366         uiNode_t *child;
00367         modelInfo_t pmi = mi;
00368         for (child = node->firstChild; child; child = child->next) {
00369             const char *tag;
00370             char childSource[MAX_VAR];
00371             const char* childRef;
00372 
00373             /* skip non "model" nodes */
00374             if (child->behaviour != node->behaviour)
00375                 continue;
00376 
00377             /* skip invisible child */
00378             if (child->invis || !UI_CheckVisibility(child))
00379                 continue;
00380 
00381             memset(&mi, 0, sizeof(mi));
00382             mi.angles = EXTRADATA(child).angles;
00383             mi.scale = EXTRADATA(child).scale;
00384             mi.center = nullVector;
00385             mi.origin = EXTRADATA(child).origin;
00386             mi.color = pmi.color;
00387 
00388             /* get the anchor name to link the model into the parent */
00389             tag = EXTRADATA(child).tag;
00390 
00391             /* init model name */
00392             childRef = UI_GetReferenceString(child, EXTRADATA(child).model);
00393             if (childRef == NULL || childRef[0] == '\0')
00394                 childSource[0] = '\0';
00395             else
00396                 Q_strncpyz(childSource, childRef, sizeof(childSource));
00397             mi.model = R_RegisterModelShort(childSource);
00398             mi.name = childSource;
00399 
00400             /* init skin */
00401             if (EXTRADATA(child).skin && *(char *) EXTRADATA(child).skin)
00402                 mi.skin = atoi(UI_GetReferenceString(child, EXTRADATA(child).skin));
00403             else
00404                 mi.skin = 0;
00405 
00406             R_DrawModelDirect(&mi, &pmi, tag);
00407         }
00408     }
00409 
00410     if (EXTRADATA(node).clipOverflow)
00411         R_PopClipRect();
00412 }
00413 
00414 static int oldMousePosX = 0;
00415 static int oldMousePosY = 0;
00416 
00417 static void UI_ModelNodeCapturedMouseMove (uiNode_t *node, int x, int y)
00418 {
00419     float *rotateAngles = EXTRADATA(node).angles;
00420 
00421     /* rotate a model */
00422     rotateAngles[YAW] -= ROTATE_SPEED * (x - oldMousePosX);
00423     rotateAngles[ROLL] += ROTATE_SPEED * (y - oldMousePosY);
00424 
00425     /* clamp the angles */
00426     while (rotateAngles[YAW] > 360.0)
00427         rotateAngles[YAW] -= 360.0;
00428     while (rotateAngles[YAW] < 0.0)
00429         rotateAngles[YAW] += 360.0;
00430 
00431     if (rotateAngles[ROLL] < 0.0)
00432         rotateAngles[ROLL] = 0.0;
00433     else if (rotateAngles[ROLL] > 180.0)
00434         rotateAngles[ROLL] = 180.0;
00435 
00436     oldMousePosX = x;
00437     oldMousePosY = y;
00438 }
00439 
00440 static void UI_ModelNodeMouseDown (uiNode_t *node, int x, int y, int button)
00441 {
00442     if (button != K_MOUSE1)
00443         return;
00444     if (!EXTRADATA(node).rotateWithMouse)
00445         return;
00446     UI_SetMouseCapture(node);
00447     oldMousePosX = x;
00448     oldMousePosY = y;
00449 }
00450 
00451 static void UI_ModelNodeMouseUp (uiNode_t *node, int x, int y, int button)
00452 {
00453     if (button != K_MOUSE1)
00454         return;
00455     if (UI_GetMouseCapture() != node)
00456         return;
00457     UI_MouseRelease();
00458 }
00459 
00463 static void UI_ModelNodeLoading (uiNode_t *node)
00464 {
00465     Vector4Set(node->color, 1, 1, 1, 1);
00466     VectorSet(EXTRADATA(node).scale, 1, 1, 1);
00467     EXTRADATA(node).clipOverflow = qtrue;
00468 }
00469 
00473 static void UI_ModelNodeClone (const uiNode_t *source, uiNode_t *clone)
00474 {
00475     localBehaviour->super->clone(source, clone);
00476     if (!clone->dynamic)
00477         EXTRADATA(clone).oldRefValue = UI_AllocStaticString("", MAX_OLDREFVALUE);
00478 }
00479 
00480 static void UI_ModelNodeNew (uiNode_t *node)
00481 {
00482     EXTRADATA(node).oldRefValue = (char*) Mem_PoolAlloc(MAX_OLDREFVALUE, ui_dynPool, 0);
00483     EXTRADATA(node).oldRefValue[0] = '\0';
00484 }
00485 
00486 static void UI_ModelNodeDelete (uiNode_t *node)
00487 {
00488     Mem_Free(EXTRADATA(node).oldRefValue);
00489     EXTRADATA(node).oldRefValue = NULL;
00490 }
00491 
00492 static void UI_ModelNodeLoaded (uiNode_t *node)
00493 {
00494     /* a tag without but not a submodel */
00495     if (EXTRADATA(node).tag != NULL && node->behaviour != node->parent->behaviour) {
00496         Com_Printf("UI_ModelNodeLoaded: '%s' use a tag but is not a submodel. Tag removed.\n", UI_GetPath(node));
00497         EXTRADATA(node).tag = NULL;
00498     }
00499 
00500     if (EXTRADATA(node).oldRefValue == NULL)
00501         EXTRADATA(node).oldRefValue = UI_AllocStaticString("", MAX_OLDREFVALUE);
00502 
00503     /* no tag but no size */
00504     if (EXTRADATA(node).tag == NULL && (node->size[0] == 0 || node->size[1] == 0)) {
00505         Com_Printf("UI_ModelNodeLoaded: Please set a pos and size to the node '%s'. Note: 'origin' is a relative value to the center of the node\n", UI_GetPath(node));
00506     }
00507 }
00508 
00510 static const value_t properties[] = {
00511     /* Both. Name of the animation for the model */
00512     {"anim", V_CVAR_OR_STRING, UI_EXTRADATA_OFFSETOF(modelExtraData_t, animation), 0},
00513     /* Main model only. Point of view. */
00514     {"angles", V_VECTOR, UI_EXTRADATA_OFFSETOF(modelExtraData_t, angles), MEMBER_SIZEOF(modelExtraData_t, angles)},
00515     /* Main model only. Position of the model relative to the center of the node. */
00516     {"origin", V_VECTOR, UI_EXTRADATA_OFFSETOF(modelExtraData_t, origin), MEMBER_SIZEOF(modelExtraData_t, origin)},
00517     /* Both. Scale the model */
00518     {"scale", V_VECTOR, UI_EXTRADATA_OFFSETOF(modelExtraData_t, scale), MEMBER_SIZEOF(modelExtraData_t, scale)},
00519     /* Submodel only. A tag name to link the model to the parent model. */
00520     {"tag", V_CVAR_OR_STRING, UI_EXTRADATA_OFFSETOF(modelExtraData_t, tag), 0},
00521     /* Main model only. Auto compute the "better" scale for the model. The function dont work
00522      * very well at the moment because it dont check the angle and no more submodel bounding box.
00523      */
00524     {"autoscale", V_BOOL, UI_EXTRADATA_OFFSETOF(modelExtraData_t, autoscale), MEMBER_SIZEOF(modelExtraData_t, autoscale)},
00525     /* Main model only. Allow to change the POV of the model with the mouse (only for main model) */
00526     {"rotatewithmouse", V_BOOL, UI_EXTRADATA_OFFSETOF(modelExtraData_t, rotateWithMouse), MEMBER_SIZEOF(modelExtraData_t, rotateWithMouse)},
00527     /* Main model only. Clip the model with the node rect */
00528     {"clipoverflow", V_BOOL, UI_EXTRADATA_OFFSETOF(modelExtraData_t, clipOverflow), MEMBER_SIZEOF(modelExtraData_t, clipOverflow)},
00529     /* Source of the model. The path to the model, relative to <code>base/models</code> */
00530     {"src", V_CVAR_OR_STRING, UI_EXTRADATA_OFFSETOF(modelExtraData_t, model), 0},
00531     /* Both. Name of the skin for the model. */
00532     {"skin", V_CVAR_OR_STRING, UI_EXTRADATA_OFFSETOF(modelExtraData_t, skin), 0},
00533 
00534     {NULL, V_NULL, 0, 0}
00535 };
00536 
00537 void UI_RegisterModelNode (uiBehaviour_t *behaviour)
00538 {
00539     localBehaviour = behaviour;
00540     behaviour->name = "model";
00541     behaviour->drawItselfChild = qtrue;
00542     behaviour->draw = UI_ModelNodeDraw;
00543     behaviour->mouseDown = UI_ModelNodeMouseDown;
00544     behaviour->mouseUp = UI_ModelNodeMouseUp;
00545     behaviour->loading = UI_ModelNodeLoading;
00546     behaviour->loaded = UI_ModelNodeLoaded;
00547     behaviour->clone = UI_ModelNodeClone;
00548     behaviour->new = UI_ModelNodeNew;
00549     behaviour->delete = UI_ModelNodeDelete;
00550     behaviour->capturedMouseMove = UI_ModelNodeCapturedMouseMove;
00551     behaviour->properties = properties;
00552     behaviour->extraDataSize = sizeof(EXTRADATA_TYPE);
00553 
00554     Cmd_AddCommand("uimodelslist", UI_ListUIModels_f, NULL);
00555 }

Generated by  doxygen 1.6.2