static qboolean load_iqm_meshes (model_t *mod, const iqmheader *hdr, byte *buffer) { iqm_t *iqm = (iqm_t *) mod->aliashdr; iqmtriangle *tris; iqmmesh *meshes; iqmjoint *joints; uint32_t i; if (!load_iqm_vertex_arrays (mod, hdr, buffer)) return false; if (!(tris = get_triangles (hdr, buffer))) return false; iqm->num_elements = hdr->num_triangles * 3; iqm->elements = malloc (hdr->num_triangles * 3 * sizeof (uint16_t)); for (i = 0; i < hdr->num_triangles; i++) VectorCopy (tris[i].vertex, iqm->elements + i * 3); if (!(meshes = get_meshes (hdr, buffer))) return false; iqm->num_meshes = hdr->num_meshes; iqm->meshes = malloc (hdr->num_meshes * sizeof (iqmmesh)); memcpy (iqm->meshes, meshes, hdr->num_meshes * sizeof (iqmmesh)); if (!(joints = get_joints (hdr, buffer))) return false; iqm->num_joints = hdr->num_joints; iqm->joints = malloc (iqm->num_joints * sizeof (iqmjoint)); iqm->baseframe = malloc (iqm->num_joints * sizeof (mat4_t)); iqm->inverse_baseframe = malloc (iqm->num_joints * sizeof (mat4_t)); memcpy (iqm->joints, joints, iqm->num_joints * sizeof (iqmjoint)); for (i = 0; i < hdr->num_joints; i++) { iqmjoint *j = &iqm->joints[i]; mat4_t *bf = &iqm->baseframe[i]; mat4_t *ibf = &iqm->inverse_baseframe[i]; quat_t t; float ilen; ilen = 1.0 / sqrt(QDotProduct (j->rotate, j->rotate)); QuatScale (j->rotate, ilen, t); Mat4Init (t, j->scale, j->translate, *bf); Mat4Inverse (*bf, *ibf); if (j->parent >= 0) { Mat4Mult (iqm->baseframe[j->parent], *bf, *bf); Mat4Mult (*ibf, iqm->inverse_baseframe[j->parent], *ibf); } } return true; }
/* PR_ExecuteProgram The interpretation main loop */ VISIBLE void PR_ExecuteProgram (progs_t * pr, func_t fnum) { int exitdepth, profile, startprofile; pr_uint_t pointer; dstatement_t *st; edict_t *ed; pr_type_t *ptr; pr_type_t old_val = {0}, *watch = 0; // make a stack frame exitdepth = pr->pr_depth; startprofile = profile = 0; Sys_PushSignalHook (signal_hook, pr); if (!PR_CallFunction (pr, fnum)) { // called a builtin instead of progs code Sys_PopSignalHook (); return; } st = pr->pr_statements + pr->pr_xstatement; if (pr->watch) { watch = pr->watch; old_val = *watch; } while (1) { pr_type_t *op_a, *op_b, *op_c; st++; ++pr->pr_xstatement; if (pr->pr_xstatement != st - pr->pr_statements) PR_RunError (pr, "internal error"); if (++profile > 1000000 && !pr->no_exec_limit) { PR_RunError (pr, "runaway loop error"); } op_a = pr->pr_globals + st->a; op_b = pr->pr_globals + st->b; op_c = pr->pr_globals + st->c; if (pr->pr_trace) PR_PrintStatement (pr, st, 1); switch (st->op) { case OP_ADD_F: OPC.float_var = OPA.float_var + OPB.float_var; break; case OP_ADD_V: VectorAdd (OPA.vector_var, OPB.vector_var, OPC.vector_var); break; case OP_ADD_Q: QuatAdd (OPA.quat_var, OPB.quat_var, OPC.quat_var); break; case OP_ADD_S: OPC.string_var = PR_CatStrings (pr, PR_GetString (pr, OPA.string_var), PR_GetString (pr, OPB.string_var)); break; case OP_SUB_F: OPC.float_var = OPA.float_var - OPB.float_var; break; case OP_SUB_V: VectorSubtract (OPA.vector_var, OPB.vector_var, OPC.vector_var); break; case OP_SUB_Q: QuatSubtract (OPA.quat_var, OPB.quat_var, OPC.quat_var); break; case OP_MUL_F: OPC.float_var = OPA.float_var * OPB.float_var; break; case OP_MUL_V: OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var); break; case OP_MUL_FV: { // avoid issues with the likes of x = x.x * x; // makes for faster code, too float scale = OPA.float_var; VectorScale (OPB.vector_var, scale, OPC.vector_var); } break; case OP_MUL_VF: { // avoid issues with the likes of x = x * x.x; // makes for faster code, too float scale = OPB.float_var; VectorScale (OPA.vector_var, scale, OPC.vector_var); } break; case OP_MUL_Q: QuatMult (OPA.quat_var, OPB.quat_var, OPC.quat_var); break; case OP_MUL_QV: QuatMultVec (OPA.quat_var, OPB.vector_var, OPC.vector_var); break; case OP_MUL_FQ: { // avoid issues with the likes of x = x.s * x; // makes for faster code, too float scale = OPA.float_var; QuatScale (OPB.quat_var, scale, OPC.quat_var); } break; case OP_MUL_QF: { // avoid issues with the likes of x = x * x.s; // makes for faster code, too float scale = OPB.float_var; QuatScale (OPA.quat_var, scale, OPC.quat_var); } break; case OP_CONJ_Q: QuatConj (OPA.quat_var, OPC.quat_var); break; case OP_DIV_F: OPC.float_var = OPA.float_var / OPB.float_var; break; case OP_BITAND: OPC.float_var = (int) OPA.float_var & (int) OPB.float_var; break; case OP_BITOR: OPC.float_var = (int) OPA.float_var | (int) OPB.float_var; break; case OP_BITXOR_F: OPC.float_var = (int) OPA.float_var ^ (int) OPB.float_var; break; case OP_BITNOT_F: OPC.float_var = ~ (int) OPA.float_var; break; case OP_SHL_F: OPC.float_var = (int) OPA.float_var << (int) OPB.float_var; break; case OP_SHR_F: OPC.float_var = (int) OPA.float_var >> (int) OPB.float_var; break; case OP_SHL_I: OPC.integer_var = OPA.integer_var << OPB.integer_var; break; case OP_SHR_I: OPC.integer_var = OPA.integer_var >> OPB.integer_var; break; case OP_SHR_U: OPC.uinteger_var = OPA.uinteger_var >> OPB.integer_var; break; case OP_GE_F: OPC.float_var = OPA.float_var >= OPB.float_var; break; case OP_LE_F: OPC.float_var = OPA.float_var <= OPB.float_var; break; case OP_GT_F: OPC.float_var = OPA.float_var > OPB.float_var; break; case OP_LT_F: OPC.float_var = OPA.float_var < OPB.float_var; break; case OP_AND: // OPA and OPB have to be float for -0.0 OPC.integer_var = FNZ (OPA) && FNZ (OPB); break; case OP_OR: // OPA and OPB have to be float for -0.0 OPC.integer_var = FNZ (OPA) || FNZ (OPB); break; case OP_NOT_F: OPC.integer_var = !FNZ (OPA); break; case OP_NOT_V: OPC.integer_var = VectorIsZero (OPA.vector_var); break; case OP_NOT_Q: OPC.integer_var = QuatIsZero (OPA.quat_var); break; case OP_NOT_S: OPC.integer_var = !OPA.string_var || !*PR_GetString (pr, OPA.string_var); break; case OP_NOT_FN: OPC.integer_var = !OPA.func_var; break; case OP_NOT_ENT: OPC.integer_var = !OPA.entity_var; break; case OP_EQ_F: OPC.integer_var = OPA.float_var == OPB.float_var; break; case OP_EQ_V: OPC.integer_var = VectorCompare (OPA.vector_var, OPB.vector_var); break; case OP_EQ_Q: OPC.integer_var = QuatCompare (OPA.quat_var, OPB.quat_var); break; case OP_EQ_E: OPC.integer_var = OPA.integer_var == OPB.integer_var; break; case OP_EQ_FN: OPC.integer_var = OPA.func_var == OPB.func_var; break; case OP_NE_F: OPC.integer_var = OPA.float_var != OPB.float_var; break; case OP_NE_V: OPC.integer_var = !VectorCompare (OPA.vector_var, OPB.vector_var); break; case OP_NE_Q: OPC.integer_var = !QuatCompare (OPA.quat_var, OPB.quat_var); break; case OP_LE_S: case OP_GE_S: case OP_LT_S: case OP_GT_S: case OP_NE_S: case OP_EQ_S: { int cmp = strcmp (PR_GetString (pr, OPA.string_var), PR_GetString (pr, OPB.string_var)); switch (st->op) { case OP_LE_S: cmp = (cmp <= 0); break; case OP_GE_S: cmp = (cmp >= 0); break; case OP_LT_S: cmp = (cmp < 0); break; case OP_GT_S: cmp = (cmp > 0); break; case OP_NE_S: break; case OP_EQ_S: cmp = !cmp; break; default: break; } OPC.integer_var = cmp; } break; case OP_NE_E: OPC.integer_var = OPA.integer_var != OPB.integer_var; break; case OP_NE_FN: OPC.integer_var = OPA.func_var != OPB.func_var; break; // ================== case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FN: // pointers case OP_STORE_I: case OP_STORE_P: OPB.integer_var = OPA.integer_var; break; case OP_STORE_V: VectorCopy (OPA.vector_var, OPB.vector_var); break; case OP_STORE_Q: QuatCopy (OPA.quat_var, OPB.quat_var); break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FN: // pointers case OP_STOREP_I: case OP_STOREP_P: pointer = OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; ptr->integer_var = OPA.integer_var; break; case OP_STOREP_V: pointer = OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (OPA.vector_var, ptr->vector_var); break; case OP_STOREP_Q: pointer = OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; case OP_ADDRESS: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 || OPA.entity_var >= pr->pr_edictareasize) PR_RunError (pr, "Progs attempted to address an out " "of bounds edict"); if (OPA.entity_var == 0 && pr->null_bad) PR_RunError (pr, "assignment to world entity"); if (OPB.uinteger_var >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to address an " "invalid field in an edict"); } ed = PROG_TO_EDICT (pr, OPA.entity_var); OPC.integer_var = &ed->v[OPB.integer_var] - pr->pr_globals; break; case OP_ADDRESS_VOID: case OP_ADDRESS_F: case OP_ADDRESS_V: case OP_ADDRESS_Q: case OP_ADDRESS_S: case OP_ADDRESS_ENT: case OP_ADDRESS_FLD: case OP_ADDRESS_FN: case OP_ADDRESS_I: case OP_ADDRESS_P: OPC.integer_var = st->a; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FN: case OP_LOAD_I: case OP_LOAD_P: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 || OPA.entity_var >= pr->pr_edictareasize) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } ed = PROG_TO_EDICT (pr, OPA.entity_var); OPC.integer_var = ed->v[OPB.integer_var].integer_var; break; case OP_LOAD_V: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 || OPA.entity_var >= pr->pr_edictareasize) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var + 2 >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } ed = PROG_TO_EDICT (pr, OPA.entity_var); memcpy (&OPC, &ed->v[OPB.integer_var], 3 * sizeof (OPC)); break; case OP_LOAD_Q: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 || OPA.entity_var >= pr->pr_edictareasize) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var + 3 >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } ed = PROG_TO_EDICT (pr, OPA.entity_var); memcpy (&OPC, &ed->v[OPB.integer_var], 3 * sizeof (OPC)); break; case OP_LOADB_F: case OP_LOADB_S: case OP_LOADB_ENT: case OP_LOADB_FLD: case OP_LOADB_FN: case OP_LOADB_I: case OP_LOADB_P: pointer = OPA.integer_var + OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; OPC.integer_var = ptr->integer_var; break; case OP_LOADB_V: pointer = OPA.integer_var + OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (ptr->vector_var, OPC.vector_var); break; case OP_LOADB_Q: pointer = OPA.integer_var + OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (ptr->quat_var, OPC.quat_var); break; case OP_LOADBI_F: case OP_LOADBI_S: case OP_LOADBI_ENT: case OP_LOADBI_FLD: case OP_LOADBI_FN: case OP_LOADBI_I: case OP_LOADBI_P: pointer = OPA.integer_var + (short) st->b; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; OPC.integer_var = ptr->integer_var; break; case OP_LOADBI_V: pointer = OPA.integer_var + (short) st->b; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (ptr->vector_var, OPC.vector_var); break; case OP_LOADBI_Q: pointer = OPA.integer_var + (short) st->b; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (ptr->quat_var, OPC.quat_var); break; case OP_LEA: pointer = OPA.integer_var + OPB.integer_var; OPC.integer_var = pointer; break; case OP_LEAI: pointer = OPA.integer_var + (short) st->b; OPC.integer_var = pointer; break; case OP_STOREB_F: case OP_STOREB_S: case OP_STOREB_ENT: case OP_STOREB_FLD: case OP_STOREB_FN: case OP_STOREB_I: case OP_STOREB_P: pointer = OPB.integer_var + OPC.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; ptr->integer_var = OPA.integer_var; break; case OP_STOREB_V: pointer = OPB.integer_var + OPC.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (OPA.vector_var, ptr->vector_var); break; case OP_STOREB_Q: pointer = OPB.integer_var + OPC.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; case OP_STOREBI_F: case OP_STOREBI_S: case OP_STOREBI_ENT: case OP_STOREBI_FLD: case OP_STOREBI_FN: case OP_STOREBI_I: case OP_STOREBI_P: pointer = OPB.integer_var + (short) st->c; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; ptr->integer_var = OPA.integer_var; break; case OP_STOREBI_V: pointer = OPB.integer_var + (short) st->c; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (OPA.vector_var, ptr->vector_var); break; case OP_STOREBI_Q: pointer = OPB.integer_var + (short) st->c; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; // ================== case OP_IFNOT: if (!OPA.integer_var) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IF: if (OPA.integer_var) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IFBE: if (OPA.integer_var <= 0) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IFB: if (OPA.integer_var < 0) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IFAE: if (OPA.integer_var >= 0) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IFA: if (OPA.integer_var > 0) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_GOTO: pr->pr_xstatement += (short)st->a - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; break; case OP_JUMP: if (pr_boundscheck->int_val && (OPA.uinteger_var >= pr->progs->numstatements)) { PR_RunError (pr, "Invalid jump destination"); } pr->pr_xstatement = OPA.uinteger_var - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; break; case OP_JUMPB: pointer = st->a + OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; pointer = ptr->integer_var; if (pr_boundscheck->int_val && (pointer >= pr->progs->numstatements)) { PR_RunError (pr, "Invalid jump destination"); } pr->pr_xstatement = pointer - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; break; case OP_RCALL2: case OP_RCALL3: case OP_RCALL4: case OP_RCALL5: case OP_RCALL6: case OP_RCALL7: case OP_RCALL8: pr->pr_params[1] = &OPC; goto op_rcall; case OP_RCALL1: pr->pr_params[1] = pr->pr_real_params[1]; op_rcall: pr->pr_params[0] = &OPB; pr->pr_argc = st->op - OP_RCALL1 + 1; goto op_call; case OP_CALL0: case OP_CALL1: case OP_CALL2: case OP_CALL3: case OP_CALL4: case OP_CALL5: case OP_CALL6: case OP_CALL7: case OP_CALL8: PR_RESET_PARAMS (pr); pr->pr_argc = st->op - OP_CALL0; op_call: pr->pr_xfunction->profile += profile - startprofile; startprofile = profile; PR_CallFunction (pr, OPA.func_var); st = pr->pr_statements + pr->pr_xstatement; break; case OP_DONE: case OP_RETURN: if (!st->a) memset (&R_INT (pr), 0, pr->pr_param_size * sizeof (OPA)); else if (&R_INT (pr) != &OPA.integer_var) memcpy (&R_INT (pr), &OPA, pr->pr_param_size * sizeof (OPA)); // fallthrough case OP_RETURN_V: pr->pr_xfunction->profile += profile - startprofile; startprofile = profile; PR_LeaveFunction (pr); st = pr->pr_statements + pr->pr_xstatement; if (pr->pr_depth == exitdepth) { if (pr->pr_trace && pr->pr_depth <= pr->pr_trace_depth) pr->pr_trace = false; Sys_PopSignalHook (); return; // all done } break; case OP_STATE: ed = PROG_TO_EDICT (pr, *pr->globals.self); ed->v[pr->fields.nextthink].float_var = *pr->globals.time + 0.1; ed->v[pr->fields.frame].float_var = OPA.float_var; ed->v[pr->fields.think].func_var = OPB.func_var; break; case OP_STATE_F: ed = PROG_TO_EDICT (pr, *pr->globals.self); ed->v[pr->fields.nextthink].float_var = *pr->globals.time + OPC.float_var; ed->v[pr->fields.frame].float_var = OPA.float_var; ed->v[pr->fields.think].func_var = OPB.func_var; break; case OP_ADD_I: OPC.integer_var = OPA.integer_var + OPB.integer_var; break; case OP_SUB_I: OPC.integer_var = OPA.integer_var - OPB.integer_var; break; case OP_MUL_I: OPC.integer_var = OPA.integer_var * OPB.integer_var; break; /* case OP_DIV_VF: { float temp = 1.0f / OPB.float_var; VectorScale (OPA.vector_var, temp, OPC.vector_var); } break; */ case OP_DIV_I: OPC.integer_var = OPA.integer_var / OPB.integer_var; break; case OP_MOD_I: OPC.integer_var = OPA.integer_var % OPB.integer_var; break; case OP_MOD_F: OPC.float_var = (int) OPA.float_var % (int) OPB.float_var; break; case OP_CONV_IF: OPC.float_var = OPA.integer_var; break; case OP_CONV_FI: OPC.integer_var = OPA.float_var; break; case OP_BITAND_I: OPC.integer_var = OPA.integer_var & OPB.integer_var; break; case OP_BITOR_I: OPC.integer_var = OPA.integer_var | OPB.integer_var; break; case OP_BITXOR_I: OPC.integer_var = OPA.integer_var ^ OPB.integer_var; break; case OP_BITNOT_I: OPC.integer_var = ~OPA.integer_var; break; case OP_GE_I: case OP_GE_P: OPC.integer_var = OPA.integer_var >= OPB.integer_var; break; case OP_GE_U: OPC.integer_var = OPA.uinteger_var >= OPB.uinteger_var; break; case OP_LE_I: case OP_LE_P: OPC.integer_var = OPA.integer_var <= OPB.integer_var; break; case OP_LE_U: OPC.integer_var = OPA.uinteger_var <= OPB.uinteger_var; break; case OP_GT_I: case OP_GT_P: OPC.integer_var = OPA.integer_var > OPB.integer_var; break; case OP_GT_U: OPC.integer_var = OPA.uinteger_var > OPB.uinteger_var; break; case OP_LT_I: case OP_LT_P: OPC.integer_var = OPA.integer_var < OPB.integer_var; break; case OP_LT_U: OPC.integer_var = OPA.uinteger_var < OPB.uinteger_var; break; case OP_AND_I: OPC.integer_var = OPA.integer_var && OPB.integer_var; break; case OP_OR_I: OPC.integer_var = OPA.integer_var || OPB.integer_var; break; case OP_NOT_I: case OP_NOT_P: OPC.integer_var = !OPA.integer_var; break; case OP_EQ_I: case OP_EQ_P: OPC.integer_var = OPA.integer_var == OPB.integer_var; break; case OP_NE_I: case OP_NE_P: OPC.integer_var = OPA.integer_var != OPB.integer_var; break; case OP_MOVEI: memmove (&OPC, &OPA, st->b * 4); break; case OP_MOVEP: if (pr_boundscheck->int_val) { PR_BoundsCheckSize (pr, OPC.integer_var, OPB.uinteger_var); PR_BoundsCheckSize (pr, OPA.integer_var, OPB.uinteger_var); } memmove (pr->pr_globals + OPC.integer_var, pr->pr_globals + OPA.integer_var, OPB.uinteger_var * 4); break; case OP_MOVEPI: if (pr_boundscheck->int_val) { PR_BoundsCheckSize (pr, OPC.integer_var, st->b); PR_BoundsCheckSize (pr, OPA.integer_var, st->b); } memmove (pr->pr_globals + OPC.integer_var, pr->pr_globals + OPA.integer_var, st->b * 4); break; // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized /* case OP_BOUNDCHECK: if (OPA.integer_var < 0 || OPA.integer_var >= st->b) { PR_RunError (pr, "Progs boundcheck failed at line number " "%d, value is < 0 or >= %d", st->b, st->c); } break; */ default: PR_RunError (pr, "Bad opcode %i", st->op); } if (watch && watch->integer_var != old_val.integer_var && (!pr->wp_conditional || watch->integer_var == pr->wp_val.integer_var)) PR_RunError (pr, "watchpoint hit: %d -> %d", old_val.integer_var, watch->integer_var); } }
float *AttitudeUpdate(float dt,float _beta, float _zeta, float a_x,float a_y, float a_z,float w_x, float w_y, float w_z,float m_x, float m_y, float m_z) { float qConj[4]; float unbiasedGyro[4]; float qDot[4]; float beta,zeta; float F[6]; float J[6*4]; float step[4]; float North,East,Down; float b2,b4; float q1 = q[0]; float q2 = q[1]; float q3 = q[2]; float q4 = q[3]; float _error[4]; float accel[] = {0,-a_x,-a_y,-a_z}; float mag[] = {0,m_x,m_y,m_z}; // Direction cosine matrix from quaternion float qdcm13 = 2.0f*(q2*q4 - q1*q3); float qdcm23 = 2.0f*(q3*q4 + q1*q2); float qdcm33 = 2.0f*(0.5f - q2*q2 - q3*q3); float qdcm12 = 2.0f*(q2*q3 + q1*q4); float qdcm22 = 2.0f*(0.5f - q2*q2 - q4*q4); float qdcm32 = 2.0f*(q3*q4 - q1*q2); float qdcm11 = 2.0f*(0.5f - q3*q3 - q4*q4); float qdcm21 = 2.0f*(q2*q3 - q1*q4); float qdcm31 = 2.0f*(q2*q4 + q1*q3); counter += dt; QuatNormalize(accel); QuatNormalize(mag); // Earth's field North = qdcm11*mag[1] + qdcm21*mag[2] + qdcm31*mag[3]; East = qdcm12*mag[1] + qdcm22*mag[2] + qdcm32*mag[3]; Down = qdcm13*mag[1] + qdcm23*mag[2] + qdcm33*mag[3]; b2 = sqrtf(North*North + East*East); b4 = Down; // 6 x 1 F[0] = qdcm13 - accel[1]; F[1] = qdcm23 - accel[2]; F[2] = qdcm33 - accel[3]; F[3] = b2*qdcm11 + b4*qdcm13 - mag[1]; F[4] = b2*qdcm21 + b4*qdcm23 - mag[2]; F[5] = b2*qdcm31 + b4*qdcm33 - mag[3]; // 6 x 4 J[0] = -2*q3; J[1] = 2*q4; J[2] = -2*q1; J[3] = 2*q2; J[4] = 2*q2; J[5] = 2*q1; J[6] = 2*q4; J[7] = 2*q3; J[8] = 0; J[9] = -4*q2; J[10]= -4*q3; J[11] = 0; J[12]=-2*b4*q3; J[13]= 2*b4*q4; J[14]=-4*b2*q3-2*b4*q1; J[15]= -4*b2*q4+2*b4*q2; J[16]=-2*b2*q4+2*b4*q2; J[17]= 2*b2*q3+2*b4*q1;J[18]= 2*b2*q2+2*b4*q4; J[19]=-2*b2*q1+2*b4*q3; J[20]=2*b2*q3; J[21]= 2*b2*q4-4*b4*q2;J[22]= 2*b2*q1-4*b4*q3; J[23] =2*b2*q2; //float Jt[4*6]; //vDSP_mtrans(J,1,Jt,1,4,6); // step = J'*F // 4 x 6 * 6 x 1 //vDSP_mmul( Jt,1,F,1,step,1,4,1,6); step[0] = J[0]*F[0] + J[4]*F[1] + J[8]*F[2] + J[12]*F[3] + J[16]*F[4] + J[20]*F[5]; step[1] = J[1]*F[0] + J[5]*F[1] + J[9]*F[2] + J[13]*F[3] + J[17]*F[4] + J[21]*F[5]; step[2] = J[2]*F[0] + J[6]*F[1] + J[10]*F[2] + J[14]*F[3] + J[18]*F[4] + J[22]*F[5]; step[3] = J[3]*F[0] + J[7]*F[1] + J[11]*F[2] + J[15]*F[3] + J[19]*F[4] + J[23]*F[5]; // normalize step QuatNormalize(step); qConj[0] = q[0]; qConj[1] = -q[1]; qConj[2]=-q[2]; qConj[3]=-q[3]; // Error QuatMultiply(qConj,step,_error); QuatScale(_error,(2.0f*dt)); // update gyro biases w_bx += zeta*_error[1]; w_by += zeta*_error[2]; w_bz += zeta*_error[3]; // quaternion dynamics unbiasedGyro[0] = 0; unbiasedGyro[1] = (w_x-w_bx); unbiasedGyro[2]= (w_y-w_by); unbiasedGyro[3] = (w_z-w_bz); QuatMultiply(q,unbiasedGyro,qDot); // higher gain during startup if(counter < 5.0f) { beta = 1.0f; zeta = 1.0f; } else { beta = _beta; zeta = _zeta; } qDot[0] = 0.5f*qDot[0] - beta*step[0]; qDot[1] = 0.5f*qDot[1] - beta*step[1]; qDot[2] = 0.5f*qDot[2] - beta*step[2]; qDot[3] = 0.5f*qDot[3] - beta*step[3]; q[0] += qDot[0]*dt; q[1] += qDot[1]*dt; q[2] += qDot[2]*dt; q[3] += qDot[3]*dt; QuatNormalize(q); return q; }
static qboolean load_iqm_anims (model_t *mod, const iqmheader *hdr, byte *buffer) { iqm_t *iqm = (iqm_t *) mod->aliashdr; iqmanim *anims; iqmpose *poses; uint16_t *framedata; uint32_t i, j; if (hdr->num_poses != hdr->num_joints) return false; iqm->num_anims = hdr->num_anims; iqm->anims = malloc (hdr->num_anims * sizeof (iqmanim)); anims = (iqmanim *) (buffer + hdr->ofs_anims); for (i = 0; i < hdr->num_anims; i++) { iqm->anims[i].name = LittleLong (anims[i].name); iqm->anims[i].first_frame = LittleLong (anims[i].first_frame); iqm->anims[i].num_frames = LittleLong (anims[i].num_frames); iqm->anims[i].framerate = LittleFloat (anims[i].framerate); iqm->anims[i].flags = LittleLong (anims[i].flags); } poses = (iqmpose *) (buffer + hdr->ofs_poses); for (i = 0; i < hdr->num_poses; i++) { poses[i].parent = LittleLong (poses[i].parent); poses[i].mask = LittleLong (poses[i].mask); for (j = 0; j < 10; j++) { poses[i].channeloffset[j] = LittleFloat(poses[i].channeloffset[j]); poses[i].channelscale[j] = LittleFloat (poses[i].channelscale[j]); } } framedata = (uint16_t *) (buffer + hdr->ofs_frames); for (i = 0; i < hdr->num_frames * hdr->num_framechannels; i++) framedata[i] = LittleShort (framedata[i]); iqm->num_frames = hdr->num_frames; iqm->frames = malloc (hdr->num_frames * sizeof (iqmframe_t *)); iqm->frames[0] = malloc (hdr->num_frames * hdr->num_poses * sizeof (iqmframe_t)); for (i = 0; i < hdr->num_frames; i++) { iqm->frames[i] = iqm->frames[0] + i * hdr->num_poses; for (j = 0; j < hdr->num_poses; j++) { iqmframe_t *frame = &iqm->frames[i][j]; iqmpose *p = &poses[j]; quat_t rotation; vec3_t scale, translation; mat4_t mat; float ilen; translation[0] = p->channeloffset[0]; if (p->mask & 0x001) translation[0] += *framedata++ * p->channelscale[0]; translation[1] = p->channeloffset[1]; if (p->mask & 0x002) translation[1] += *framedata++ * p->channelscale[1]; translation[2] = p->channeloffset[2]; if (p->mask & 0x004) translation[2] += *framedata++ * p->channelscale[2]; // QF's quaternions are wxyz while IQM's quaternions are xyzw rotation[1] = p->channeloffset[3]; if (p->mask & 0x008) rotation[1] += *framedata++ * p->channelscale[3]; rotation[2] = p->channeloffset[4]; if (p->mask & 0x010) rotation[2] += *framedata++ * p->channelscale[4]; rotation[3] = p->channeloffset[5]; if (p->mask & 0x020) rotation[3] += *framedata++ * p->channelscale[5]; rotation[0] = p->channeloffset[6]; if (p->mask & 0x040) rotation[0] += *framedata++ * p->channelscale[6]; scale[0] = p->channeloffset[7]; if (p->mask & 0x080) scale[0] += *framedata++ * p->channelscale[7]; scale[1] = p->channeloffset[8]; if (p->mask & 0x100) scale[1] += *framedata++ * p->channelscale[8]; scale[2] = p->channeloffset[9]; if (p->mask & 0x200) scale[2] += *framedata++ * p->channelscale[9]; ilen = 1.0 / sqrt(QDotProduct (rotation, rotation)); QuatScale (rotation, ilen, rotation); Mat4Init (rotation, scale, translation, mat); if (p->parent >= 0) Mat4Mult (iqm->baseframe[p->parent], mat, mat); #if 0 Mat4Mult (mat, iqm->inverse_baseframe[j], mat); // convert the matrix to dual quaternion + shear + scale Mat4Decompose (mat, frame->rt.q0.q, frame->shear, frame->scale, frame->rt.qe.sv.v); frame->rt.qe.sv.s = 0; // apply the inverse of scale and shear to translation so // everything works out properly in the shader. // Normally v' = T*Sc*Sh*R*v, but with the dual quaternion, we get // v' = Sc*Sh*T'*R*v VectorCompDiv (frame->rt.qe.sv.v, frame->scale, frame->rt.qe.sv.v); VectorUnshear (frame->shear, frame->rt.qe.sv.v, frame->rt.qe.sv.v); // Dual quaternions need 1/2 translation. VectorScale (frame->rt.qe.sv.v, 0.5, frame->rt.qe.sv.v); // and tranlation * rotation QuatMult (frame->rt.qe.q, frame->rt.q0.q, frame->rt.qe.q); #else Mat4Mult (mat, iqm->inverse_baseframe[j], (float *)frame); #endif } } return true; }