00001
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
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
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
00146 uiModel_t *parentModel;
00147 modelInfo_t pmi;
00148 vec3_t pmiorigin;
00149 animState_t *as;
00150
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
00174 mi->origin[0] -= node->root->pos[0];
00175 mi->origin[1] -= node->root->pos[1];
00176
00177
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
00195 const char *ref;
00196 UI_InitModelInfoView(node, mi, model);
00197 Vector4Copy(node->color, mi->color);
00198
00199
00200
00201
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
00217 if (EXTRADATA(node).animation && *(char *) EXTRADATA(node).animation) {
00218 ref = UI_GetReferenceString(node, EXTRADATA(node).animation);
00219
00220 } else
00221 ref = model->anim;
00222
00223
00224 if (ref && *ref) {
00225 animState_t *as = &model->animState;
00226 const char *anim = R_AnimGetName(as, mi->model);
00227
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
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
00263 if (!model) {
00264
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
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
00290 if (model) {
00291 UI_DrawModelNodeWithUIModel(node, source, &mi, model);
00292 if (EXTRADATA(node).clipOverflow)
00293 R_PopClipRect();
00294 return;
00295 }
00296
00297
00298 if (EXTRADATA(node).tag) {
00299 if (EXTRADATA(node).clipOverflow)
00300 R_PopClipRect();
00301 return;
00302 }
00303
00304
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
00313 mi.frame = 0;
00314 mi.oldframe = 0;
00315 mi.backlerp = 0;
00316
00317
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
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
00330 if (strncmp(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE)) {
00331 Q_strncpyz(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE);
00332
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
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
00362 R_DrawModelDirect(&mi, NULL, NULL);
00363
00364
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
00374 if (child->behaviour != node->behaviour)
00375 continue;
00376
00377
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
00389 tag = EXTRADATA(child).tag;
00390
00391
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
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
00422 rotateAngles[YAW] -= ROTATE_SPEED * (x - oldMousePosX);
00423 rotateAngles[ROLL] += ROTATE_SPEED * (y - oldMousePosY);
00424
00425
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
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
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
00512 {"anim", V_CVAR_OR_STRING, UI_EXTRADATA_OFFSETOF(modelExtraData_t, animation), 0},
00513
00514 {"angles", V_VECTOR, UI_EXTRADATA_OFFSETOF(modelExtraData_t, angles), MEMBER_SIZEOF(modelExtraData_t, angles)},
00515
00516 {"origin", V_VECTOR, UI_EXTRADATA_OFFSETOF(modelExtraData_t, origin), MEMBER_SIZEOF(modelExtraData_t, origin)},
00517
00518 {"scale", V_VECTOR, UI_EXTRADATA_OFFSETOF(modelExtraData_t, scale), MEMBER_SIZEOF(modelExtraData_t, scale)},
00519
00520 {"tag", V_CVAR_OR_STRING, UI_EXTRADATA_OFFSETOF(modelExtraData_t, tag), 0},
00521
00522
00523
00524 {"autoscale", V_BOOL, UI_EXTRADATA_OFFSETOF(modelExtraData_t, autoscale), MEMBER_SIZEOF(modelExtraData_t, autoscale)},
00525
00526 {"rotatewithmouse", V_BOOL, UI_EXTRADATA_OFFSETOF(modelExtraData_t, rotateWithMouse), MEMBER_SIZEOF(modelExtraData_t, rotateWithMouse)},
00527
00528 {"clipoverflow", V_BOOL, UI_EXTRADATA_OFFSETOF(modelExtraData_t, clipOverflow), MEMBER_SIZEOF(modelExtraData_t, clipOverflow)},
00529
00530 {"src", V_CVAR_OR_STRING, UI_EXTRADATA_OFFSETOF(modelExtraData_t, model), 0},
00531
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 }