/* =========== Vis_Main =========== */ int Vis_Main( int argc, char **argv ) { int i; double start, end; printf ("---- vis ----\n"); fastvis = false; verbose = false; rvis = true; noambientslime = true; noreuse = false; farplane = 0; if (ismcbsp) noambient = true; for (i=1 ; i<argc ; i++) { if (!strcmp(argv[i], "-norvis")) { rvis = false; printf ("rvis optimization disabled\n"); } else if (!strcmp(argv[i], "-fast")) { printf ("fastvis = true\n"); fastvis = true; } else if (!strcmp(argv[i], "-level")) { testlevel = atoi(argv[i+1]); printf ("testlevel = %i\n", testlevel); i++; } else if (!strcmp(argv[i], "-v")) { printf ("verbose = true\n"); verbose = true; } else if (!strcmp(argv[i], "-noreuse")) { printf ("vis rows reusage disabled\n"); noreuse = true; } else if (!strcmp(argv[i], "-noambient")) { noambient = true; printf ("all ambient sounds disabled\n"); } else if (!strcmp(argv[i], "-noambientwater")) { noambientwater = true; printf ("ambient water sounds disabled\n"); } else if (!strcmp(argv[i], "-ambientslime")) { noambientslime = false; printf ("ambient slime sounds enabled\n"); } else if (!strcmp(argv[i], "-noambientlava")) { noambientlava = true; printf ("ambient lava sounds disabled\n"); } else if (!strcmp(argv[i], "-noambientsky")) { noambientsky = true; printf ("ambient sky sounds disabled\n"); } else if (!strcmp(argv[i], "-farplane")) { farplane = atoi (argv[i+1]); printf ("farplane = %f\n", farplane); i++; } else if (argv[i][0] == '-') Error ("Unknown option \"%s\"", argv[i]); else break; } if (i != argc - 1) { Error ("%s", "usage: hmap2 -vis [options] bspfile\n" "Compiles visibility data in a .bsp, needs a .prt file\n" "\n" "What the options do:\n" "-level 0-4 quality, default 4\n" "-fast fast but bad quality vis\n" "-v verbose\n" "-norvis disable rvis optimization, 0.001% better quality and 30% slower\n" "-ambientslime do not convert slime channel to water (requires engine support)\n" "-noambient disable ambient sounds (water bubbling, wind, etc)\n" "-noambientwater disable ambient water sounds (water)\n" "-noambientslime disable ambient slime sounds (water, or -ambientslime)\n" "-noambientlava disable ambient lava sounds (unused by quake)\n" "-noambientsky disable ambient sky sounds (wind)\n" "-noreuse disable merging of identical vis data (less compression)\n" "-farplane limit visible distance (warning: not a good idea without fog)\n" ); } // init memory Q_InitMem (); start = I_DoubleTime (); LoadBSPFile (filename_bsp); LoadPortals (filename_prt); uncompressed = qmalloc(bitlongs*portalleafs*sizeof(long)); memset (uncompressed, 0, bitlongs*portalleafs*sizeof(long)); // CalcPassages (); CalcVis (); printf ("row size: %i\n",bitbytes); printf ("c_reused: %i\n",c_reused); printf ("c_chains: %i\n",c_chains); visdatasize = vismap_p - dvisdata; printf ("reused bytes: %i\n",c_reused*bitbytes); printf ("visdatasize:%i compressed from %i\n", visdatasize, originalvismapsize); if (!noambient) CalcAmbientSounds (); WriteBSPFile (filename_bsp, false); // unlink (portalfile); end = I_DoubleTime (); printf ("%5.2f seconds elapsed\n\n", end-start); // print memory stats Q_PrintMem (); // free allocated memory Q_ShutdownMem (); return 0; }
/*---------------------------------------------------------------------------*/ int parse_select_query(qmessage_header_t * qm_header) { int size; int i; char parsing_failed; smessage_header_t * smsg_header; squery_data_t * squery_data; field_t * field; field_data_t * field_data, * fd_tmp; expression_t * expr; expression_data_t * expr_data; qtable_entry_t * qtable_entry; smsg_header = (smessage_header_t *)(qm_header + 1); /* Check whether a query with same id and same query root exists. */ if(get_query_entry(qm_header->qid, &qm_header->qroot)) { PRINTF("[DEBUG]: A Query exists with the same id and same root.\n"); return -1; } /* the memory size needed to be allocated. */ parsing_failed = FALSE; size = sizeof(squery_data_t) + (smsg_header->nfields * sizeof(field_data_t)) + (smsg_header->nexprs * sizeof(expression_data_t)); /* Allocate memory for the SELECT query. */ squery_data = (squery_data_t *)qmalloc(size); if(squery_data == NULL) { PRINTF("[DEBUG]: Can not allocate memory. query_id %d\n", qm_header->qid); return -1; } /* set SELECT query header infomations. */ squery_data->qid = qm_header->qid; squery_data->nfields = smsg_header->nfields; squery_data->nexprs = smsg_header->nexprs; squery_data->in_buffer_id = smsg_header->in_buffer; squery_data->out_buffer_id = smsg_header->out_buffer; memcpy(&squery_data->epoch_duration, &smsg_header->epoch_duration, sizeof(nw_uint16_t)); memcpy(&squery_data->nepochs, &smsg_header->nepochs, sizeof(nw_uint16_t)); memset(&squery_data->current_epoch, 0, sizeof(nw_uint16_t)); /* store field data. */ field = (field_t *)(smsg_header + 1); field_data = (field_data_t *)(squery_data + 1); for(i=0; i<squery_data->nfields; i++, field++, field_data++) { field_data->id = field->id; field_data->in_result = field->in_result; field_data->op = field->op; /* fill data value with zero */ memset(&field_data->data, 0, sizeof(attr_data_t)); } /* store expressions */ expr = (expression_t *)(field); expr_data = (expression_data_t *)(field_data); for(i=0; i<squery_data->nexprs; i++, expr++, expr_data++) { fd_tmp = ((field_data_t *)(squery_data + 1)) + expr->l_value_index; if(!get_attr_entry(fd_tmp->id)) { parsing_failed = TRUE; PRINTF("[DEBUG]: Error! Found unsupported attribute. attribute_id %d\n", fd_tmp->id); break; } expr_data->l_valuep = fd_tmp; expr_data->op = expr->op; /* copy right value data */ memcpy(expr_data->r_value.data_bytes, expr->r_value.data_bytes, ATTR_DATA_SIZE); } if(parsing_failed) { qfree(squery_data); PRINTF("[DEBUG]: Parsing SELECT query failed. query_id %d\n", qm_header->qid); return -1; } print_squery(squery_data); qtable_entry = add_query_entry(squery_data->qid, QTYPE_SELECT, squery_data, &qm_header->qroot); if(!qtable_entry) { qfree(squery_data); PRINTF("[DEBUG]: Error adding to query table. query_id %d\n", qm_header->qid); return -1; } ctimer_set(&squery_data->timer, CLOCK_SECOND * ntoh_leuint16(&squery_data->epoch_duration), execute_select_query, qtable_entry); return 0; }
sep_t *Findpassages (viswinding_t *source, viswinding_t *pass) { int i, j, k, l; plane_t plane; vec3_t v1, v2; double d; double length; int counts[3]; qboolean fliptest; sep_t *sep, *list; list = NULL; // hush warnings about uninitialized plane.type (which isn't used here) memset(&plane, 0, sizeof(plane)); // check all combinations for (i=0 ; i<source->numpoints ; i++) { l = (i+1)%source->numpoints; VectorSubtract (source->points[l] , source->points[i], v1); // fing a vertex of pass that makes a plane that puts all of the // vertexes of pass on the front side and all of the vertexes of // source on the back side for (j=0 ; j<pass->numpoints ; j++) { VectorSubtract (pass->points[j], source->points[i], v2); CrossProduct(v1, v2, plane.normal); // if points don't make a valid plane, skip it length = DotProduct( plane.normal, plane.normal ); if (length < ON_EPSILON) continue; length = 1/sqrt(length); VectorScale( plane.normal, length, plane.normal ); plane.dist = DotProduct (pass->points[j], plane.normal); // // find out which side of the generated seperating plane has the // source portal // fliptest = false; for (k=0 ; k<source->numpoints ; k++) { if (k == i || k == l) continue; d = DotProduct (source->points[k], plane.normal) - plane.dist; if (d < -ON_EPSILON) { // source is on the negative side, so we want all // pass and target on the positive side fliptest = false; break; } else if (d > ON_EPSILON) { // source is on the positive side, so we want all // pass and target on the negative side fliptest = true; break; } } if (k == source->numpoints) continue; // planar with source portal // // flip the normal if the source portal is backwards // if (fliptest) { VectorNegate (plane.normal, plane.normal); plane.dist = -plane.dist; } // // if all of the pass portal points are now on the positive side, // this is the seperating plane // counts[0] = counts[1] = counts[2] = 0; for (k=0 ; k<pass->numpoints ; k++) { if (k==j) continue; d = DotProduct (pass->points[k], plane.normal) - plane.dist; if (d < -ON_EPSILON) break; else if (d > ON_EPSILON) counts[0]++; else counts[2]++; } if (k != pass->numpoints) continue; // points on negative side, not a seperating plane if (!counts[0]) continue; // planar with pass portal // // save this out // count_sep++; sep = qmalloc(sizeof(*sep)); sep->next = list; list = sep; sep->plane = plane; } } return list; }
/* ============ LoadPortals ============ */ void LoadPortals (char *name) { int i, j; portal_t *p; leaf_t *l; char magic[80]; FILE *f; int numpoints; viswinding_t *w; int leafnums[2]; plane_t plane; vec3_t origin; vec_t radius; if (!strcmp(name,"-")) f = stdin; else { f = fopen(name, "r"); if (!f) Error ("LoadPortals: couldn't read %s\n",name); } if (fscanf (f,"%79s\n%i\n%i\n",magic, &portalleafs, &numportals) != 3) Error ("LoadPortals: failed to read header"); if (strcmp(magic,PORTALFILE)) Error ("LoadPortals: not a portal file"); printf ("%4i portalleafs\n", portalleafs); printf ("%4i numportals\n", numportals); bitbytes = (portalleafs+7)>>3; bitlongs = (portalleafs+(8*sizeof(long)-1))/(8*sizeof(long)); // each file portal is split into two memory portals portals = qmalloc(2*numportals*sizeof(portal_t)); memset (portals, 0, 2*numportals*sizeof(portal_t)); leafs = qmalloc(portalleafs*sizeof(leaf_t)); memset (leafs, 0, portalleafs*sizeof(leaf_t)); originalvismapsize = portalleafs*((portalleafs+7)/8); vismap = vismap_p = dvisdata; vismap_end = vismap + MAX_MAP_VISIBILITY; for (i=0, p=portals ; i<numportals ; i++) { if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3) Error ("LoadPortals: reading portal %i", i); if (numpoints > MAX_POINTS_ON_VISWINDING) Error ("LoadPortals: portal %i has too many points", i); if ((unsigned)leafnums[0] > (unsigned)portalleafs || (unsigned)leafnums[1] > (unsigned)portalleafs) Error ("LoadPortals: reading portal %i", i); w = p->winding = NewVisWinding (numpoints); w->original = true; w->numpoints = numpoints; for (j=0 ; j<numpoints ; j++) { double v[3]; int k; // scanf into double, then assign to vec_t if (fscanf (f, "(%lf %lf %lf ) ", &v[0], &v[1], &v[2]) != 3) Error ("LoadPortals: reading portal %i", i); for (k=0 ; k<3 ; k++) w->points[j][k] = v[k]; } fscanf (f, "\n"); // calc plane PlaneFromVisWinding (w, &plane); // calc origin and radius VisWindingCentre (w, origin, &radius); // create forward portal l = &leafs[leafnums[0]]; if (l->numportals == MAX_PORTALS_ON_LEAF) Error ("Leaf with too many portals"); l->portals[l->numportals] = p; l->numportals++; p->winding = w; VectorCopy (origin, p->origin); p->radius = radius; VectorNegate (plane.normal, p->plane.normal); p->plane.dist = -plane.dist; if (p->plane.normal[0] == 1) p->plane.type = PLANE_X; else if (p->plane.normal[1] == 1) p->plane.type = PLANE_Y; else if (p->plane.normal[2] == 1) p->plane.type = PLANE_Z; else p->plane.type = PLANE_ANYX; p->leaf = leafnums[1]; p++; // create backwards portal l = &leafs[leafnums[1]]; if (l->numportals == MAX_PORTALS_ON_LEAF) Error ("Leaf with too many portals"); l->portals[l->numportals] = p; l->numportals++; p->winding = w; VectorCopy (origin, p->origin); p->radius = radius; p->plane = plane; if (p->plane.normal[0] == 1) p->plane.type = PLANE_X; else if (p->plane.normal[1] == 1) p->plane.type = PLANE_Y; else if (p->plane.normal[2] == 1) p->plane.type = PLANE_Z; else p->plane.type = PLANE_ANYX; p->leaf = leafnums[0]; p++; } fclose (f); }
qboolean Eclass_hasModel(eclass_t *e, vec3_t &vMin, vec3_t &vMax) { if (e->modelpath != NULL) { if (e->model == NULL) { e->model = reinterpret_cast<entitymodel_t*>(qmalloc(sizeof(entitymodel_t))); } char *pModelBuff = strdup(e->modelpath); char *pSkinBuff = NULL; if (e->skinpath) { pSkinBuff = strdup(e->skinpath); } CStringList Models; CStringList Skins; char* pToken = strtok(pModelBuff, ";\0"); while (pToken != NULL) { Models.AddTail(pToken); pToken = strtok(NULL, ";\0"); } if (pSkinBuff != NULL) { pToken = strtok(pSkinBuff, ";\0"); while (pToken != NULL) { Skins.AddTail(pToken); pToken = strtok(NULL, ";\0"); } } entitymodel *model = e->model; int i = 0; for (; i < Models.GetCount(); i++) { char *pSkin = NULL; if (i < Skins.GetCount()) { pSkin = Skins.GetAt(Skins.FindIndex(i)).GetBuffer(0); } LoadModel(Models.GetAt(Models.FindIndex(i)), e, vMin, vMax, model, pSkin); model->pNext = reinterpret_cast<entitymodel_t*>(qmalloc(sizeof(entitymodel_t))); model = model->pNext; } // at this poitn vMin and vMax contain the min max of the model // which needs to be centered at origin 0, 0, 0 VectorSnap(vMin); VectorSnap(vMax); if (vMax[0] - vMin[0] < 2) { vMin[0] -= 1; vMax[0] += 1; } if (vMin[1] - vMax[1] < 2) { vMin[1] -= 1; vMax[1] += 1; } if (vMax[2] - vMin[2] < 2) { vMax[2] -= 1; vMax[2] += 1; } vec3_t vTemp; VectorAdd(vMin, vMax, vTemp); VectorScale(vTemp, 0.5, vTemp); model = e->model; while (model != NULL) { for (i = 0; i < model->nTriCount; i++) { for (int j = 0; j < 3; j++) { ;//VectorSubtract(model->pTriList[i].v[j], vTemp, model->pTriList[i].v[j]); } } model = model->pNext; } free(pModelBuff); free(e->modelpath); e->modelpath = NULL; if(e->skinpath) { free(e->skinpath); e->skinpath = NULL; free(pSkinBuff); } } return (e->model != NULL && e->model->nTriCount > 0); }
void DoTower(void) { brush_t* brush1 = NULL; brush_t* brush2 = NULL; brush_t* newBrush = NULL; brush_t* tempBrush = NULL; face_t* topFace = NULL; face_t* bottomFace = NULL; face_t* curFace; face_t* faceList; int zFlag = 0; int i = 0; // loop counter if (g_qeglobals.d_select_count != 2) { Sys_Printf ("Error: you must have exactly 2 brushes selected\n"); Sys_Beep (); return; } brush1 = selected_brushes.next; brush2 = selected_brushes.next->next; // establish brush1 as the upper brush if (brush2->maxs[2] > brush1->mins[2]) { tempBrush = brush1; brush1 = brush2; brush2 = tempBrush; } // test to insure brushes do not "overlap" in the Z direction if (brush2->maxs[2] > brush1->mins[2]) { Sys_Printf ("Brushes are not separated in the Z direction!"); Sys_Beep(); return; } // find the bottom Z plane (topFace) in 1 and top Z plane in 2 (bottomFace) topFace = brush1->brush_faces; while (topFace != NULL) { zFlag = 0; for (i = 0; i<3; i++) { if (abs(topFace->planepts[i][2] - brush1->mins[2]) < TOWER_EPSILON) { zFlag++; } } if (zFlag == 3) { break; } else { topFace = topFace->next; } } if (topFace == NULL) { Sys_Printf("Couldn't find flat bottom-face in top brush", 0); Sys_Beep(); return; } bottomFace = brush2->brush_faces; while (bottomFace != NULL) { zFlag = 0; for (i = 0; i<3; i++) { if (abs(bottomFace->planepts[i][2] - brush2->maxs[2]) < TOWER_EPSILON) { zFlag++; } } if (zFlag == 3) { break; } else { bottomFace = bottomFace->next; } } if (bottomFace == NULL) { Sys_Printf ("Couldn't find flat top-face in bottom brush", 0); Sys_Beep(); return; } // count vertices on top and bottom planes to make sure they are equal if (topFace->face_winding->numpoints != bottomFace->face_winding->numpoints) { Sys_Printf ("Top and Bottom faces don't have same #'s of vertices!", 0); Sys_Beep(); return; } // put top and bottom faces on brush // reverse winding for top and bottom faceList = Face_Alloc(); for ( i = 0; i<3; i++) { VectorCopy(topFace->planepts[2-i],faceList->planepts[i]); } curFace = Face_Alloc(); for ( i = 0; i < 3; i++) { VectorCopy(bottomFace->planepts[2-i],curFace->planepts[i]); } curFace->next = faceList; faceList = curFace; curFace = MakePlaneList(topFace, bottomFace); if (curFace == NULL) { Sys_Printf ("Couldn't make planes for tower!", 0); Sys_Beep(); return; } else { faceList->next->next = curFace; } newBrush = (brush_t*)qmalloc(sizeof(brush_t)); newBrush->brush_faces = faceList; Select_Deselect(); Brush_AddToList (newBrush, &selected_brushes); Entity_LinkBrush (world_entity, newBrush); Brush_Build(newBrush); // UNDO_FinishBrushAdd("&Undo Tower"); Sys_UpdateWindows(W_ALL); return; }
// FIXME: this code is a TOTAL clusterfuck // void LoadModel(const char *pLocation, eclass_t *e, vec3_t &vMin, vec3_t &vMax, entitymodel *&pModel, const char *pSkin) { // this assumes a path only and uses tris.md2 // for the model and skin.pcx for the skin char cPath[1024]; char cSkin[1024]; char cFullLocation[1024]; //struct _finddata_t fileinfo; vMin[0] = vMin[1] = vMin[2] = 99999; vMax[0] = vMax[1] = vMax[2] = -99999; bool bMD3 = false; bool bASE = false; strcpy( cFullLocation, pLocation ); if (strstr(pLocation, ".md3")) { bMD3 = true; } else if (strstr(pLocation, ".md2") != NULL) { sprintf( cFullLocation, "%stris.md2", pLocation); } else if (strstr(pLocation, ".ase") != NULL) { bASE = true; } sprintf( cPath, "%s/%s", ValueForKey(g_qeglobals.d_project_entity, "basepath"), cFullLocation); Sys_Printf("Loading model %s...", cPath); unsigned char* p = NULL; bool bOpen = (LoadFile(cPath, reinterpret_cast<void**>(&p)) > 0); if (!bOpen) { Sys_Printf(" failed. Trying PAK file..."); // sprintf (cPath, "%stris.md2", pLocation); strcpy (cPath, cFullLocation); bOpen = (PakLoadAnyFile(cPath, reinterpret_cast<void**>(&p)) > 0); } if (bOpen) { Sys_Printf(" successful.\n"); if (bASE) { /* free(p); CString strOut; ::GetTempPath(1024, strOut.GetBuffer(1024)); strOut.ReleaseBuffer(); AddSlash(strOut); strOut += "Temp.ase"; CopyFile(cPath, strOut, false); CString strIn = strOut; FindReplace(strOut, ".ase", ".md3"); strcpy(cPath, strIn); strcpy(cSkin, strOut); Q3Data_ProduceTempMD3(ValueForKey(g_qeglobals.d_project_entity, "basepath"), cPath, cSkin); CString strModel = cPath; if (LoadFile(strOut.GetBuffer(0), reinterpret_cast<void**>(&p)) == 0) { Sys_Printf(" Conversion from ASE failed.\n"); return; } bMD3 = true; */ } if (bMD3) { md3Header_t header; md3Surface_t *pSurface; header = *(md3Header_t *)p; if (pSkin != NULL) { strcpy(cSkin, pSkin); } else { cSkin[0] = '\0'; } int n = header.numFrames; pSurface = (md3Surface_t *) (p + header.ofsSurfaces); for (int z = 0; z < header.numSurfaces; z++ ) { int nTris = pSurface->numTriangles; //unsigned char* pTris = reinterpret_cast<unsigned char*>(pSurface); //pTris += pSurface->ofsTriangles; if (nTris > 0) { int nStart = 0; if (pModel->pTriList == NULL) { pModel->nModelPosition = 0; pModel->pTriList = new trimodel[nTris]; pModel->nTriCount = nTris; } else { // already have one so we need to reallocate int nNewCount = pModel->nTriCount + nTris; trimodel* pNewModels = new trimodel[nNewCount]; for (int i = 0; i < pModel->nTriCount; i++) { memcpy(&pNewModels[i], &pModel->pTriList[i], sizeof(trimodel)); } nStart = pModel->nTriCount; pModel->nTriCount = nNewCount; //nTris = nNewCount; delete [] pModel->pTriList; pModel->pTriList = pNewModels; } md3Triangle_t *pTris = reinterpret_cast<md3Triangle_t*>((reinterpret_cast<unsigned char*>(pSurface) + pSurface->ofsTriangles)); md3XyzNormal_t *pXyz = reinterpret_cast<md3XyzNormal_t*>((reinterpret_cast<unsigned char*>(pSurface) + pSurface->ofsXyzNormals)); if (e->nFrame < pSurface->numFrames) { pXyz += (e->nFrame * pSurface->numVerts); } md3St_t *pST = reinterpret_cast<md3St_t*>((reinterpret_cast<unsigned char*>(pSurface) + pSurface->ofsSt)); for (int i = 0; i < nTris; i++) { for (int k = 0; k < 3; k ++) { for (int j = 0; j < 3; j++) { //e->pTriList[i].v[k][j] = (f->verts[tri.index_xyz[k]].v[j] * f->scale[j] + f->translate[j]); pModel->pTriList[nStart].v[k][j] = pXyz[pTris[i].indexes[k]].xyz[j] * MD3_XYZ_SCALE; } pModel->pTriList[nStart].st[k][0] = pST[pTris[i].indexes[k]].st[0]; pModel->pTriList[nStart].st[k][1] = pST[pTris[i].indexes[k]].st[1]; ExtendBounds (pModel->pTriList[nStart].v[k], vMin, vMax); } nStart++; } } md3Shader_t *pShader = reinterpret_cast<md3Shader_t*>((reinterpret_cast<unsigned char*>(pSurface) + pSurface->ofsShaders)); sprintf (cPath, "%s/%s", ValueForKey(g_qeglobals.d_project_entity, "basepath"), pShader->name); strlwr(cPath); pModel->nTextureBind = Texture_LoadSkin(cPath, &pModel->nSkinWidth, &pModel->nSkinHeight); if (pModel->nTextureBind == -1) { Sys_Printf("Model skin load failed on texture %s\n", cPath); } pSurface = (md3Surface_t *) ((( char * ) pSurface) + pSurface->ofsEnd); pModel->pNext = reinterpret_cast<entitymodel_t*>(qmalloc(sizeof(entitymodel_t))); pModel = pModel->pNext; } } else { dmdl_t model; daliasframe_t *f; unsigned char* pTris = p; dstvert_t *pST = NULL; int nTris = 0; // grab model params memcpy(&model, p, sizeof(dmdl_t)); f = (daliasframe_t*)(p + model.ofs_frames); pTris += model.ofs_tris; pST = reinterpret_cast<dstvert_t*>(p + model.ofs_st); nTris = model.num_tris; if(pSkin) { strcpy (cSkin, pSkin); if ((cSkin[strlen(cSkin)-1] == '\\') || (cSkin[strlen(cSkin)-1] == '/')) strcat(cSkin, "skin.pcx\0"); } else { strcpy(cSkin, (char *)(p + model.ofs_skins)); } sprintf (cPath, "%s/%s", ValueForKey(g_qeglobals.d_project_entity, "basepath"), cSkin); strlwr(cPath); pModel->nTextureBind = Texture_LoadSkin(cPath, &pModel->nSkinWidth, &pModel->nSkinHeight); if (pModel->nTextureBind == -1) { Sys_Printf("Model skin load failed on texture %s\n", cPath); } int nStart = 0; if (pModel->pTriList == NULL) { pModel->nModelPosition = 0; pModel->pTriList = new trimodel[nTris]; pModel->nTriCount = nTris; } else { // already have one so we need to reallocate int nNewCount = pModel->nTriCount + nTris; trimodel* pNewModels = new trimodel[nNewCount]; for (int i = 0; i < pModel->nTriCount; i++) { memcpy(&pNewModels[i], &pModel->pTriList[i], sizeof(trimodel)); } nStart = pModel->nTriCount; pModel->nTriCount = nNewCount; nTris = nNewCount; delete [] pModel->pTriList; pModel->pTriList = pNewModels; } for (int i = nStart; i < nTris; i++) { dtriangle_t tri; memcpy(&tri, pTris, sizeof(dtriangle_t)); for (int k = 0; k < 3; k ++) { for (int j = 0; j < 3; j++) { pModel->pTriList[i].v[k][j] = (f->verts[tri.index_xyz[k]].v[j] * f->scale[j] + f->translate[j]); } pModel->pTriList[i].st[k][0] = pST[tri.index_st[k]].s / pModel->nSkinWidth; pModel->pTriList[i].st[k][1] = pST[tri.index_st[k]].t / pModel->nSkinHeight;; ExtendBounds (pModel->pTriList[i].v[k], vMin, vMax); } pTris += sizeof(dtriangle_t); } } free(p); } else { Sys_Printf(" failed.\n"); } #if 0 if (pModel->pTriList != NULL && pModel->nTriCount > 0 && !bMD3) { if(fabs(vMin[2]) < ((vMax[2]-vMin[2]) / 10.0)) // > 90% above 0 point. pModel->nModelPosition = 1; // sprintf (cPath, "%s/%sskin.pcx", ValueForKey(g_qeglobals.d_project_entity, "basepath"), pLocation); sprintf (cPath, "%s/%s", ValueForKey(g_qeglobals.d_project_entity, "basepath"), cSkin); pModel->nTextureBind = Texture_LoadSkin(cPath, &pModel->nSkinWidth, &pModel->nSkinHeight); if (pModel->nTextureBind == -1) { // sprintf (cPath, "%sskin.pcx", pLocation); strcpy (cPath, cSkin); pModel->nTextureBind = Texture_LoadSkin(cPath, &pModel->nSkinWidth, &pModel->nSkinHeight); } } #endif }
/* ============ Entity_Create Creates a new entity out of the selected_brushes list. If the entity class is fixed size, the brushes are only used to find a midpoint. Otherwise, the brushes have their ownershi[ transfered to the new entity. ============ */ entity_t *Entity_Create (eclass_t *c) { entity_t *e; brush_t *b; vec3_t mins, maxs; int i; // check to make sure the brushes are ok for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) if (b->owner != world_entity) { Sys_Printf ("Entity NOT created, brushes not all from world\n"); Sys_Beep (); return NULL; } // create it e = (entity_t*)qmalloc(sizeof(*e)); e->brushes.onext = e->brushes.oprev = &e->brushes; e->eclass = c; SetKeyValue (e, "classname", c->name); // add the entity to the entity list e->next = entities.next; entities.next = e; e->next->prev = e; e->prev = &entities; if (c->fixedsize) { // // just use the selection for positioning // b = selected_brushes.next; for (i=0 ; i<3 ; i++) e->origin[i] = b->mins[i] - c->mins[i]; // create a custom brush VectorAdd (c->mins, e->origin, mins); VectorAdd (c->maxs, e->origin, maxs); b = Brush_Create (mins, maxs, &c->texdef); Entity_LinkBrush (e, b); // delete the current selection Select_Delete (); // select the new brush b->next = b->prev = &selected_brushes; selected_brushes.next = selected_brushes.prev = b; Brush_Build( b ); } else { // // change the selected brushes over to the new entity // for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) { Entity_UnlinkBrush (b); Entity_LinkBrush (e, b); Brush_Build( b ); // so the key brush gets a name } } Sys_UpdateWindows (W_ALL); return e; }
bool_t model_md2_save(const model_t *orig_model, xbuf_t *xbuf, char **out_error) { char *error; int skinwidth, skinheight; char **skinfilenames; const skininfo_t *skininfo; model_t *model; const mesh_t *mesh; md2_data_t *md2data; md2_header_t *header; dtriangle_t *dtriangles; int i, j, k; model = model_merge_meshes(orig_model); mesh = &model->meshes[0]; skinwidth = (texwidth != -1) ? texwidth : 0; skinheight = (texheight != -1) ? texheight : 0; for (i = 0, skininfo = model->skininfo; i < model->num_skins; i++, skininfo++) { for (j = 0; j < skininfo->num_skins; j++) { int offset = skininfo->skins[j].offset; if (!mesh->skins[offset].components[SKIN_DIFFUSE]) { if (out_error) *out_error = msprintf("Model has missing skin."); model_free(model); return false; } if (skinwidth && skinheight && (skinwidth != mesh->skins[offset].components[SKIN_DIFFUSE]->width || skinheight != mesh->skins[offset].components[SKIN_DIFFUSE]->height)) { if (out_error) *out_error = msprintf("Model has skins of different sizes. Use -texwidth and -texheight to resize all images to the same size"); model_free(model); return false; } skinwidth = mesh->skins[offset].components[SKIN_DIFFUSE]->width; skinheight = mesh->skins[offset].components[SKIN_DIFFUSE]->height; /* if fullbright texture is a different size, resample it to match the diffuse texture */ if (mesh->skins[offset].components[SKIN_FULLBRIGHT] && (mesh->skins[offset].components[SKIN_FULLBRIGHT]->width != skinwidth || mesh->skins[offset].components[SKIN_FULLBRIGHT]->height != skinheight)) { image_rgba_t *image = image_resize(mem_globalpool, mesh->skins[offset].components[SKIN_FULLBRIGHT], skinwidth, skinheight); image_free(&mesh->skins[offset].components[SKIN_FULLBRIGHT]); mesh->skins[offset].components[SKIN_FULLBRIGHT] = image; } } } if (!skinwidth || !skinheight) { if (out_error) *out_error = msprintf("Model has no skin. Use -texwidth and -texheight to set the skin dimensions, or -tex to import a skin"); model_free(model); return false; } /* create 8-bit skins and save them to PCX files */ skinfilenames = (char**)qmalloc(sizeof(char*) * model->num_skins); for (i = 0, skininfo = model->skininfo; i < model->num_skins; i++, skininfo++) { image_paletted_t *pimage; int offset = skininfo->skins[0].offset; /* skingroups not supported, just take the first skin from the group */ skinfilenames[i] = md2_create_skin_filename(skininfo->skins[0].name); pimage = image_palettize(mem_globalpool, &palette_quake2, mesh->skins[offset].components[SKIN_DIFFUSE], mesh->skins[offset].components[SKIN_FULLBRIGHT]); /* FIXME - this shouldn't be a fatal error */ if (!image_paletted_save(skinfilenames[i], pimage, &error)) { if (out_error) *out_error = msprintf("Failed to write %s: %s", skinfilenames[i], error); qfree(error); qfree(pimage); for (j = 0; j < i; j++) qfree(skinfilenames[j]); qfree(skinfilenames); model_free(model); return false; } qfree(pimage); } /* optimize vertices for md2 format */ md2data = md2_process_vertices(model, mesh, skinwidth, skinheight); /* write header */ header = (md2_header_t*)xbuf_reserve_data(xbuf, sizeof(md2_header_t)); memcpy(header->ident, "IDP2", 4); header->version = LittleLong(8); header->skinwidth = LittleLong(skinwidth); header->skinheight = LittleLong(skinheight); header->framesize = LittleLong(sizeof(daliasframe_t) + sizeof(dtrivertx_t) * md2data->numvertices); header->num_skins = LittleLong(model->num_skins); header->num_vertices = LittleLong(md2data->numvertices); header->num_st = LittleLong(md2data->numtexcoords); header->num_tris = LittleLong(mesh->num_triangles); header->num_glcmds = 0; /* filled in later */ header->num_frames = LittleLong(model->num_frames); header->offset_skins = 0; header->offset_st = 0; header->offset_tris = 0; header->offset_frames = 0; header->offset_glcmds = 0; header->offset_end = 0; /* write skins */ header->offset_skins = LittleLong(xbuf_get_bytes_written(xbuf)); for (i = 0; i < model->num_skins; i++) { md2_skin_t md2skin; strlcpy(md2skin.name, skinfilenames[i], sizeof(md2skin.name)); xbuf_write_data(xbuf, sizeof(md2_skin_t), &md2skin); } /* write texcoords */ for (i = 0; i < md2data->numtexcoords; i++) { md2data->texcoords[i].s = LittleShort(md2data->texcoords[i].s); md2data->texcoords[i].t = LittleShort(md2data->texcoords[i].t); } header->offset_st = LittleLong(xbuf_get_bytes_written(xbuf)); xbuf_write_data(xbuf, sizeof(dstvert_t) * md2data->numtexcoords, md2data->texcoords); /* write triangles */ dtriangles = (dtriangle_t*)qmalloc(sizeof(dtriangle_t) * mesh->num_triangles); for (i = 0; i < mesh->num_triangles; i++) { for (j = 0; j < 3; j++) { dtriangles[i].index_xyz[j] = LittleShort(md2data->vertex_lookup[mesh->triangle3i[i*3+j]]); dtriangles[i].index_st[j] = LittleShort(md2data->texcoord_lookup[mesh->triangle3i[i*3+j]]); } } header->offset_tris = LittleLong(xbuf_get_bytes_written(xbuf)); xbuf_write_data(xbuf, sizeof(dtriangle_t) * mesh->num_triangles, dtriangles); /* write frames */ header->offset_frames = LittleLong(xbuf_get_bytes_written(xbuf)); for (i = 0; i < model->num_frames; i++) { daliasframe_t md2frame; for (j = 0; j < 3; j++) { md2frame.scale[j] = LittleFloat(md2data->frames[i].scale[j]); md2frame.translate[j] = LittleFloat(md2data->frames[i].translate[j]); } strlcpy(md2frame.name, model->frameinfo[i].frames[0].name, sizeof(md2frame.name)); xbuf_write_data(xbuf, sizeof(daliasframe_t), &md2frame); /* write vertices */ for (j = 0; j < md2data->numvertices; j++) { const dtrivertx_t *md2vertex = md2data->original_vertices + md2data->vertices[j] * model->num_frames + i; dtrivertx_t vtx; for (k = 0; k < 3; k++) vtx.v[k] = md2vertex->v[k]; vtx.lightnormalindex = md2vertex->lightnormalindex; xbuf_write_data(xbuf, sizeof(dtrivertx_t), &vtx); } } /* write glcmds */ triangles = dtriangles; num_tris = mesh->num_triangles; md2_build_glcmds(md2data->texcoords, skinwidth, skinheight); header->num_glcmds = LittleLong(numcommands); header->offset_glcmds = LittleLong(xbuf_get_bytes_written(xbuf)); for (i = 0; i < numcommands; i++) commands[i] = LittleLong(commands[i]); xbuf_write_data(xbuf, sizeof(int) * numcommands, commands); /* write end */ header->offset_end = LittleLong(xbuf_get_bytes_written(xbuf)); /* done */ qfree(dtriangles); md2_free_data(md2data); for (i = 0; i < model->num_skins; i++) qfree(skinfilenames[i]); qfree(skinfilenames); model_free(model); return true; }
eclass_t *Eclass_InitFromText (char *text) { char *t; int len; int r, i; char parms[256], *p; eclass_t *e; char color[128]; e = qmalloc(sizeof(*e)); memset (e, 0, sizeof(*e)); text += strlen("/*QUAKED "); // grab the name text = COM_Parse (text); e->name = qmalloc (strlen(com_token)+1); strcpy (e->name, com_token); debugname = e->name; // grab the color, reformat as texture name r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]); if (r != 3) return e; sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); strcpy (e->texdef.name, color); while (*text != ')') { if (!*text) return e; text++; } text++; // get the size text = COM_Parse (text); if (com_token[0] == '(') { // parse the size as two vectors e->fixedsize = true; r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], &e->maxs[0], &e->maxs[1], &e->maxs[2]); if (r != 6) return e; for (i=0 ; i<2 ; i++) { while (*text != ')') { if (!*text) return e; text++; } text++; } } else { // use the brushes } // get the flags // copy to the first /n p = parms; while (*text && *text != '\n') *p++ = *text++; *p = 0; text++; // any remaining words are parm flags p = parms; for (i=0 ; i<8 ; i++) { p = COM_Parse (p); if (!p) break; strcpy (e->flagnames[i], com_token); } // find the length until close comment for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++) ; // copy the comment block out len = t-text; e->comments = qmalloc (len+1); memcpy (e->comments, text, len); #if 0 for (i=0 ; i<len ; i++) if (text[i] == '\n') e->comments[i] = '\r'; else e->comments[i] = text[i]; #endif e->comments[len] = 0; return e; }
static void md2_build_glcmds(const dstvert_t *texcoords, int skinwidth, int skinheight) { int i, j; int startv; int len, bestlen, besttype = -1; int best_xyz[1024]; int best_st[1024]; int best_tris[1024]; int type; numcommands = 0; used = (int*)qmalloc(sizeof(int) * num_tris); memset(used, 0, sizeof(int) * num_tris); for (i = 0; i < num_tris; i++) { /* pick an unused triangle and start the trifan */ if (used[i]) continue; bestlen = 0; for (type = 0; type < 2; type++) { for (startv = 0; startv < 3; startv++) { if (type == 1) len = md2_strip_length(i, startv); else len = md2_fan_length(i, startv); if (len > bestlen) { besttype = type; bestlen = len; for (j = 0; j < bestlen + 2; j++) { best_st[j] = strip_st[j]; best_xyz[j] = strip_xyz[j]; } for (j = 0; j < bestlen; j++) best_tris[j] = strip_tris[j]; } } } /* mark the tris on the best strip/fan as used */ for (j = 0; j < bestlen; j++) used[best_tris[j]] = 1; if (besttype == 1) commands[numcommands++] = (bestlen+2); else commands[numcommands++] = -(bestlen+2); for (j = 0; j < bestlen + 2; j++) { union { float f; int i; } u; u.f = (texcoords[best_st[j]].s + 0.5f) / skinwidth; commands[numcommands++] = u.i; u.f = (texcoords[best_st[j]].t + 0.5f) / skinheight; commands[numcommands++] = u.i; commands[numcommands++] = best_xyz[j]; } } commands[numcommands++] = 0; /* end of list marker */ qfree(used); }
static md2_data_t *md2_process_vertices(const model_t *model, const mesh_t *mesh, int skinwidth, int skinheight) { md2_data_t *data; int i, j, k; data = (md2_data_t*)qmalloc(sizeof(md2_data_t)); /* convert texcoords to integer and combine duplicates */ data->texcoords = (dstvert_t*)qmalloc(sizeof(dstvert_t) * mesh->num_vertices); data->numtexcoords = 0; data->texcoord_lookup = (int*)qmalloc(sizeof(int) * mesh->num_vertices); for (i = 0; i < mesh->num_vertices; i++) { dstvert_t md2texcoord; md2texcoord.s = (int)(mesh->texcoord2f[i*2+0] * skinwidth); md2texcoord.t = (int)(mesh->texcoord2f[i*2+1] * skinheight); for (j = 0; j < data->numtexcoords; j++) if (md2texcoord.s == data->texcoords[j].s && md2texcoord.t == data->texcoords[j].t) break; if (j == data->numtexcoords) data->texcoords[data->numtexcoords++] = md2texcoord; data->texcoord_lookup[i] = j; } /* compress vertices */ data->frames = (daliasframe_t*)qmalloc(sizeof(daliasframe_t) * model->num_frames); data->original_vertices = (dtrivertx_t*)qmalloc(sizeof(dtrivertx_t) * mesh->num_vertices * model->num_frames); for (i = 0; i < model->num_frames; i++) { daliasframe_t *md2frame = &data->frames[i]; const float *v, *n; float mins[3], maxs[3], iscale[3]; /* calculate bounds of frame */ VectorClear(mins); VectorClear(maxs); v = mesh->vertex3f + model->frameinfo[i].frames[0].offset * mesh->num_vertices * 3; for (j = 0; j < mesh->num_vertices; j++, v += 3) { for (k = 0; k < 3; k++) { mins[k] = (j == 0) ? v[k] : min(mins[k], v[k]); maxs[k] = (j == 0) ? v[k] : max(maxs[k], v[k]); } } for (j = 0; j < 3; j++) { md2frame->scale[j] = (maxs[j] - mins[j]) * (1.0f / 255.0f); md2frame->translate[j] = mins[j]; iscale[j] = md2frame->scale[j] ? (1.0f / md2frame->scale[j]) : 0.0f; } /* compress vertices */ v = mesh->vertex3f + model->frameinfo[i].frames[0].offset * mesh->num_vertices * 3; n = mesh->normal3f + model->frameinfo[i].frames[0].offset * mesh->num_vertices * 3; for (j = 0; j < mesh->num_vertices; j++, v += 3, n += 3) { dtrivertx_t *md2vertex = &data->original_vertices[j * model->num_frames + i]; for (k = 0; k < 3; k++) { float pos = (v[k] - md2frame->translate[k]) * iscale[k]; pos = (float)floor(pos + 0.5f); pos = bound(0.0f, pos, 255.0f); md2vertex->v[k] = (unsigned char)pos; } md2vertex->lightnormalindex = compress_normal(n); } } /* combine duplicate vertices */ data->vertices = (int*)qmalloc(sizeof(int) * mesh->num_vertices); data->numvertices = 0; data->vertex_lookup = (int*)qmalloc(sizeof(int) * mesh->num_vertices); for (i = 0; i < mesh->num_vertices; i++) { const dtrivertx_t *v1 = data->original_vertices + i * model->num_frames; /* see if a vertex at this position already exists */ for (j = 0; j < data->numvertices; j++) { const dtrivertx_t *v2 = data->original_vertices + data->vertices[j] * model->num_frames; for (k = 0; k < model->num_frames; k++) if (v1[k].v[0] != v2[k].v[0] || v1[k].v[1] != v2[k].v[1] || v1[k].v[2] != v2[k].v[2] || v1[k].lightnormalindex != v2[k].lightnormalindex) break; if (k == model->num_frames) break; } if (j == data->numvertices) { /* no match, add this one */ data->vertices[data->numvertices++] = i; } data->vertex_lookup[i] = j; } return data; }
group_t* Group_Alloc(char *name) { group_t *g = (group_t*)qmalloc(sizeof(group_t)); SetKeyValue( g->epairs, "group", name ); return g; }
static bool save_var (const char *filename, const char *section, const char *key, const char *value) { char line[1024], *ptr; MemStream old_rc; bool found; FILE *rc; rc = fopen (filename, "rb"); if (rc != NULL) { guint32 len; void *buf; fseek (rc, 0, SEEK_END); len = ftell (rc); rewind (rc); buf = qmalloc (len); fread (buf, len, 1, rc); old_rc.Write (buf, len); free (buf); fclose (rc); old_rc.Seek (0, SEEK_SET); } // TTimo: changed to binary writing. It doesn't seem to affect linux version, and win32 version was happending a lot of '\n' rc = fopen (filename, "wb"); if (rc == NULL) return false; // First we need to find the section found = false; while (old_rc.ReadString (line, 1024) != NULL) { fputs (line, rc); if (line[0] == '[') { ptr = strchr (line, ']'); *ptr = '\0'; if (strcmp (&line[1], section) == 0) { found = true; break; } } } if (!found) { fputs ("\n", rc); fprintf (rc, "[%s]\n", section); } fprintf (rc, "%s=%s\n", key, value); while (old_rc.ReadString (line, 1024) != NULL) { ptr = strchr (line, '='); if (ptr != NULL) { *ptr = '\0'; if (strcmp (line, key) == 0) break; *ptr = '='; fputs (line, rc); } else { fputs (line, rc); break; } } while (old_rc.ReadString (line, 1024) != NULL) fputs (line, rc); fclose (rc); return true; }
eclass_t *Eclass_InitFromText (char *text) { char *t; int len; int r, i; char parms[256], *p; eclass_t *e; char color[128]; e = (eclass_t*)qmalloc(sizeof(*e)); memset (e, 0, sizeof(*e)); text += strlen("/*QUAKED "); // grab the name text = COM_Parse (text); e->name = (char*)qmalloc (strlen(com_token)+1); strcpy (e->name, com_token); debugname = e->name; // grab the color, reformat as texture name r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]); if (r != 3) return e; sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); //strcpy (e->texdef.name, color); e->texdef.SetName(color); while (*text != ')') { if (!*text) return e; text++; } text++; // get the size text = COM_Parse (text); if (com_token[0] == '(') { // parse the size as two vectors e->fixedsize = true; r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], &e->maxs[0], &e->maxs[1], &e->maxs[2]); if (r != 6) return e; for (i=0 ; i<2 ; i++) { while (*text != ')') { if (!*text) return e; text++; } text++; } } else { // use the brushes } // get the flags // copy to the first /n p = parms; while (*text && *text != '\n') *p++ = *text++; *p = 0; text++; // any remaining words are parm flags p = parms; for (i=0 ; i<8 ; i++) { p = COM_Parse (p); if (!p) break; strcpy (e->flagnames[i], com_token); } // find the length until close comment for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++) ; // copy the comment block out len = t-text; e->comments = (char*)qmalloc (len+1); memcpy (e->comments, text, len); #if 0 for (i=0 ; i<len ; i++) if (text[i] == '\n') e->comments[i] = '\r'; else e->comments[i] = text[i]; #endif e->comments[len] = 0; setSpecialLoad(e, "model=", e->modelpath); setSpecialLoad(e, "skin=", e->skinpath); char *pFrame = NULL; setSpecialLoad(e, "frame=", pFrame); if (pFrame != NULL) { e->nFrame = atoi(pFrame); } if(!e->skinpath) setSpecialLoad(e, "texture=", e->skinpath); // setup show flags e->nShowFlags = 0; if (strcmpi(e->name, "light") == 0) { e->nShowFlags |= ECLASS_LIGHT; } if ( (strnicmp(e->name, "info_player", strlen("info_player")) == 0) ||(strnicmp(e->name, "path_corner", strlen("path_corner")) == 0) ||(strnicmp(e->name, "team_ctf", strlen("team_ctf")) == 0) ) { e->nShowFlags |= ECLASS_ANGLE; } if (strcmpi(e->name, "path") == 0) { e->nShowFlags |= ECLASS_PATH; } if (strcmpi(e->name, "misc_model") == 0) { e->nShowFlags |= ECLASS_MISCMODEL; } return e; }
void ParseBrushFace (entity_t *ent, mbrush_t **brushpointer, brushtype_t brushtype) { int i, j, sv, tv, hltexdef, facecontents, faceflags, facevalue, q2brushface, q3brushface, bpface; vec_t planepts[3][3], t1[3], t2[3], d, rotate, scale[2], vecs[2][4], ang, sinv, cosv, ns, nt, bp[2][3]; mface_t *f, *f2; plane_t plane; texinfo_t tx; mbrush_t *b; if (brushtype == BRUSHTYPE_PATCHDEF2 || brushtype == BRUSHTYPE_PATCHDEF3) return; // read the three point plane definition if (strcmp (token, "(") ) Error ("parsing brush on line %d\n", scriptline); GetToken (false); planepts[0][0] = atof(token); GetToken (false); planepts[0][1] = atof(token); GetToken (false); planepts[0][2] = atof(token); GetToken (false); if (!strcmp(token, ")")) { GetToken (false); if (strcmp(token, "(")) Error("parsing brush on line %d\n", scriptline); GetToken (false); planepts[1][0] = atof(token); GetToken (false); planepts[1][1] = atof(token); GetToken (false); planepts[1][2] = atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); GetToken (false); if (strcmp(token, "(")) Error("parsing brush on line %d\n", scriptline); GetToken (false); planepts[2][0] = atof(token); GetToken (false); planepts[2][1] = atof(token); GetToken (false); planepts[2][2] = atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); // convert points to a plane VectorSubtract(planepts[0], planepts[1], t1); VectorSubtract(planepts[2], planepts[1], t2); CrossProduct(t1, t2, plane.normal); VectorNormalize(plane.normal); plane.dist = DotProduct(planepts[1], plane.normal); } else { // oh, it's actually a 4 value plane plane.normal[0] = planepts[0][0]; plane.normal[1] = planepts[0][1]; plane.normal[2] = planepts[0][2]; plane.dist = -atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); } // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); bpface = false; hltexdef = false; if (!strcmp(token, "(")) { // brush primitives, utterly insane bpface = true; // ( GetToken(false); // ( GetToken(false); bp[0][0] = atof(token); GetToken(false); bp[0][1] = atof(token); GetToken(false); bp[0][2] = atof(token); GetToken(false); // ) GetToken(false); // ( GetToken(false); bp[1][0] = atof(token); GetToken(false); bp[1][1] = atof(token); GetToken(false); bp[1][2] = atof(token); GetToken(false); // ) GetToken (false); GetToken (false); tx.miptex = FindMiptex (token); rotate = 0; scale[0] = 1; scale[1] = 1; } else { // if the texture name contains a / then this is a q2/q3 brushface // strip off the path, wads don't use a path on texture names tx.miptex = FindMiptex (token); GetToken (false); if (!strcmp(token, "[")) { hltexdef = true; // S vector GetToken(false); vecs[0][0] = (vec_t)atof(token); GetToken(false); vecs[0][1] = (vec_t)atof(token); GetToken(false); vecs[0][2] = (vec_t)atof(token); GetToken(false); vecs[0][3] = (vec_t)atof(token); // ] GetToken(false); // [ GetToken(false); // T vector GetToken(false); vecs[1][0] = (vec_t)atof(token); GetToken(false); vecs[1][1] = (vec_t)atof(token); GetToken(false); vecs[1][2] = (vec_t)atof(token); GetToken(false); vecs[1][3] = (vec_t)atof(token); // ] GetToken(false); // rotation (unused - implicit in tex coords) GetToken(false); rotate = 0; } else { vecs[0][3] = (vec_t)atof(token); // LordHavoc: float coords GetToken (false); vecs[1][3] = (vec_t)atof(token); // LordHavoc: float coords GetToken (false); rotate = atof(token); // LordHavoc: float coords } GetToken (false); scale[0] = (vec_t)atof(token); // LordHavoc: was already float coords GetToken (false); scale[1] = (vec_t)atof(token); // LordHavoc: was already float coords } // q3 .map properties, currently unused but parsed facecontents = 0; faceflags = 0; facevalue = 0; q2brushface = false; q3brushface = false; if (GetToken (false)) { q2brushface = true; facecontents = atoi(token); if (GetToken (false)) { faceflags = atoi(token); if (GetToken (false)) { q2brushface = false; q3brushface = true; facevalue = atoi(token); } } } // skip trailing info (the 3 q3 .map parameters for example) while (GetToken (false)); if (DotProduct(plane.normal, plane.normal) < 0.1) { printf ("WARNING: brush plane with no normal on line %d\n", scriptline); return; } if (bpface) { // fake proper texture vectors from QuakeEd style TextureAxisFromPlane(&plane, vecs[0], vecs[1], true); // FIXME: deal with the bp stuff here printf("warning: brush primitive texturing not yet supported (line %d)\n", scriptline); // generic texturing tx.vecs[0][0] = vecs[0][0]; tx.vecs[0][1] = vecs[0][1]; tx.vecs[0][2] = vecs[0][2]; tx.vecs[0][3] = vecs[0][3]; tx.vecs[1][0] = vecs[1][0]; tx.vecs[1][1] = vecs[1][1]; tx.vecs[1][2] = vecs[1][2]; tx.vecs[1][3] = vecs[1][3]; } else { if (hltexdef) { for (i = 0; i < 2; i++) { d = 1.0 / (scale[i] ? scale[i] : 1.0); for (j = 0; j < 3; j++) tx.vecs[i][j] = vecs[i][j] * d; tx.vecs[i][3] = vecs[i][3] /*+ DotProduct(origin, tx.vecs[i])*/; // Sajt: ripped the commented out bit from the HL compiler code, not really sure what it is exactly doing // 'origin': origin set on bmodel by origin brush or origin key } } else { // fake proper texture vectors from QuakeEd style TextureAxisFromPlane(&plane, vecs[0], vecs[1], q3brushface); // rotate axis if (rotate == 0) {sinv = 0;cosv = 1;} else if (rotate == 90) {sinv = 1;cosv = 0;} else if (rotate == 180) {sinv = 0;cosv = -1;} else if (rotate == 270) {sinv = -1;cosv = 0;} else {ang = rotate * (Q_PI / 180);sinv = sin(ang);cosv = cos(ang);} // LordHavoc: I don't quite understand this for (sv = 0;sv < 2 && !vecs[0][sv];sv++); for (tv = 0;tv < 2 && !vecs[1][tv];tv++); for (i = 0;i < 2;i++) { // rotate ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; // scale and store into texinfo d = 1.0 / (scale[i] ? scale[i] : 1.0); for (j = 0;j < 3;j++) tx.vecs[i][j] = vecs[i][j] * d; tx.vecs[i][3] = vecs[i][3]; } } } /* // LordHavoc: fix for CheckFace: point off plane errors in some maps (most notably QOOLE ones), // and hopefully preventing most 'portal clipped away' warnings VectorNormalize (plane.normal); for (j = 0;j < 3;j++) plane.normal[j] = (Q_rint((vec_t) plane.normal[j] * (vec_t) 8.0)) * (vec_t) (1.0 / 8.0); VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); d = (Q_rint(plane.dist * 8.0)) * (1.0 / 8.0); //if (fabs(d - plane.dist) >= (0.4 / 8.0)) // printf("WARNING: correcting minor math errors in brushface on line %d\n", scriptline); plane.dist = d; */ /* VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); VectorCopy(plane.normal, v); //for (j = 0;j < 3;j++) // v[j] = (Q_rint((vec_t) v[j] * (vec_t) 32.0)) * (vec_t) (1.0 / 32.0); VectorNormalize (v); d = (Q_rint(DotProduct (t3, v) * 8.0)) * (1.0 / 8.0); // if deviation is too high, warn (frequently happens on QOOLE maps) if (fabs(DotProduct(v, plane.normal) - 1.0) > (0.5 / 32.0) || fabs(d - plane.dist) >= (0.25 / 8.0)) printf("WARNING: minor misalignment of brushface on line %d\n" "normal %f %f %f (l: %f d: %f)\n" "rounded to %f %f %f (l: %f d: %f r: %f)\n", scriptline, (vec_t) plane.normal[0], (vec_t) plane.normal[1], (vec_t) plane.normal[2], (vec_t) sqrt(DotProduct(plane.normal, plane.normal)), (vec_t) DotProduct (t3, plane.normal), (vec_t) v[0], (vec_t) v[1], (vec_t) v[2], (vec_t) sqrt(DotProduct(v, v)), (vec_t) DotProduct(t3, v), (vec_t) d); //VectorCopy(v, plane.normal); //plane.dist = d; */ b = *brushpointer; if (b) { // if the three points are all on a previous plane, it is a // duplicate plane for (f2 = b->faces ; f2 ; f2=f2->next) { for (i = 0;i < 3;i++) { d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i==3) break; } if (f2) { printf ("WARNING: brush with duplicate plane (first point is at %g %g %g, .map file line number %d)\n", planepts[0][0], planepts[0][1], planepts[0][2], scriptline); return; } } else { b = &mapbrushes[nummapbrushes]; nummapbrushes++; b->next = ent->brushes; ent->brushes = b; *brushpointer = b; } f = qmalloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; f->plane = plane; f->texinfo = FindTexinfo (&tx); nummapbrushfaces++; }
/* ================ Entity_Parse If onlypairs is set, the classname info will not be looked up, and the entity will not be added to the global list. Used for parsing the project. ================ */ entity_t *Entity_Parse (qboolean onlypairs, brush_t* pList) { entity_t *ent; eclass_t *e; brush_t *b; vec3_t mins, maxs; epair_t *ep; qboolean has_brushes; #ifdef SOF float scale; #endif if (!GetToken (true)) return NULL; if (strcmp (token, "{") ) Error ("ParseEntity: { not found"); ent = (entity_t*)qmalloc (sizeof(*ent)); ent->brushes.onext = ent->brushes.oprev = &ent->brushes; do { if (!GetToken (true)) { Warning ("ParseEntity: EOF without closing brace"); return NULL; } if (!strcmp (token, "}") ) break; if (!strcmp (token, "{") ) { b = Brush_Parse (); if (b != NULL) { b->owner = ent; // add to the end of the entity chain b->onext = &ent->brushes; b->oprev = ent->brushes.oprev; ent->brushes.oprev->onext = b; ent->brushes.oprev = b; } else { break; } } else { ep = ParseEpair (); { // update: the original code here may have been simple, but it meant that every map load/save // the key/value pair fields were reversed in the save file, which messes up SourceSafe when it // tries to delta the two versions during check-in... -slc #if 0 ep->next = ent->epairs; ent->epairs = ep; #else // join this onto the END of the chain instead... // if (ent->epairs == NULL) // special case for if there isn't a chain yet... :-) { ep->next = ent->epairs; ent->epairs = ep; } else { for (epair_t* ep2 = ent->epairs ; ep2 ; ep2=ep2->next) { if (ep2->next == NULL) { // found the end, so... // ep2->next = ep; ep->next = NULL; break; } } } #endif } } } while (1); if (onlypairs) return ent; if (ent->brushes.onext == &ent->brushes) has_brushes = false; else has_brushes = true; GetVectorForKey (ent, "origin", ent->origin); e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes); ent->eclass = e; if (e->fixedsize) { // fixed size entity if (ent->brushes.onext != &ent->brushes) { printf ("Warning: Fixed size entity with brushes\n"); #if 0 while (ent->brushes.onext != &ent->brushes) { // FIXME: this will free the entity and crash! Brush_Free (b); } #endif ent->brushes.next = ent->brushes.prev = &ent->brushes; } // create a custom brush VectorAdd (e->mins, ent->origin, mins); VectorAdd (e->maxs, ent->origin, maxs); float a = 0; if (strnicmp(e->name, "misc_model",10) == 0) { char* p = ValueForKey(ent, "model"); if (p != NULL && strlen(p) > 0) { vec3_t vMin, vMax; a = FloatForKey (ent, "angle"); gEntityToSetBoundsOf = ent; if (GetCachedModel(ent, p, vMin, vMax)) { // create a custom brush VectorAdd (ent->md3Class->mins, ent->origin, mins); VectorAdd (ent->md3Class->maxs, ent->origin, maxs); } } } #ifdef SOF if (strnicmp(e->name, "misc_", 5) == 0 || strnicmp(e->name, "light_", 6) == 0 || strnicmp(e->name, "m_", 2) == 0 || strnicmp(e->name, "item_weapon_", 12)== 0 || strnicmp(e->name, "item_ammo_", 10)== 0 ) a = FloatForKey (ent, "angle"); #endif b = Brush_Create (mins, maxs, &e->texdef); /////// b->owner = ent; b->onext = ent->brushes.onext; b->oprev = &ent->brushes; ent->brushes.onext->oprev = b; ent->brushes.onext = b; /////// Brush_Build(b); #ifdef SOF scale = FloatForKey (ent, "scale"); if (scale) { Brush_Scale2(e, b, scale, ent->origin,false); } #endif // if (a) // { // vec3_t vAngle; // vAngle[0] = vAngle[1] = 0; // vAngle[2] = a; // Brush_Rotate(b, vAngle, ent->origin, false); // } /* b->owner = ent; b->onext = ent->brushes.onext; b->oprev = &ent->brushes; ent->brushes.onext->oprev = b; ent->brushes.onext = b; */ // do this AFTER doing the brush stuff just above, so don't join to the other "if (a)"... // if (a) { // pick any old value to rotate away to, then back from, to avoid 0/360 weirdness on key-compares // SetKeyValue(ent, "angle", "0", false); // false = no tracking, ie just set the angle and nothing else SetKeyValue(ent, "angle", va("%g",a), true); // true = do tracking, ie actually do the brush rotate } } else { // brush entity if (ent->brushes.next == &ent->brushes) printf ("Warning: Brush entity with no brushes\n"); } // add all the brushes to the main list if (pList) { for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext) { b->next = pList->next; pList->next->prev = b; b->prev = pList; pList->next = b; } } return ent; }