bool IsInSelection(const EERIE_3DOBJ * obj, size_t vert, ObjSelection tw) { if(!obj || tw == ObjSelection()) return false; const EERIE_SELECTIONS & sel = obj->selections[tw.handleData()]; for(size_t i = 0; i < sel.selected.size(); i++) { if(sel.selected[i] == vert) return true; } return false; }
static bool IsNearSelection(EERIE_3DOBJ * obj, long vert, ObjSelection tw) { if(!obj || tw == ObjSelection() || vert < 0) return false; const EERIE_SELECTIONS & sel = obj->selections[tw.handleData()]; for(size_t i = 0; i < sel.selected.size(); i++) { float d = glm::distance(obj->vertexlist[sel.selected[i]].v, obj->vertexlist[vert].v); if(d < 8.f) return true; } return false; }
static EERIE_3DOBJ * CreateIntermediaryMesh(const EERIE_3DOBJ * obj1, const EERIE_3DOBJ * obj2, long tw) { ObjSelection tw1 = ObjSelection(); ObjSelection tw2 = ObjSelection(); ObjSelection iw1 = ObjSelection(); ObjSelection jw1 = ObjSelection(); ObjSelection sel_head1 = ObjSelection(); ObjSelection sel_head2 = ObjSelection(); ObjSelection sel_torso1 = ObjSelection(); ObjSelection sel_torso2 = ObjSelection(); ObjSelection sel_legs1 = ObjSelection(); ObjSelection sel_legs2 = ObjSelection(); // First we retreive selection groups indexes for(size_t i = 0; i < obj1->selections.size(); i++) { // TODO iterator ObjSelection sel = ObjSelection(i); if(obj1->selections[i].name == "head") { sel_head1 = sel; } else if(obj1->selections[i].name == "chest") { sel_torso1 = sel; } else if(obj1->selections[i].name == "leggings") { sel_legs1 = sel; } } for(size_t i = 0; i < obj2->selections.size(); i++) { // TODO iterator ObjSelection sel = ObjSelection(i); if(obj2->selections[i].name == "head") { sel_head2 = sel; } else if(obj2->selections[i].name == "chest") { sel_torso2 = sel; } else if(obj2->selections[i].name == "leggings") { sel_legs2 = sel; } } if(sel_head1 == ObjSelection()) return NULL; if(sel_head2 == ObjSelection()) return NULL; if(sel_torso1 == ObjSelection()) return NULL; if(sel_torso2 == ObjSelection()) return NULL; if(sel_legs1 == ObjSelection()) return NULL; if(sel_legs2 == ObjSelection()) return NULL; if(tw == TWEAK_HEAD) { tw1 = sel_head1; tw2 = sel_head2; iw1 = sel_torso1; jw1 = sel_legs1; } if(tw == TWEAK_TORSO) { tw1 = sel_torso1; tw2 = sel_torso2; iw1 = sel_head1; jw1 = sel_legs1; } if(tw == TWEAK_LEGS) { tw1 = sel_legs1; tw2 = sel_legs2; iw1 = sel_torso1; jw1 = sel_head1; } if(tw1 == ObjSelection() || tw2 == ObjSelection()) return NULL; // Now Retreives Tweak Action Points { ActionPoint idx_head1 = GetActionPoint(obj1, "head2chest"); if(idx_head1 == ActionPoint()) return NULL; ActionPoint idx_head2 = GetActionPoint(obj2, "head2chest"); if(idx_head2 == ActionPoint()) return NULL; ActionPoint idx_torso1 = GetActionPoint(obj1, "chest2leggings"); if(idx_torso1 == ActionPoint()) return NULL; ActionPoint idx_torso2 = GetActionPoint(obj2, "chest2leggings"); if(idx_torso2 == ActionPoint()) return NULL; } // copy vertices std::vector<EERIE_VERTEX> obj1vertexlist2 = obj1->vertexlist; std::vector<EERIE_VERTEX> obj2vertexlist2 = obj2->vertexlist; // Work will contain the Tweaked object EERIE_3DOBJ * work = new EERIE_3DOBJ; work->pos = obj1->pos; work->angle = obj1->angle; // We reset all data to create a fresh object work->cub = obj1->cub; work->quat = obj1->quat; // Linked objects are linked to this object. if(obj1->linked.size() > obj2->linked.size()) { work->linked = obj1->linked; } else { work->linked = obj2->linked; } // Is the origin of object in obj1 or obj2 ? Retreives it for work object if(IsInSelection(obj1, obj1->origin, tw1)) { work->point0 = obj2->point0; work->origin = ObjectAddVertex(work, &obj2vertexlist2[obj2->origin]); } else { work->point0 = obj1->point0; work->origin = ObjectAddVertex(work, &obj1vertexlist2[obj1->origin]); } // Recreate Action Points included in work object.for Obj1 for(size_t i = 0; i < obj1->actionlist.size(); i++) { const EERIE_ACTIONLIST & action = obj1->actionlist[i]; if( IsInSelection(obj1, action.idx.handleData(), iw1) || IsInSelection(obj1, action.idx.handleData(), jw1) || action.name == "head2chest" || action.name == "chest2leggings" ) { ObjectAddAction(work, action.name, action.act, action.sfx, &obj1vertexlist2[action.idx.handleData()]); } } // Do the same for Obj2 for(size_t i = 0; i < obj2->actionlist.size(); i++) { const EERIE_ACTIONLIST & action = obj2->actionlist[i]; if( IsInSelection(obj2, action.idx.handleData(), tw2) || action.name == "head2chest" || action.name == "chest2leggings" ) { ObjectAddAction(work, action.name, action.act, action.sfx, &obj2vertexlist2[action.idx.handleData()]); } } // Recreate Vertex using Obj1 Vertexes for(size_t i = 0; i < obj1->vertexlist.size(); i++) { if(IsInSelection(obj1, i, iw1) || IsInSelection(obj1, i, jw1)) { ObjectAddVertex(work, &obj1vertexlist2[i]); } } // The same for Obj2 for(size_t i = 0; i < obj2->vertexlist.size(); i++) { if(IsInSelection(obj2, i, tw2)) { ObjectAddVertex(work, &obj2vertexlist2[i]); } } // Look in Faces for forgotten Vertexes... AND // Re-Create TextureContainers Infos // We look for texturecontainers included in the future tweaked object TextureContainer * tc = NULL; for(size_t i = 0; i < obj1->facelist.size(); i++) { const EERIE_FACE & face = obj1->facelist[i]; if( (IsInSelection(obj1, face.vid[0], iw1) || IsInSelection(obj1, face.vid[0], jw1)) && (IsInSelection(obj1, face.vid[1], iw1) || IsInSelection(obj1, face.vid[1], jw1)) && (IsInSelection(obj1, face.vid[2], iw1) || IsInSelection(obj1, face.vid[2], jw1)) ) { if(face.texid != -1) { if(tc != obj1->texturecontainer[face.texid]) { tc = obj1->texturecontainer[face.texid]; ObjectAddMap(work, tc); } } ObjectAddFace(work, &face, obj1); } } for(size_t i = 0; i < obj2->facelist.size(); i++) { const EERIE_FACE & face = obj2->facelist[i]; if( IsInSelection(obj2, face.vid[0], tw2) || IsInSelection(obj2, face.vid[1], tw2) || IsInSelection(obj2, face.vid[2], tw2) ) { if(face.texid != -1) { if(tc != obj2->texturecontainer[face.texid]) { tc = obj2->texturecontainer[face.texid]; ObjectAddMap(work, tc); } } ObjectAddFace(work, &face, obj2); } } // Recreate Groups work->grouplist.resize(std::max(obj1->grouplist.size(), obj2->grouplist.size())); for(size_t k = 0; k < obj1->grouplist.size(); k++) { const VertexGroup & grp = obj1->grouplist[k]; work->grouplist[k].name = grp.name; long v = GetEquivalentVertex(work, &obj1vertexlist2[grp.origin]); if(v >= 0) { work->grouplist[k].siz = grp.siz; if(IsInSelection(obj1, grp.origin, iw1) || IsInSelection(obj1, grp.origin, jw1)) work->grouplist[k].origin = v; } } for(size_t k = 0; k < obj2->grouplist.size(); k++) { if(k >= obj1->grouplist.size()) { work->grouplist[k].name = obj2->grouplist[k].name; } long v = GetEquivalentVertex(work, &obj2vertexlist2[obj2->grouplist[k].origin]); if(v >= 0) { work->grouplist[k].siz = obj2->grouplist[k].siz; if(IsInSelection(obj2, obj2->grouplist[k].origin, tw2)) work->grouplist[k].origin = v; } } // Recreate Selection Groups (only the 3 selections needed to reiterate MeshTweaking !) work->selections.resize(3); work->selections[0].name = "head"; work->selections[1].name = "chest"; work->selections[2].name = "leggings"; // Re-Creating sel_head if(tw == TWEAK_HEAD) { const EERIE_SELECTIONS & sel = obj2->selections[sel_head2.handleData()]; for(size_t l = 0; l < sel.selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj2vertexlist2[sel.selected[l]].v; long t = GetEquivalentVertex(work, &temp); if(t != -1) { ObjectAddSelection(work, 0, t); } } } else { const EERIE_SELECTIONS & sel = obj1->selections[sel_head1.handleData()]; for(size_t l = 0; l < sel.selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj1vertexlist2[sel.selected[l]].v; long t = GetEquivalentVertex(work, &temp); if(t != -1) { ObjectAddSelection(work, 0, t); } } } // Re-Create sel_torso if(tw == TWEAK_TORSO) { const EERIE_SELECTIONS & sel = obj2->selections[sel_torso2.handleData()]; for(size_t l = 0; l < sel.selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj2vertexlist2[sel.selected[l]].v; long t = GetEquivalentVertex(work, &temp); if(t != -1) { ObjectAddSelection(work, 1, t); } } } else { const EERIE_SELECTIONS & sel = obj1->selections[sel_torso1.handleData()]; for(size_t l = 0; l < sel.selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj1vertexlist2[sel.selected[l]].v; long t = GetEquivalentVertex(work, &temp); if(t != -1) { ObjectAddSelection(work, 1, t); } } } // Re-Create sel_legs if(tw == TWEAK_LEGS) { const EERIE_SELECTIONS & sel = obj2->selections[sel_legs2.handleData()]; for(size_t l = 0; l < sel.selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj2vertexlist2[sel.selected[l]].v; long t = GetEquivalentVertex(work, &temp); if(t != -1) { ObjectAddSelection(work, 2, t); } } } else { const EERIE_SELECTIONS & sel = obj1->selections[sel_legs1.handleData()]; for(size_t l = 0; l < sel.selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj1vertexlist2[sel.selected[l]].v; long t = GetEquivalentVertex(work, &temp); if(t != -1) { ObjectAddSelection(work, 2, t); } } } //Now recreates other selections... for(size_t i = 0; i < obj1->selections.size(); i++) { if(EERIE_OBJECT_GetSelection(work, obj1->selections[i].name) == ObjSelection()) { size_t num = work->selections.size(); work->selections.resize(num + 1); work->selections[num].name = obj1->selections[i].name; for(size_t l = 0; l < obj1->selections[i].selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj1vertexlist2[obj1->selections[i].selected[l]].v; long t = GetEquivalentVertex(work, &temp); if (t != -1) { ObjectAddSelection(work, num, t); } } ObjSelection ii = EERIE_OBJECT_GetSelection(obj2, obj1->selections[i].name); if(ii != ObjSelection()) { const EERIE_SELECTIONS & sel = obj2->selections[ii.handleData()]; for(size_t l = 0; l < sel.selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj2vertexlist2[sel.selected[l]].v; long t = GetEquivalentVertex(work, &temp); if(t != -1) { ObjectAddSelection(work, num, t); } } } } } for(size_t i = 0; i < obj2->selections.size(); i++) { if(EERIE_OBJECT_GetSelection(work, obj2->selections[i].name) == ObjSelection()) { size_t num = work->selections.size(); work->selections.resize(num + 1); work->selections[num].name = obj2->selections[i].name; for(size_t l = 0; l < obj2->selections[i].selected.size(); l++) { EERIE_VERTEX temp; temp.v = obj2vertexlist2[obj2->selections[i].selected[l]].v; long t = GetEquivalentVertex(work, &temp); if(t != -1) { ObjectAddSelection(work, num, t); } } } } // Recreate Animation-groups vertex for(size_t i = 0; i < obj1->grouplist.size(); i++) { for(size_t j = 0; j < obj1->grouplist[i].indexes.size(); j++) { AddVertexToGroup(work, i, &obj1vertexlist2[obj1->grouplist[i].indexes[j]]); } } for(size_t i = 0; i < obj2->grouplist.size(); i++) { for(size_t j = 0; j < obj2->grouplist[i].indexes.size(); j++) { AddVertexToGroup(work, i, &obj2vertexlist2[obj2->grouplist[i].indexes[j]]); } } work->vertexWorldPositions.resize(work->vertexlist.size()); work->vertexClipPositions.resize(work->vertexlist.size()); work->vertexColors.resize(work->vertexlist.size()); return work; }
/*! * \brief Spawns a body part from NPC * \param ioo * \param num */ static void ARX_NPC_SpawnMember(Entity * ioo, ObjSelection num) { if(!ioo) return; EERIE_3DOBJ * from = ioo->obj; if(!from || num == ObjSelection() || (size_t)num.handleData() >= from->selections.size()) return; EERIE_3DOBJ * nouvo = new EERIE_3DOBJ; if(!nouvo) return; size_t nvertex = from->selections[num.handleData()].selected.size(); long gore = -1; for(size_t k = 0; k < from->texturecontainer.size(); k++) { if(from->texturecontainer[k] && boost::contains(from->texturecontainer[k]->m_texName.string(), "gore")) { gore = k; break; } } for(size_t k = 0; k < from->facelist.size(); k++) { if(from->facelist[k].texid == gore) { if( IsNearSelection(from, from->facelist[k].vid[0], num) || IsNearSelection(from, from->facelist[k].vid[1], num) || IsNearSelection(from, from->facelist[k].vid[2], num) ) { nvertex += 3; } } } nouvo->vertexlist.resize(nvertex); nouvo->vertexlist3.resize(nvertex); long inpos = 0; long * equival = (long *)malloc(sizeof(long) * from->vertexlist.size()); if(!equival) { delete nouvo; return; } for(size_t k = 0; k < from->vertexlist.size(); k++) { equival[k] = -1; } const EERIE_SELECTIONS & cutSelection = from->selections[num.handleData()]; arx_assert(0 < cutSelection.selected.size()); for(size_t k = 0; k < cutSelection.selected.size(); k++) { inpos = cutSelection.selected[k]; equival[cutSelection.selected[k]] = k; nouvo->vertexlist[k] = from->vertexlist[cutSelection.selected[k]]; nouvo->vertexlist[k].v = from->vertexlist3[cutSelection.selected[k]].v; nouvo->vertexlist[k].v -= ioo->pos; nouvo->vertexlist[k].vert.p = nouvo->vertexlist[k].v; nouvo->vertexlist[k].vert.color = from->vertexlist[k].vert.color; nouvo->vertexlist[k].vert.uv = from->vertexlist[k].vert.uv; nouvo->vertexlist3[k] = nouvo->vertexlist[k]; } size_t count = cutSelection.selected.size(); for(size_t k = 0; k < from->facelist.size(); k++) { if(from->facelist[k].texid == gore) { if( IsNearSelection(from, from->facelist[k].vid[0], num) || IsNearSelection(from, from->facelist[k].vid[1], num) || IsNearSelection(from, from->facelist[k].vid[2], num) ) { for(long j = 0; j < 3; j++) { equival[from->facelist[k].vid[j]] = count; if(count < nouvo->vertexlist.size()) { nouvo->vertexlist[count] = from->vertexlist[from->facelist[k].vid[j]]; nouvo->vertexlist[count].v = from->vertexlist3[from->facelist[k].vid[j]].v; nouvo->vertexlist[count].v -= ioo->pos; nouvo->vertexlist[count].vert.p = nouvo->vertexlist[count].v; nouvo->vertexlist3[count] = nouvo->vertexlist[count]; } else { equival[from->facelist[k].vid[j]] = -1; } count++; } } } } float min = nouvo->vertexlist[0].vert.p.y; long nummm = 0; for(size_t k = 1; k < nouvo->vertexlist.size(); k++) { if(nouvo->vertexlist[k].vert.p.y > min) { min = nouvo->vertexlist[k].vert.p.y; nummm = k; } } nouvo->origin = nummm; nouvo->point0 = nouvo->vertexlist[nouvo->origin].v; for(size_t k = 0; k < nouvo->vertexlist.size(); k++) { nouvo->vertexlist[k].vert.p = nouvo->vertexlist[k].v -= nouvo->point0; nouvo->vertexlist[k].vert.color = Color(255, 255, 255, 255).toRGBA(); } nouvo->point0 = Vec3f_ZERO; nouvo->pbox = NULL; nouvo->pdata = NULL; nouvo->cdata = NULL; nouvo->sdata = NULL; nouvo->ndata = NULL; size_t nfaces = 0; for(size_t k = 0; k < from->facelist.size(); k++) { if( equival[from->facelist[k].vid[0]] != -1 && equival[from->facelist[k].vid[1]] != -1 && equival[from->facelist[k].vid[2]] != -1 ) { nfaces++; } } if(nfaces) { nouvo->facelist.reserve(nfaces); for(size_t k = 0; k < from->facelist.size(); k++) { if( equival[from->facelist[k].vid[0]] != -1 && equival[from->facelist[k].vid[1]] != -1 && equival[from->facelist[k].vid[2]] != -1 ) { EERIE_FACE newface = from->facelist[k]; newface.vid[0] = (unsigned short)equival[from->facelist[k].vid[0]]; newface.vid[1] = (unsigned short)equival[from->facelist[k].vid[1]]; newface.vid[2] = (unsigned short)equival[from->facelist[k].vid[2]]; nouvo->facelist.push_back(newface); } } long gore = -1; for(size_t k = 0; k < from->texturecontainer.size(); k++) { if(from->texturecontainer[k] && boost::contains(from->texturecontainer[k]->m_texName.string(), "gore") ) { gore = k; break; } } for(size_t k = 0; k < nouvo->facelist.size(); k++) { nouvo->facelist[k].facetype &= ~POLY_HIDE; if(nouvo->facelist[k].texid == gore) { nouvo->facelist[k].facetype |= POLY_DOUBLESIDED; } } } free(equival); nouvo->texturecontainer = from->texturecontainer; nouvo->linked.clear(); nouvo->originaltextures = NULL; Entity * io = new Entity("noname", EntityInstance(0)); io->_itemdata = new IO_ITEMDATA(); io->ioflags = IO_ITEM | IO_NOSAVE | IO_MOVABLE; io->script.size = 0; io->script.data = NULL; io->gameFlags |= GFLAG_NO_PHYS_IO_COL; EERIE_COLLISION_Cylinder_Create(io); EERIE_PHYSICS_BOX_Create(nouvo); if(!nouvo->pbox){ delete nouvo; return; } io->infracolor = Color3f::blue * 0.8f; io->collision = COLLIDE_WITH_PLAYER; io->m_icon = NULL; io->scriptload = 1; io->obj = nouvo; io->lastpos = io->initpos = io->pos = ioo->obj->vertexlist3[inpos].v; io->angle = ioo->angle; io->gameFlags = ioo->gameFlags; io->halo = ioo->halo; io->angle.setYaw(Random::getf(340.f, 380.f)); io->angle.setPitch(Random::getf(0.f, 360.f)); io->angle.setRoll(0); io->obj->pbox->active = 1; io->obj->pbox->stopcount = 0; io->velocity = Vec3f_ZERO; io->stopped = 1; Vec3f vector; vector.x = -std::sin(glm::radians(io->angle.getPitch())); vector.y = std::sin(glm::radians(io->angle.getYaw())) * 2.f; vector.z = std::cos(glm::radians(io->angle.getPitch())); vector = glm::normalize(vector); io->rubber = 0.6f; io->no_collide = ioo->index(); io->gameFlags |= GFLAG_GOREEXPLODE; io->animBlend.lastanimtime = arxtime.now_ul(); io->soundtime = 0; io->soundcount = 0; EERIE_PHYSICS_BOX_Launch(io->obj, io->pos, io->angle, vector); }
void ARX_NPC_TryToCutSomething(Entity * target, const Vec3f * pos) { //return; if(!target || !(target->ioflags & IO_NPC)) return; if(target->gameFlags & GFLAG_NOGORE) return; float mindistSqr = std::numeric_limits<float>::max(); ObjSelection numsel = ObjSelection(); long goretex = -1; for(size_t i = 0; i < target->obj->texturecontainer.size(); i++) { if(target->obj->texturecontainer[i] && boost::contains(target->obj->texturecontainer[i]->m_texName.string(), "gore") ) { goretex = i; break; } } for(size_t i = 0; i < target->obj->selections.size(); i++) { ObjSelection sel = ObjSelection(i); if(target->obj->selections[i].selected.size() > 0 && boost::contains(target->obj->selections[i].name, "cut_") ) { DismembermentFlag fll = GetCutFlag(target->obj->selections[i].name); if(IsAlreadyCut(target, fll)) continue; long out = 0; for(size_t ll = 0; ll < target->obj->facelist.size(); ll++) { EERIE_FACE & face = target->obj->facelist[ll]; if(face.texid != goretex) { if( IsInSelection(target->obj, face.vid[0], sel) || IsInSelection(target->obj, face.vid[1], sel) || IsInSelection(target->obj, face.vid[2], sel) ) { if(face.facetype & POLY_HIDE) { out++; } } } } if(out < 3) { float dist = glm::distance2(*pos, target->obj->vertexlist3[target->obj->selections[i].selected[0]].v); if(dist < mindistSqr) { mindistSqr = dist; numsel = sel; } } } } if(numsel == ObjSelection()) return; // Nothing to cut... bool hid = false; if(mindistSqr < square(60)) { // can only cut a close part... DismembermentFlag fl = GetCutFlag( target->obj->selections[numsel.handleData()].name ); if(fl && !(target->_npcdata->cuts & fl)) { target->_npcdata->cuts |= fl; hid = ARX_NPC_ApplyCuts(target); } } if(hid) { ARX_SOUND_PlayCinematic("flesh_critical", false); // TODO why play cinmeatic sound? ARX_NPC_SpawnMember(target, numsel); } }