void inDOMView::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, PRInt32 /* unused */) { if (!mTree) return; nsresult rv; nsCOMPtr<nsIDOMNode> childDOMNode(do_QueryInterface(aChild)); nsCOMPtr<nsIDOMNode> parent; if (!mDOMUtils) { mDOMUtils = do_GetService("@mozilla.org/inspector/dom-utils;1"); if (!mDOMUtils) { return; } } mDOMUtils->GetParentForNode(childDOMNode, mShowAnonymous, getter_AddRefs(parent)); // find the inDOMViewNode for the parent of the inserted content PRInt32 parentRow = 0; if (NS_FAILED(rv = NodeToRow(parent, &parentRow))) return; inDOMViewNode* parentNode = nsnull; if (NS_FAILED(rv = RowToNode(parentRow, &parentNode))) return; nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); if (!parentNode->isOpen) { // Parent is not open, so don't bother creating tree rows for the // kids. But do indicate that it's now a container, if needed. if (!parentNode->isContainer) { parentNode->isContainer = PR_TRUE; mTree->InvalidateRow(parentRow); } return; } // get the previous sibling of the inserted content nsCOMPtr<nsIDOMNode> previous; GetRealPreviousSibling(childDOMNode, parent, getter_AddRefs(previous)); inDOMViewNode* previousNode = nsnull; PRInt32 row = 0; if (previous) { // find the inDOMViewNode for the previous sibling of the inserted content PRInt32 previousRow = 0; if (NS_FAILED(rv = NodeToRow(previous, &previousRow))) return; if (NS_FAILED(rv = RowToNode(previousRow, &previousNode))) return; // get the last descendant of the previous row, which is the row // after which to insert this new row GetLastDescendantOf(previousNode, previousRow, &row); ++row; } else { // there is no previous sibling, so the new row will be inserted after the parent row = parentRow+1; } inDOMViewNode* newNode = CreateNode(childDOMNode, parentNode); if (previous) { InsertLinkAfter(newNode, previousNode); } else { PRInt32 firstChildRow; if (NS_SUCCEEDED(GetFirstDescendantOf(parentNode, parentRow, &firstChildRow))) { inDOMViewNode* firstChild; RowToNode(firstChildRow, &firstChild); InsertLinkBefore(newNode, firstChild); } } // insert new node InsertNode(newNode, row); mTree->RowCountChanged(row, 1); }
void inDOMView::AttributeChanged(nsIDocument* aDocument, dom::Element* aElement, PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType) { if (!mTree) { return; } if (!(mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE)) { return; } nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); // get the dom attribute node, if there is any nsCOMPtr<nsIDOMNode> content(do_QueryInterface(aElement)); nsCOMPtr<nsIDOMElement> el(do_QueryInterface(aElement)); nsCOMPtr<nsIDOMAttr> domAttr; nsDependentAtomString attrStr(aAttribute); if (aNameSpaceID) { nsCOMPtr<nsINameSpaceManager> nsm = do_GetService(NS_NAMESPACEMANAGER_CONTRACTID); if (!nsm) { // we can't find out which attribute we want :( return; } nsString attrNS; nsresult rv = nsm->GetNameSpaceURI(aNameSpaceID, attrNS); if (NS_FAILED(rv)) { return; } (void)el->GetAttributeNodeNS(attrNS, attrStr, getter_AddRefs(domAttr)); } else { (void)el->GetAttributeNode(attrStr, getter_AddRefs(domAttr)); } if (aModType == nsIDOMMutationEvent::MODIFICATION) { // No fancy stuff here, just invalidate the changed row if (!domAttr) { return; } PRInt32 row = 0; NodeToRow(domAttr, &row); mTree->InvalidateRange(row, row); } else if (aModType == nsIDOMMutationEvent::ADDITION) { if (!domAttr) { return; } // get the number of attributes on this content node nsCOMPtr<nsIDOMNamedNodeMap> attrs; content->GetAttributes(getter_AddRefs(attrs)); PRUint32 attrCount; attrs->GetLength(&attrCount); inDOMViewNode* contentNode = nsnull; PRInt32 contentRow; PRInt32 attrRow; if (mRootNode == content && !(mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT)) { // if this view has a root node but is not displaying it, // it is ok to act as if the changed attribute is on the root. attrRow = attrCount - 1; } else { if (NS_FAILED(NodeToRow(content, &contentRow))) { return; } RowToNode(contentRow, &contentNode); if (!contentNode->isOpen) { return; } attrRow = contentRow + attrCount; } inDOMViewNode* newNode = CreateNode(domAttr, contentNode); inDOMViewNode* insertNode = nsnull; RowToNode(attrRow, &insertNode); if (insertNode) { if (contentNode && insertNode->level <= contentNode->level) { RowToNode(attrRow-1, &insertNode); InsertLinkAfter(newNode, insertNode); } else InsertLinkBefore(newNode, insertNode); } InsertNode(newNode, attrRow); mTree->RowCountChanged(attrRow, 1); } else if (aModType == nsIDOMMutationEvent::REMOVAL) { // At this point, the attribute is already gone from the DOM, but is still represented // in our mRows array. Search through the content node's children for the corresponding // node and remove it. // get the row of the content node inDOMViewNode* contentNode = nsnull; PRInt32 contentRow; PRInt32 baseLevel; if (NS_SUCCEEDED(NodeToRow(content, &contentRow))) { RowToNode(contentRow, &contentNode); baseLevel = contentNode->level; } else { if (mRootNode == content) { contentRow = -1; baseLevel = -1; } else return; } // search for the attribute node that was removed inDOMViewNode* checkNode = nsnull; PRInt32 row = 0; for (row = contentRow+1; row < GetRowCount(); ++row) { checkNode = GetNodeAt(row); if (checkNode->level == baseLevel+1) { domAttr = do_QueryInterface(checkNode->node); if (domAttr) { nsAutoString attrName; domAttr->GetNodeName(attrName); if (attrName.Equals(attrStr)) { // we have found the row for the attribute that was removed RemoveLink(checkNode); RemoveNode(row); mTree->RowCountChanged(row, -1); break; } } } if (checkNode->level <= baseLevel) break; } } }
void SV_LinkEdict(edict_t *ent) { guard(SV_LinkEdict); int i, j, k; //!! HOOK - move outside ? if (bspfile.type != map_q2) { if (ent->s.modelindex >= 0 && ent->s.modelindex < MAX_MODELS) { // link model hook const char *modelName = sv.configstrings[CS_MODELS + ent->s.modelindex]; if (!strcmp(modelName, "models/objects/dmspot/tris.md2")) { // teleporter (source+target) was found // appPrintf(S_CYAN"teleport: %g %g %g\n", VECTOR_ARG(ent->s.origin)); return; // simply do not link model; trigger entity will be added anyway } } } if (ent->area.prev) SV_UnlinkEdict(ent); // unlink from old position (i.e. relink edict) if (ent == ge->edicts) return; // don't add the world if (!ent->inuse) return; entityHull_t &ex = ents[NUM_FOR_EDICT(ent)]; memset(&ex, 0, sizeof(entityHull_t)); ex.owner = ent; ex.axis.FromEuler(ent->s.angles); // set the size VectorSubtract(ent->bounds.maxs, ent->bounds.mins, ent->size); // encode the size into the entity_state for client prediction if (ent->solid == SOLID_BBOX) { // assume that x/y are equal and symetric i = appRound(ent->bounds.maxs[0] / 8); // z is not symetric j = appRound(-ent->bounds.mins[2] / 8); // and z maxs can be negative... k = appRound((ent->bounds.maxs[2] + 32) / 8); // original Q2 have bounded i/j/k/ with lower margin==1 (for client prediction only); this will // produce incorrect collision test when bbox mins/maxs is (0,0,0) i = bound(i, 0, 31); // mins/maxs[0,1] range is -248..0/0..248 j = bound(j, 0, 31); // mins[2] range is [-248..0] k = bound(k, 0, 63); // maxs[2] range is [-32..472] // if SVF_DEADMONSTER, s.solid should be 0 ent->s.solid = (ent->svflags & SVF_DEADMONSTER) ? 0 : (k<<10) | (j<<5) | i; i *= 8; j *= 8; k *= 8; ex.bounds.mins.Set(-i, -i, -j); ex.bounds.maxs.Set(i, i, k - 32); ex.bounds.GetCenter(ex.center); ex.center.Add(ent->s.origin); ex.model = NULL; ex.radius = VectorDistance(ex.bounds.maxs, ex.bounds.mins) / 2; } else if (ent->solid == SOLID_BSP) { ex.model = sv.models[ent->s.modelindex]; if (!ex.model) Com_DropError("MOVETYPE_PUSH with a non bsp model"); CVec3 v; ex.model->bounds.GetCenter(v); UnTransformPoint(ent->s.origin, ex.axis, v, ex.center); ex.radius = ex.model->radius; ent->s.solid = 31; // a SOLID_BBOX will never create this value (mins=(-248,-248,0) maxs=(248,248,-32)) } else if (ent->solid == SOLID_TRIGGER) { ent->s.solid = 0; // check for model link ex.model = sv.models[ent->s.modelindex]; if (!ex.model) { // model not attached by game, check entstring //?? can optimize: add 'bool spawningEnts', set to 'true' before SpawnEntities() //?? and 'false' after; skip code below when 'false' for (triggerModelLink_t *link = bspfile.modelLinks; link; link = link->next) #define CMP(n) (fabs(ent->s.origin[n] - link->origin[n]) < 0.5f) if (CMP(0) && CMP(1) && CMP(2)) { CBspModel *model = CM_InlineModel(link->modelIdx); VectorSubtract(model->bounds.maxs, ent->s.origin, ent->bounds.maxs); VectorSubtract(model->bounds.mins, ent->s.origin, ent->bounds.mins); break; } #undef CMP } } else ent->s.solid = 0; // set the abs box if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2])) { // expand for rotation for (i = 0; i < 3 ; i++) { ent->absBounds.mins[i] = ex.center[i] - ex.radius; ent->absBounds.maxs[i] = ex.center[i] + ex.radius; } } else { // normal VectorAdd(ent->s.origin, ent->bounds.mins, ent->absBounds.mins); VectorAdd(ent->s.origin, ent->bounds.maxs, ent->absBounds.maxs); } // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch for (i = 0; i < 3; i++) { ent->absBounds.mins[i] -= 1; ent->absBounds.maxs[i] += 1; } // link to PVS leafs ent->num_clusters = 0; ent->zonenum = 0; ent->zonenum2 = 0; // get all leafs, including solids CBspLeaf *leafs[MAX_TOTAL_ENT_LEAFS]; int topnode; int num_leafs = CM_BoxLeafs(ent->absBounds, ARRAY_ARG(leafs), &topnode); // set zones int clusters[MAX_TOTAL_ENT_LEAFS]; for (i = 0; i < num_leafs; i++) { clusters[i] = leafs[i]->cluster; int zone = leafs[i]->zone; if (zone) { // doors may legally straggle two zones, // but nothing should evern need more than that if (ent->zonenum && ent->zonenum != zone) { if (ent->zonenum2 && ent->zonenum2 != zone && sv.state == ss_loading) Com_DPrintf("Object touching 3 zones at %g %g %g\n", VECTOR_ARG(ent->absBounds.mins)); ent->zonenum2 = zone; } else ent->zonenum = zone; } } if (num_leafs >= MAX_TOTAL_ENT_LEAFS) { // assume we missed some leafs, and mark by headnode ent->num_clusters = -1; ent->headnode = topnode; } else { ent->num_clusters = 0; for (i = 0; i < num_leafs; i++) { if (clusters[i] == -1) continue; // not a visible leaf for (j = 0; j < i; j++) if (clusters[j] == clusters[i]) break; if (j == i) { if (ent->num_clusters == MAX_ENT_CLUSTERS) { // assume we missed some leafs, and mark by headnode ent->num_clusters = -1; ent->headnode = topnode; break; } ent->clusternums[ent->num_clusters++] = clusters[i]; } } } // if first time, make sure old_origin is valid if (!ent->linkcount) ent->s.old_origin = ent->s.origin; ent->linkcount++; if (ent->solid == SOLID_NOT) return; // find the first node that the ent's box crosses areanode_t *node = areaNodes; while (node->axis != -1) { if (ent->absBounds.mins[node->axis] > node->dist) node = node->children[0]; else if (ent->absBounds.maxs[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in areanode_t *node2 = node; if (ent->solid == SOLID_TRIGGER) { InsertLinkBefore(ent->area, node->trigEdicts); for ( ; node2; node2 = node2->parent) node2->numTrigEdicts++; } else { InsertLinkBefore(ent->area, node->solidEdicts); for ( ; node2; node2 = node2->parent) node2->numSolidEdicts++; } ex.area = node; unguard; }
void SV_LinkEdict (edict_t *ent) { areanode_t *node; int leafs[MAX_TOTAL_ENT_LEAFS]; int clusters[MAX_TOTAL_ENT_LEAFS]; int num_leafs; int i, j, k; int area; int topnode; if (ent->area.prev) SV_UnlinkEdict (ent); // unlink from old position if (ent == ge->edicts) return; // don't add the world if (!ent->inuse) return; // set the size VectorSubtract (ent->maxs, ent->mins, ent->size); // encode the size into the entity_state for client prediction if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER)) { // assume that x/y are equal and symetric i = ent->maxs[0]/8; if (i<1) i = 1; if (i>31) i = 31; // z is not symetric j = (-ent->mins[2])/8; if (j<1) j = 1; if (j>31) j = 31; // and z maxs can be negative... k = (ent->maxs[2]+32)/8; if (k<1) k = 1; if (k>63) k = 63; ent->s.solid = (k<<10) | (j<<5) | i; } else if (ent->solid == SOLID_BSP) { ent->s.solid = 31; // a solid_bbox will never create this value } else ent->s.solid = 0; // set the abs box if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) ) { // expand for rotation float max, v; int i; max = 0; for (i=0 ; i<3 ; i++) { v =fabs( ent->mins[i]); if (v > max) max = v; v =fabs( ent->maxs[i]); if (v > max) max = v; } for (i=0 ; i<3 ; i++) { ent->absmin[i] = ent->s.origin[i] - max; ent->absmax[i] = ent->s.origin[i] + max; } } else { // normal VectorAdd (ent->s.origin, ent->mins, ent->absmin); VectorAdd (ent->s.origin, ent->maxs, ent->absmax); } // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch ent->absmin[0] -= 1; ent->absmin[1] -= 1; ent->absmin[2] -= 1; ent->absmax[0] += 1; ent->absmax[1] += 1; ent->absmax[2] += 1; // link to PVS leafs ent->num_clusters = 0; ent->areanum = 0; ent->areanum2 = 0; //get all leafs, including solids num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode); // set areas for (i=0 ; i<num_leafs ; i++) { clusters[i] = CM_LeafCluster (leafs[i]); area = CM_LeafArea (leafs[i]); if (area) { // doors may legally straggle two areas, // but nothing should evern need more than that if (ent->areanum && ent->areanum != area) { if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading) Com_DPrintf ("Object touching 3 areas at %f %f %f\n", ent->absmin[0], ent->absmin[1], ent->absmin[2]); ent->areanum2 = area; } else ent->areanum = area; } } if (num_leafs >= MAX_TOTAL_ENT_LEAFS) { // assume we missed some leafs, and mark by headnode ent->num_clusters = -1; ent->headnode = topnode; } else { ent->num_clusters = 0; for (i=0 ; i<num_leafs ; i++) { if (clusters[i] == -1) continue; // not a visible leaf for (j=0 ; j<i ; j++) if (clusters[j] == clusters[i]) break; if (j == i) { if (ent->num_clusters == MAX_ENT_CLUSTERS) { // assume we missed some leafs, and mark by headnode ent->num_clusters = -1; ent->headnode = topnode; break; } ent->clusternums[ent->num_clusters++] = clusters[i]; } } } // if first time, make sure old_origin is valid if (!ent->linkcount) { VectorCopy (ent->s.origin, ent->s.old_origin); } ent->linkcount++; if (ent->solid == SOLID_NOT) return; // find the first node that the ent's box crosses node = sv_areanodes; while (1) { if (node->axis == -1) break; if (ent->absmin[node->axis] > node->dist) node = node->children[0]; else if (ent->absmax[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in if (ent->solid == SOLID_TRIGGER) InsertLinkBefore (&ent->area, &node->trigger_edicts); else InsertLinkBefore (&ent->area, &node->solid_edicts); }
/* =============== SV_LinkEdict =============== */ void SV_LinkEdict (edict_t *ent, qbool touch_triggers) { areanode_t *node; if (ent->area.prev) SV_UnlinkEdict (ent); // unlink from old position if (ent == sv.edicts) return; // don't add the world if (!ent->inuse) return; // set the abs box VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin); VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax); // // to make items easier to pick up and allow them to be grabbed off // of shelves, the abs sizes are expanded // if ((int)ent->v.flags & FL_ITEM) { ent->v.absmin[0] -= 15; ent->v.absmin[1] -= 15; ent->v.absmax[0] += 15; ent->v.absmax[1] += 15; } else { // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch ent->v.absmin[0] -= 1; ent->v.absmin[1] -= 1; ent->v.absmin[2] -= 1; ent->v.absmax[0] += 1; ent->v.absmax[1] += 1; ent->v.absmax[2] += 1; } // link to PVS leafs if (ent->v.modelindex) SV_LinkToLeafs (ent); else ent->num_leafs = 0; if (ent->v.solid == SOLID_NOT) return; // find the first node that the ent's box crosses node = sv_areanodes; while (1) { if (node->axis == -1) break; if (ent->v.absmin[node->axis] > node->dist) node = node->children[0]; else if (ent->v.absmax[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in if (ent->v.solid == SOLID_TRIGGER) InsertLinkBefore (&ent->area, &node->trigger_edicts); else InsertLinkBefore (&ent->area, &node->solid_edicts); // if touch_triggers, touch all entities at this node and decend for more if (touch_triggers) SV_TouchLinks ( ent, sv_areanodes ); }