X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_alias.c;h=517975fd0d338b1e14e6e51845100f2fded19e64;hp=6247e5b64162b89f3c86b0ecffe6171fbd503812;hb=6da366f77c74605f13ec0e88c68a112974b3a2ae;hpb=32d73f2e1ef4c7f22b283c21c99eaf6abf223304 diff --git a/model_alias.c b/model_alias.c index 6247e5b6..517975fd 100644 --- a/model_alias.c +++ b/model_alias.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "image.h" static cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0"}; @@ -36,9 +37,9 @@ static int vertonseam[MAXALIASVERTS]; static int vertremap[MAXALIASVERTS]; static int temptris[MAXALIASTRIS][3]; -static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, trivertx_t *out) +static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, aliasvertex_t *out) { - int i, j, invalidnormals = 0; + int i, j; float dist; vec3_t temp; for (i = 0;i < inverts;i++) @@ -65,42 +66,46 @@ static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, j = vertremap[i]; // not onseam if (j >= 0) - { - VectorCopy(v[i].v, out[j].v); - out[j].lightnormalindex = v[i].lightnormalindex; - if (out[j].lightnormalindex >= NUMVERTEXNORMALS) - { - invalidnormals++; - out[j].lightnormalindex = 0; - } - } + VectorCopy(temp, out[j].origin); j = vertremap[i+inverts]; // onseam if (j >= 0) - { - VectorCopy(v[i].v, out[j].v); - out[j].lightnormalindex = v[i].lightnormalindex; - if (out[j].lightnormalindex >= NUMVERTEXNORMALS) - { - invalidnormals++; - out[j].lightnormalindex = 0; - } - } + VectorCopy(temp, out[j].origin); } - if (invalidnormals) - Con_Printf("Mod_ConvertAliasVerts: \"%s\", %i invalid normal indices found\n", loadmodel->name, invalidnormals); } -static void Mod_MDL_LoadFrames (qbyte * datapointer, int inverts, int outverts, vec3_t scale, vec3_t translate) +static void Mod_BuildAliasVertexTextureVectors(int numtriangles, const int *elements, int numverts, aliasvertex_t *vertices, const float *texcoords, float *vertexbuffer, float *svectorsbuffer, float *tvectorsbuffer, float *normalsbuffer) { - daliasframetype_t *pframetype; - daliasframe_t *pinframe; - daliasgroup_t *group; - daliasinterval_t *intervals; - int i, f, pose, groupframes; - float interval; - animscene_t *scene; + int i; + for (i = 0;i < numverts;i++) + VectorCopy(vertices[i].origin, &vertexbuffer[i * 4]); + Mod_BuildTextureVectorsAndNormals(numverts, numtriangles, vertexbuffer, texcoords, elements, svectorsbuffer, tvectorsbuffer, normalsbuffer); + for (i = 0;i < numverts;i++) + { + // LordHavoc: alias models are backwards, apparently + vertices[i].normal[0] = normalsbuffer[i * 4 + 0]; + vertices[i].normal[1] = normalsbuffer[i * 4 + 1]; + vertices[i].normal[2] = normalsbuffer[i * 4 + 2]; + vertices[i].svector[0] = svectorsbuffer[i * 4 + 0]; + vertices[i].svector[1] = svectorsbuffer[i * 4 + 1]; + vertices[i].svector[2] = svectorsbuffer[i * 4 + 2]; + } +} + +static void Mod_MDL_LoadFrames (qbyte* datapointer, int inverts, vec3_t scale, vec3_t translate, int *elements, float *texcoords, aliasvertex_t *posedata) +{ + int i, f, pose, groupframes; + float interval, *vertexbuffer, *svectorsbuffer, *tvectorsbuffer, *normalsbuffer; + daliasframetype_t *pframetype; + daliasframe_t *pinframe; + daliasgroup_t *group; + daliasinterval_t *intervals; + animscene_t *scene; pose = 0; scene = loadmodel->animscenes; + vertexbuffer = Mem_Alloc(tempmempool, loadmodel->numverts * sizeof(float[4]) * 4); + svectorsbuffer = vertexbuffer + loadmodel->numverts * 4; + tvectorsbuffer = svectorsbuffer + loadmodel->numverts * 4; + normalsbuffer = tvectorsbuffer + loadmodel->numverts * 4; for (f = 0;f < loadmodel->numframes;f++) { pframetype = (daliasframetype_t *)datapointer; @@ -142,127 +147,214 @@ static void Mod_MDL_LoadFrames (qbyte * datapointer, int inverts, int outverts, { pinframe = (daliasframe_t *)datapointer; datapointer += sizeof(daliasframe_t); - - // convert to MD2 frame headers - strcpy(loadmodel->mdlmd2data_frames[pose].name, pinframe->name); - VectorCopy(scale, loadmodel->mdlmd2data_frames[pose].scale); - VectorCopy(translate, loadmodel->mdlmd2data_frames[pose].translate); - - Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, loadmodel->mdlmd2data_pose + pose * outverts); + Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, posedata + pose * loadmodel->numverts); + Mod_BuildAliasVertexTextureVectors(loadmodel->numtris, elements, loadmodel->numverts, posedata + pose * loadmodel->numverts, texcoords, vertexbuffer, svectorsbuffer, tvectorsbuffer, normalsbuffer); datapointer += sizeof(trivertx_t) * inverts; pose++; } } + Mem_Free(vertexbuffer); } -static rtexture_t *GL_SkinSplitShirt(qbyte *in, qbyte *out, int width, int height, int bits, char *name, int precache) +static rtexture_t *GL_TextureForSkinLayer(const qbyte *in, int width, int height, const char *name, const unsigned int *palette, int precache) { - int i, pixels, passed; - qbyte pixeltest[16]; - for (i = 0;i < 16;i++) - pixeltest[i] = (bits & (1 << i)) != 0; - pixels = width*height; - passed = 0; - while(pixels--) - { - if (pixeltest[*in >> 4] && *in != 0 && *in != 255) - { - passed++; - // turn to white while copying - if (*in >= 128 && *in < 224) // backwards ranges - *out = (*in & 15) ^ 15; - else - *out = *in & 15; - } - else - *out = 0; - in++; - out++; - } - if (passed) - return R_LoadTexture (loadmodel->texturepool, name, width, height, out - width*height, TEXTYPE_QPALETTE, (r_mipskins.integer ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0)); - else - return NULL; + int i; + for (i = 0;i < width*height;i++) + if (((qbyte *)&palette[in[i]])[3] > 0) + return R_LoadTexture2D (loadmodel->texturepool, name, width, height, in, TEXTYPE_PALETTE, (r_mipskins.integer ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0), palette); + return NULL; } -static rtexture_t *GL_SkinSplit(qbyte *in, qbyte *out, int width, int height, int bits, char *name, int precache) +static int Mod_LoadExternalSkin (char *basename, skinframe_t *skinframe, int precache) { - int i, pixels, passed; - qbyte pixeltest[16]; - for (i = 0;i < 16;i++) - pixeltest[i] = (bits & (1 << i)) != 0; - pixels = width*height; - passed = 0; - while(pixels--) - { - if (pixeltest[*in >> 4] && *in != 0 && *in != 255) - { - passed++; - *out = *in; - } - else - *out = 0; - in++; - out++; - } - if (passed) - return R_LoadTexture (loadmodel->texturepool, name, width, height, out - width*height, TEXTYPE_QPALETTE, (r_mipskins.integer ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0)); - else - return NULL; + skinframe->base = loadtextureimagewithmaskandnmap(loadmodel->texturepool, va("%s_normal", basename), 0, 0, false, TEXF_ALPHA | (precache ? TEXF_PRECACHE : 0) | (r_mipskins.integer ? TEXF_MIPMAP : 0), 1); + if (!skinframe->base) + skinframe->base = loadtextureimagewithmaskandnmap(loadmodel->texturepool, basename, 0, 0, false, TEXF_ALPHA | (precache ? TEXF_PRECACHE : 0) | (r_mipskins.integer ? TEXF_MIPMAP : 0), 1); + skinframe->fog = image_masktex; + skinframe->nmap = image_nmaptex; + skinframe->gloss = loadtextureimage(loadmodel->texturepool, va("%s_gloss" , basename), 0, 0, false, TEXF_ALPHA | (precache ? TEXF_PRECACHE : 0) | (r_mipskins.integer ? TEXF_MIPMAP : 0)); + skinframe->pants = loadtextureimage(loadmodel->texturepool, va("%s_pants" , basename), 0, 0, false, TEXF_ALPHA | (precache ? TEXF_PRECACHE : 0) | (r_mipskins.integer ? TEXF_MIPMAP : 0)); + skinframe->shirt = loadtextureimage(loadmodel->texturepool, va("%s_shirt" , basename), 0, 0, false, TEXF_ALPHA | (precache ? TEXF_PRECACHE : 0) | (r_mipskins.integer ? TEXF_MIPMAP : 0)); + skinframe->glow = loadtextureimage(loadmodel->texturepool, va("%s_glow" , basename), 0, 0, false, TEXF_ALPHA | (precache ? TEXF_PRECACHE : 0) | (r_mipskins.integer ? TEXF_MIPMAP : 0)); + skinframe->merged = NULL; + return skinframe->base != NULL || skinframe->pants != NULL || skinframe->shirt != NULL || skinframe->glow != NULL; } -static void Mod_LoadSkin (char *basename, qbyte *skindata, qbyte *skintemp, int width, int height, skinframe_t *skinframe, int precache) +static int Mod_LoadInternalSkin (char *basename, qbyte *skindata, int width, int height, skinframe_t *skinframe, int precache) { - skinframe->base = loadtextureimagewithmask(loadmodel->texturepool, va("%s_normal", basename), 0, 0, false, r_mipskins.integer, precache); - skinframe->fog = image_masktex; - skinframe->pants = NULL; - skinframe->shirt = NULL; - skinframe->glow = loadtextureimage(loadmodel->texturepool, va("%s_glow" , basename), 0, 0, false, r_mipskins.integer, precache); - skinframe->merged = NULL; - if (skinframe->base) + qbyte *temp1, *temp2; + if (!skindata) + return false; + temp1 = Mem_Alloc(loadmodel->mempool, width * height * 8); + temp2 = temp1 + width * height * 4; + Image_Copy8bitRGBA(skindata, temp1, width * height, palette_nofullbrights); + Image_HeightmapToNormalmap(temp1, temp2, width, height, false, 1); + skinframe->nmap = R_LoadTexture2D(loadmodel->texturepool, va("%s_nmap", basename), width, height, temp2, TEXTYPE_RGBA, (r_mipskins.integer ? TEXF_MIPMAP : 0) | (precache ? TEXF_PRECACHE : 0), NULL); + Mem_Free(temp1); + skinframe->gloss = NULL; + skinframe->pants = GL_TextureForSkinLayer(skindata, width, height, va("%s_pants", basename), palette_pantsaswhite, false); // pants + skinframe->shirt = GL_TextureForSkinLayer(skindata, width, height, va("%s_shirt", basename), palette_shirtaswhite, false); // shirt + skinframe->glow = GL_TextureForSkinLayer(skindata, width, height, va("%s_glow", basename), palette_onlyfullbrights, precache); // glow + if (skinframe->pants || skinframe->shirt) { - skinframe->pants = loadtextureimage(loadmodel->texturepool, va("%s_pants" , basename), 0, 0, false, r_mipskins.integer, precache); - skinframe->shirt = loadtextureimage(loadmodel->texturepool, va("%s_shirt" , basename), 0, 0, false, r_mipskins.integer, precache); + skinframe->base = GL_TextureForSkinLayer(skindata, width, height, va("%s_normal", basename), palette_nocolormapnofullbrights, false); // normal (no special colors) + skinframe->merged = GL_TextureForSkinLayer(skindata, width, height, va("%s_body", basename), palette_nofullbrights, precache); // body (normal + pants + shirt, but not glow) } else + skinframe->base = GL_TextureForSkinLayer(skindata, width, height, va("%s_base", basename), palette_nofullbrights, precache); // no special colors + // quake model skins don't have alpha + skinframe->fog = NULL; + return true; +} + +void Mod_BuildMDLMD2MeshInfo(int *elements, float *texcoords, aliasvertex_t *posedata) +{ + int i; + aliasmesh_t *mesh; + aliasskin_t *skin; + aliaslayer_t *layer; + skinframe_t *skinframe; + + loadmodel->aliasnum_meshes = 1; + mesh = loadmodel->aliasdata_meshes = Mem_Alloc(loadmodel->mempool, loadmodel->aliasnum_meshes * sizeof(aliasmesh_t)); + mesh->num_skins = 0; + mesh->num_frames = 0; + for (i = 0;i < loadmodel->numframes;i++) + mesh->num_frames += loadmodel->animscenes[i].framecount; + for (i = 0;i < loadmodel->numskins;i++) + mesh->num_skins += loadmodel->skinscenes[i].framecount; + mesh->num_triangles = loadmodel->numtris; + mesh->num_vertices = loadmodel->numverts; + mesh->data_skins = Mem_Alloc(loadmodel->mempool, mesh->num_skins * sizeof(aliasskin_t)); + mesh->data_elements = elements; + mesh->data_neighbors = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(int[3])); + Mod_ValidateElements(mesh->data_elements, loadmodel->numtris, loadmodel->numverts, __FILE__, __LINE__); + Mod_BuildTriangleNeighbors(mesh->data_neighbors, elements, loadmodel->numtris); + mesh->data_texcoords = texcoords; + mesh->data_vertices = posedata; + for (i = 0, skin = mesh->data_skins, skinframe = loadmodel->skinframes;i < mesh->num_skins;i++, skin++, skinframe++) { - skinframe->base = loadtextureimagewithmask(loadmodel->texturepool, basename, 0, 0, false, true, true); - skinframe->fog = image_masktex; - if (!skinframe->base) + skin->flags = 0; + // fog texture only exists if some pixels are transparent... + if (skinframe->fog != NULL) + skin->flags |= ALIASSKIN_TRANSPARENT; + // fog and gloss layers always exist + skin->num_layers = 2; + if (skinframe->glow != NULL) + skin->num_layers++; + if (skinframe->merged != NULL) + skin->num_layers += 2; + if (skinframe->base != NULL) + skin->num_layers += 2; + if (skinframe->pants != NULL) + skin->num_layers += 2; + if (skinframe->shirt != NULL) + skin->num_layers += 2; + layer = skin->data_layers = Mem_Alloc(loadmodel->mempool, skin->num_layers * sizeof(aliaslayer_t)); + if (skinframe->glow != NULL) { - skinframe->pants = GL_SkinSplitShirt(skindata, skintemp, width, height, 0x0040, va("%s_pants", basename), false); // pants - skinframe->shirt = GL_SkinSplitShirt(skindata, skintemp, width, height, 0x0002, va("%s_shirt", basename), false); // shirt - skinframe->glow = GL_SkinSplit (skindata, skintemp, width, height, 0xC000, va("%s_glow", basename), precache); // glow - if (skinframe->pants || skinframe->shirt) - { - skinframe->base = GL_SkinSplit (skindata, skintemp, width, height, 0x3FBD, va("%s_normal", basename), false); // normal (no special colors) - skinframe->merged = GL_SkinSplit (skindata, skintemp, width, height, 0x3FFF, va("%s_body", basename), precache); // body (normal + pants + shirt, but not glow) - } - else - skinframe->base = GL_SkinSplit (skindata, skintemp, width, height, 0x3FFF, va("%s_base", basename), precache); // no special colors - // quake model skins don't have alpha - skinframe->fog = NULL; + layer->flags = 0; + layer->texture = skinframe->glow; + layer++; + } + if (skinframe->merged != NULL) + { + layer->flags = ALIASLAYER_NODRAW_IF_COLORMAPPED | ALIASLAYER_DIFFUSE; + if (skinframe->glow != NULL) + layer->flags |= ALIASLAYER_ADD; + layer->texture = skinframe->merged; + layer->nmap = skinframe->nmap; + layer++; + } + if (skinframe->base != NULL) + { + layer->flags = ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_DIFFUSE; + if (skinframe->glow != NULL) + layer->flags |= ALIASLAYER_ADD; + layer->texture = skinframe->base; + layer->nmap = skinframe->nmap; + layer++; + } + if (skinframe->pants != NULL) + { + layer->flags = ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_DIFFUSE | ALIASLAYER_COLORMAP_SHIRT; + if (skinframe->glow != NULL || skinframe->base != NULL) + layer->flags |= ALIASLAYER_ADD; + layer->texture = skinframe->pants; + layer->nmap = skinframe->nmap; + layer++; + } + if (skinframe->shirt != NULL) + { + layer->flags = ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_DIFFUSE | ALIASLAYER_COLORMAP_SHIRT; + if (skinframe->glow != NULL || skinframe->base != NULL || skinframe->pants != NULL) + layer->flags |= ALIASLAYER_ADD; + layer->texture = skinframe->shirt; + layer->nmap = skinframe->nmap; + layer++; + } + layer->flags = ALIASLAYER_FOG; + layer->texture = skinframe->fog; + layer++; + layer->flags = ALIASLAYER_DRAW_PER_LIGHT | ALIASLAYER_SPECULAR; + layer->texture = skinframe->gloss; + layer->nmap = skinframe->nmap; + layer++; + if (skinframe->merged != NULL) + { + layer->flags = ALIASLAYER_DRAW_PER_LIGHT | ALIASLAYER_NODRAW_IF_COLORMAPPED | ALIASLAYER_DIFFUSE; + layer->texture = skinframe->merged; + layer->nmap = skinframe->nmap; + layer++; + } + if (skinframe->base != NULL) + { + layer->flags = ALIASLAYER_DRAW_PER_LIGHT | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_DIFFUSE; + layer->texture = skinframe->base; + layer->nmap = skinframe->nmap; + layer++; + } + if (skinframe->pants != NULL) + { + layer->flags = ALIASLAYER_DRAW_PER_LIGHT | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_DIFFUSE | ALIASLAYER_COLORMAP_PANTS; + layer->texture = skinframe->pants; + layer->nmap = skinframe->nmap; + layer++; + } + if (skinframe->shirt != NULL) + { + layer->flags = ALIASLAYER_DRAW_PER_LIGHT | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_DIFFUSE | ALIASLAYER_COLORMAP_SHIRT; + layer->texture = skinframe->shirt; + layer->nmap = skinframe->nmap; + layer++; } } } #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", loadmodel->name, VALUE, MIN, MAX); #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX); +extern void R_Model_Alias_Draw(entity_render_t *ent); +extern void R_Model_Alias_DrawFakeShadow(entity_render_t *ent); +extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius); +extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor); void Mod_LoadAliasModel (model_t *mod, void *buffer) { - int i, j, version, numverts, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins; - mdl_t *pinmodel; - stvert_t *pinstverts; - dtriangle_t *pintriangles; - daliasskintype_t *pinskintype; - daliasskingroup_t *pinskingroup; - daliasskininterval_t *pinskinintervals; - daliasframetype_t *pinframetype; - daliasgroup_t *pinframegroup; - float scales, scalet, scale[3], translate[3], interval; - qbyte *datapointer, *startframes, *startskins; - char name[MAX_QPATH]; - qbyte *skintemp = NULL; + int i, j, version, numverts, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins, *elements; + float scales, scalet, scale[3], translate[3], interval, *texcoords; + mdl_t *pinmodel; + stvert_t *pinstverts; + dtriangle_t *pintriangles; + daliasskintype_t *pinskintype; + daliasskingroup_t *pinskingroup; + daliasskininterval_t *pinskinintervals; + daliasframetype_t *pinframetype; + daliasgroup_t *pinframegroup; + aliasvertex_t *posedata; + qbyte *datapointer, *startframes, *startskins; + char name[MAX_QPATH]; + skinframe_t tempskinframe; + animscene_t *tempskinscenes; + skinframe_t *tempskinframes; modelyawradius = 0; modelradius = 0; @@ -276,7 +368,12 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) loadmodel->name, version, ALIAS_VERSION); loadmodel->type = mod_alias; - loadmodel->aliastype = ALIASTYPE_MDLMD2; + loadmodel->aliastype = ALIASTYPE_ALIAS; + loadmodel->DrawSky = NULL; + loadmodel->Draw = R_Model_Alias_Draw; + loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow; + loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume; + loadmodel->DrawLight = R_Model_Alias_DrawLight; loadmodel->numskins = LittleLong(pinmodel->numskins); BOUNDI(loadmodel->numskins,0,256); @@ -354,7 +451,6 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) } // load the skins - skintemp = Mem_Alloc(tempmempool, skinwidth * skinheight); loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t)); loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, totalskins * sizeof(skinframe_t)); totalskins = 0; @@ -396,12 +492,41 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) sprintf (name, "%s_%i_%i", loadmodel->name, i, j); else sprintf (name, "%s_%i", loadmodel->name, i); - Mod_LoadSkin(name, (qbyte *)datapointer, skintemp, skinwidth, skinheight, loadmodel->skinframes + totalskins, i == 0); + if (!Mod_LoadExternalSkin(name, loadmodel->skinframes + totalskins, i == 0)) + Mod_LoadInternalSkin(name, (qbyte *)datapointer, skinwidth, skinheight, loadmodel->skinframes + totalskins, i == 0); datapointer += skinwidth * skinheight; totalskins++; } } - Mem_Free(skintemp); + // check for skins that don't exist in the model, but do exist as external images + // (this was added because yummyluv kept pestering me about support for it) + for (;;) + { + sprintf (name, "%s_%i", loadmodel->name, loadmodel->numskins); + if (Mod_LoadExternalSkin(name, &tempskinframe, loadmodel->numskins == 0)) + { + // expand the arrays to make room + tempskinscenes = loadmodel->skinscenes; + tempskinframes = loadmodel->skinframes; + loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t)); + loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, (totalskins + 1) * sizeof(skinframe_t)); + memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t)); + memcpy(loadmodel->skinframes, tempskinframes, totalskins * sizeof(skinframe_t)); + Mem_Free(tempskinscenes); + Mem_Free(tempskinframes); + // store the info about the new skin + strcpy(loadmodel->skinscenes[loadmodel->numskins].name, name); + loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins; + loadmodel->skinscenes[loadmodel->numskins].framecount = 1; + loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f; + loadmodel->skinscenes[loadmodel->numskins].loop = true; + loadmodel->skinframes[totalskins] = tempskinframe; + loadmodel->numskins++; + totalskins++; + } + else + break; + } // store texture coordinates into temporary array, they will be stored after usage is determined (triangle data) scales = 1.0 / skinwidth; @@ -409,8 +534,8 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) for (i = 0;i < numverts;i++) { vertonseam[i] = LittleLong(pinstverts[i].onseam); - vertst[i][0] = LittleLong(pinstverts[i].s) * scales; - vertst[i][1] = LittleLong(pinstverts[i].t) * scalet; + vertst[i][0] = (LittleLong(pinstverts[i].s) + 0.5) * scales; + vertst[i][1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet; vertst[i+numverts][0] = vertst[i][0] + 0.5; vertst[i+numverts][1] = vertst[i][1]; vertusage[i] = 0; @@ -418,7 +543,7 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) } // load triangle data - loadmodel->mdlmd2data_indices = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->numtris); + elements = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->numtris); // count the vertices used for (i = 0;i < numverts*2;i++) @@ -456,28 +581,27 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) // remap the triangle references for (i = 0;i < loadmodel->numtris;i++) { - loadmodel->mdlmd2data_indices[i*3+0] = vertremap[temptris[i][0]]; - loadmodel->mdlmd2data_indices[i*3+1] = vertremap[temptris[i][1]]; - loadmodel->mdlmd2data_indices[i*3+2] = vertremap[temptris[i][2]]; + elements[i*3+0] = vertremap[temptris[i][0]]; + elements[i*3+1] = vertremap[temptris[i][1]]; + elements[i*3+2] = vertremap[temptris[i][2]]; } // store the texture coordinates - loadmodel->mdlmd2data_texcoords = Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * totalverts); + texcoords = Mem_Alloc(loadmodel->mempool, sizeof(float[4]) * totalverts); for (i = 0;i < totalverts;i++) { - loadmodel->mdlmd2data_texcoords[i*2+0] = vertst[i][0]; - loadmodel->mdlmd2data_texcoords[i*2+1] = vertst[i][1]; + texcoords[i*4+0] = vertst[i][0]; + texcoords[i*4+1] = vertst[i][1]; } // load the frames loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); - loadmodel->mdlmd2data_frames = Mem_Alloc(loadmodel->mempool, sizeof(md2frame_t) * totalposes); - loadmodel->mdlmd2data_pose = Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * totalposes * totalverts); + posedata = Mem_Alloc(loadmodel->mempool, sizeof(aliasvertex_t) * totalposes * totalverts); // LordHavoc: doing proper bbox for model aliasbboxmin[0] = aliasbboxmin[1] = aliasbboxmin[2] = 1000000000; aliasbboxmax[0] = aliasbboxmax[1] = aliasbboxmax[2] = -1000000000; - Mod_MDL_LoadFrames (startframes, numverts, totalverts, scale, translate); + Mod_MDL_LoadFrames (startframes, numverts, scale, translate, elements, texcoords, posedata); modelyawradius = sqrt(modelyawradius); modelradius = sqrt(modelradius); @@ -491,22 +615,21 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) loadmodel->yawmins[0] = loadmodel->yawmins[1] = -(loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelyawradius); loadmodel->yawmins[2] = loadmodel->normalmins[2]; loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; + loadmodel->radius = modelradius; + loadmodel->radius2 = modelradius * modelradius; - loadmodel->Draw = R_DrawAliasModel; - loadmodel->DrawSky = NULL; - loadmodel->DrawShadow = NULL; + Mod_BuildMDLMD2MeshInfo(elements, texcoords, posedata); } -static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, trivertx_t *out, int *vertremap) +static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, aliasvertex_t *out, int *vertremap) { - int i, invalidnormals = 0; + int i; float dist; trivertx_t *in; vec3_t temp; for (i = 0;i < loadmodel->numverts;i++) { in = v + vertremap[i]; - VectorCopy(in->v, out[i].v); temp[0] = in->v[0] * scale[0] + translate[0]; temp[1] = in->v[1] * scale[1] + translate[1]; temp[2] = in->v[2] * scale[2] + translate[2]; @@ -523,25 +646,21 @@ static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, dist += temp[2]*temp[2]; if (modelradius < dist) modelradius = dist; - out[i].lightnormalindex = in->lightnormalindex; - if (out[i].lightnormalindex >= NUMVERTEXNORMALS) - { - invalidnormals++; - out[i].lightnormalindex = 0; - } + VectorCopy(temp, out[i].origin); } - if (invalidnormals) - Con_Printf("Mod_MD2_ConvertVerts: \"%s\", %i invalid normal indices found\n", loadmodel->name, invalidnormals); } void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) { - int *vertremap; + int i, j, k, hashindex, num, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end, *elements; + float *stverts, s, t, scale[3], translate[3], *vertexbuffer, *svectorsbuffer, *tvectorsbuffer, *normalsbuffer, *texcoords; + aliasvertex_t *posedata; md2_t *pinmodel; - qbyte *base; - int version, end; - int i, j, k, hashindex, num, numxyz, numst, xyz, st; - float *stverts, s, t; + qbyte *base, *datapointer; + md2frame_t *pinframe; + char *inskin; + md2triangle_t *intri; + unsigned short *inst; struct md2verthash_s { struct md2verthash_s *next; @@ -549,12 +668,6 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) float st[2]; } *hash, **md2verthash, *md2verthashdata; - qbyte *datapointer; - md2frame_t *pinframe; - char *inskin; - md2triangle_t *intri; - unsigned short *inst; - int skinwidth, skinheight; pinmodel = buffer; base = buffer; @@ -565,10 +678,12 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) loadmodel->name, version, MD2ALIAS_VERSION); loadmodel->type = mod_alias; - loadmodel->aliastype = ALIASTYPE_MDLMD2; - loadmodel->Draw = R_DrawAliasModel; + loadmodel->aliastype = ALIASTYPE_ALIAS; loadmodel->DrawSky = NULL; - loadmodel->DrawShadow = NULL; + loadmodel->Draw = R_Model_Alias_Draw; + loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow; + loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume; + loadmodel->DrawLight = R_Model_Alias_DrawLight; if (LittleLong(pinmodel->num_tris < 1) || LittleLong(pinmodel->num_tris) > MD2MAX_TRIANGLES) Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris)); @@ -604,16 +719,18 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) inskin = (void*)(base + LittleLong(pinmodel->ofs_skins)); if (loadmodel->numskins) { - loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); - loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, sizeof(skinframe_t) * loadmodel->numskins); + loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins + sizeof(skinframe_t) * loadmodel->numskins); + loadmodel->skinframes = (void *)(loadmodel->skinscenes + loadmodel->numskins); for (i = 0;i < loadmodel->numskins;i++) { loadmodel->skinscenes[i].firstframe = i; loadmodel->skinscenes[i].framecount = 1; loadmodel->skinscenes[i].loop = true; loadmodel->skinscenes[i].framerate = 10; - loadmodel->skinframes[i].base = loadtextureimagewithmask (loadmodel->texturepool, inskin, 0, 0, true, r_mipskins.integer, true); + loadmodel->skinframes[i].base = loadtextureimagewithmaskandnmap (loadmodel->texturepool, inskin, 0, 0, true, TEXF_ALPHA | TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0), 1); loadmodel->skinframes[i].fog = image_masktex; + loadmodel->skinframes[i].nmap = image_nmaptex; + loadmodel->skinframes[i].gloss = NULL; loadmodel->skinframes[i].pants = NULL; loadmodel->skinframes[i].shirt = NULL; loadmodel->skinframes[i].glow = NULL; @@ -648,7 +765,7 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) md2verthashdata = Mem_Alloc(tempmempool, loadmodel->numtris * 3 * sizeof(*hash)); // swap the triangle list num = 0; - loadmodel->mdlmd2data_indices = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(int[3])); + elements = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(int[3])); for (i = 0;i < loadmodel->numtris;i++) { for (j = 0;j < 3;j++) @@ -680,7 +797,7 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) hash->next = md2verthash[hashindex]; md2verthash[hashindex] = hash; } - loadmodel->mdlmd2data_indices[i*3+j] = (hash - md2verthashdata); + elements[i*3+j] = (hash - md2verthashdata); } } @@ -688,13 +805,13 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) loadmodel->numverts = num; vertremap = Mem_Alloc(loadmodel->mempool, num * sizeof(int)); - loadmodel->mdlmd2data_texcoords = Mem_Alloc(loadmodel->mempool, num * sizeof(float[2])); + texcoords = Mem_Alloc(loadmodel->mempool, num * sizeof(float[4])); for (i = 0;i < num;i++) { hash = md2verthashdata + i; vertremap[i] = hash->xyz; - loadmodel->mdlmd2data_texcoords[i*2+0] = hash->st[0]; - loadmodel->mdlmd2data_texcoords[i*2+1] = hash->st[1]; + texcoords[i*4+0] = hash->st[0]; + texcoords[i*4+1] = hash->st[1]; } Mem_Free(md2verthash); @@ -710,28 +827,32 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) datapointer = (base + LittleLong(pinmodel->ofs_frames)); // load the frames loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t)); - loadmodel->mdlmd2data_frames = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(md2frame_t)); - loadmodel->mdlmd2data_pose = Mem_Alloc(loadmodel->mempool, loadmodel->numverts * loadmodel->numframes * sizeof(trivertx_t)); + posedata = Mem_Alloc(loadmodel->mempool, loadmodel->numverts * loadmodel->numframes * sizeof(trivertx_t)); + vertexbuffer = Mem_Alloc(tempmempool, loadmodel->numverts * sizeof(float[4]) * 4); + svectorsbuffer = vertexbuffer + loadmodel->numverts * 4; + tvectorsbuffer = svectorsbuffer + loadmodel->numverts * 4; + normalsbuffer = tvectorsbuffer + loadmodel->numverts * 4; for (i = 0;i < loadmodel->numframes;i++) { pinframe = (md2frame_t *)datapointer; datapointer += sizeof(md2frame_t); - strcpy(loadmodel->mdlmd2data_frames[i].name, pinframe->name); for (j = 0;j < 3;j++) { - loadmodel->mdlmd2data_frames[i].scale[j] = LittleFloat(pinframe->scale[j]); - loadmodel->mdlmd2data_frames[i].translate[j] = LittleFloat(pinframe->translate[j]); + scale[j] = LittleFloat(pinframe->scale[j]); + translate[j] = LittleFloat(pinframe->translate[j]); } - Mod_MD2_ConvertVerts (loadmodel->mdlmd2data_frames[i].scale, loadmodel->mdlmd2data_frames[i].translate, (void *)datapointer, &loadmodel->mdlmd2data_pose[i * loadmodel->numverts], vertremap); + Mod_MD2_ConvertVerts(scale, translate, (void *)datapointer, posedata + i * loadmodel->numverts, vertremap); + Mod_BuildAliasVertexTextureVectors(loadmodel->numtris, elements, loadmodel->numverts, posedata + i * loadmodel->numverts, texcoords, vertexbuffer, svectorsbuffer, tvectorsbuffer, normalsbuffer); datapointer += numxyz * sizeof(trivertx_t); - strcpy(loadmodel->animscenes[i].name, loadmodel->mdlmd2data_frames[i].name); + strcpy(loadmodel->animscenes[i].name, pinframe->name); loadmodel->animscenes[i].firstframe = i; loadmodel->animscenes[i].framecount = 1; loadmodel->animscenes[i].framerate = 10; loadmodel->animscenes[i].loop = true; } + Mem_Free(vertexbuffer); Mem_Free(vertremap); @@ -748,212 +869,260 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) loadmodel->yawmins[0] = loadmodel->yawmins[1] = -(loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelyawradius); loadmodel->yawmins[2] = loadmodel->normalmins[2]; loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; -} + loadmodel->radius = modelradius; + loadmodel->radius2 = modelradius * modelradius; -static void zymswapintblock(int *m, int size) -{ - size /= 4; - while(size--) - { - *m = BigLong(*m); - m++; - } + Mod_BuildMDLMD2MeshInfo(elements, texcoords, posedata); } +extern void R_Model_Zymotic_DrawSky(entity_render_t *ent); +extern void R_Model_Zymotic_Draw(entity_render_t *ent); +extern void R_Model_Zymotic_DrawFakeShadow(entity_render_t *ent); +extern void R_Model_Zymotic_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius); +extern void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor); void Mod_LoadZymoticModel(model_t *mod, void *buffer) { - int i, pbase, *bonecount, numposes; - unsigned int count, a, b, c, *renderlist, *renderlistend; - rtexture_t **texture; - char *shadername; zymtype1header_t *pinmodel, *pheader; - zymscene_t *scene; - zymbone_t *bone; - float corner[2], modelradius; + qbyte *pbase; pinmodel = (void *)buffer; - + pbase = buffer; if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12)) Host_Error ("Mod_LoadZymoticModel: %s is not a zymotic model\n"); - if (BigLong(pinmodel->type) != 1) Host_Error ("Mod_LoadZymoticModel: only type 1 (skeletal pose) models are currently supported (name = %s)\n", loadmodel->name); loadmodel->type = mod_alias; loadmodel->aliastype = ALIASTYPE_ZYM; - - loadmodel->zymdata_header = pheader = Mem_Alloc(loadmodel->mempool, BigLong(pinmodel->filesize)); - - pbase = (int) pheader; - - memcpy(pheader, pinmodel, BigLong(pinmodel->filesize)); + loadmodel->DrawSky = NULL; + loadmodel->Draw = R_Model_Zymotic_Draw; + loadmodel->DrawFakeShadow = NULL;//R_Model_Zymotic_DrawFakeShadow; + loadmodel->DrawShadowVolume = NULL;//R_Model_Zymotic_DrawShadowVolume; + loadmodel->DrawLight = NULL;//R_Model_Zymotic_DrawLight; // byteswap header -#define SWAPLONG(var) var = BigLong(var) -#define SWAPFLOAT(var) var = BigFloat(var) -#define SWAPVEC(var) SWAPFLOAT(var[0]);SWAPFLOAT(var[1]);SWAPFLOAT(var[2]) - SWAPLONG(pheader->type); - SWAPLONG(pheader->filesize); - SWAPVEC(pheader->mins); - SWAPVEC(pheader->maxs); - SWAPFLOAT(pheader->radius); - SWAPLONG(pheader->numverts); - SWAPLONG(pheader->numtris); - SWAPLONG(pheader->numshaders); - SWAPLONG(pheader->numbones); - SWAPLONG(pheader->numscenes); - -#define SWAPLUMPINFO(var) SWAPLONG(pheader->lump_##var.start);SWAPLONG(pheader->lump_##var.length) - SWAPLUMPINFO(scenes); - SWAPLUMPINFO(poses); - SWAPLUMPINFO(bones); - SWAPLUMPINFO(vertbonecounts); - SWAPLUMPINFO(verts); - SWAPLUMPINFO(texcoords); - SWAPLUMPINFO(render); - SWAPLUMPINFO(shaders); - SWAPLUMPINFO(trizone); + pheader = pinmodel; + pheader->type = BigLong(pinmodel->type); + pheader->filesize = BigLong(pinmodel->filesize); + pheader->mins[0] = BigFloat(pinmodel->mins[0]); + pheader->mins[1] = BigFloat(pinmodel->mins[1]); + pheader->mins[2] = BigFloat(pinmodel->mins[2]); + pheader->maxs[0] = BigFloat(pinmodel->maxs[0]); + pheader->maxs[1] = BigFloat(pinmodel->maxs[1]); + pheader->maxs[2] = BigFloat(pinmodel->maxs[2]); + pheader->radius = BigFloat(pinmodel->radius); + pheader->numverts = loadmodel->zymnum_verts = BigLong(pinmodel->numverts); + pheader->numtris = loadmodel->zymnum_tris = BigLong(pinmodel->numtris); + pheader->numshaders = loadmodel->zymnum_shaders = BigLong(pinmodel->numshaders); + pheader->numbones = loadmodel->zymnum_bones = BigLong(pinmodel->numbones); + pheader->numscenes = loadmodel->zymnum_scenes = BigLong(pinmodel->numscenes); + pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start); + pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length); + pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start); + pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length); + pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start); + pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length); + pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start); + pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length); + pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start); + pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length); + pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start); + pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length); + pheader->lump_render.start = BigLong(pinmodel->lump_render.start); + pheader->lump_render.length = BigLong(pinmodel->lump_render.length); + pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start); + pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length); + pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start); + pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length); loadmodel->flags = 0; // there are no flags loadmodel->numframes = pheader->numscenes; loadmodel->synctype = ST_SYNC; loadmodel->numtris = pheader->numtris; + loadmodel->numverts = 0; - // FIXME: add skin support and texturing and shaders and... - loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) + sizeof(skinframe_t)); - loadmodel->skinscenes[0].firstframe = 0; - loadmodel->skinscenes[0].framecount = 1; - loadmodel->skinscenes[0].loop = true; - loadmodel->skinscenes[0].framerate = 10; - loadmodel->skinframes = (void *)(loadmodel->skinscenes + 1); - loadmodel->skinframes->base = NULL; - loadmodel->skinframes->fog = NULL; - loadmodel->skinframes->pants = NULL; - loadmodel->skinframes->shirt = NULL; - loadmodel->skinframes->glow = NULL; - loadmodel->skinframes->merged = NULL; - loadmodel->numskins = 1; - numposes = pheader->lump_poses.length / sizeof(float[3][4]) / pheader->numbones; - - // go through the lumps, swapping things + { + unsigned int i; + float modelradius, corner[2]; + // model bbox + modelradius = pheader->radius; + for (i = 0;i < 3;i++) + { + loadmodel->normalmins[i] = pheader->mins[i]; + loadmodel->normalmaxs[i] = pheader->maxs[i]; + loadmodel->rotatedmins[i] = -modelradius; + loadmodel->rotatedmaxs[i] = modelradius; + } + corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0])); + corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1])); + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]); + if (loadmodel->yawmaxs[0] > modelradius) + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius; + loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0]; + loadmodel->yawmins[2] = loadmodel->normalmins[2]; + loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; + loadmodel->radius = modelradius; + loadmodel->radius2 = modelradius * modelradius; + } -// zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct) - scene = (void *) (pheader->lump_scenes.start + pbase); - loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); - for (i = 0;i < pheader->numscenes;i++) - { - SWAPVEC(scene->mins); - SWAPVEC(scene->maxs); - SWAPFLOAT(scene->radius); - SWAPFLOAT(scene->framerate); - SWAPLONG(scene->flags); - SWAPLONG(scene->start); - SWAPLONG(scene->length); - - memcpy(loadmodel->animscenes[i].name, scene->name, 32); - loadmodel->animscenes[i].firstframe = scene->start; - loadmodel->animscenes[i].framecount = scene->length; - loadmodel->animscenes[i].framerate = scene->framerate; - loadmodel->animscenes[i].loop = (scene->flags & ZYMSCENEFLAG_NOLOOP) == 0; - - if ((unsigned int) loadmodel->animscenes[i].firstframe >= numposes) - Host_Error("Mod_LoadZymoticModel: scene firstframe (%i) >= numposes (%i)\n", loadmodel->animscenes[i].firstframe, numposes); - if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > numposes) - Host_Error("Mod_LoadZymoticModel: scene firstframe (%i) + framecount (%i) >= numposes (%i)\n", loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes); - if (loadmodel->animscenes[i].framerate < 0) - Host_Error("Mod_LoadZymoticModel: scene framerate (%f) < 0\n", loadmodel->animscenes[i].framerate); - scene++; + { + // FIXME: add shaders, and make them switchable shader sets and... + loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) + sizeof(skinframe_t)); + loadmodel->skinscenes[0].firstframe = 0; + loadmodel->skinscenes[0].framecount = 1; + loadmodel->skinscenes[0].loop = true; + loadmodel->skinscenes[0].framerate = 10; + loadmodel->skinframes = (void *)(loadmodel->skinscenes + 1); + loadmodel->skinframes->base = NULL; + loadmodel->skinframes->fog = NULL; + loadmodel->skinframes->pants = NULL; + loadmodel->skinframes->shirt = NULL; + loadmodel->skinframes->glow = NULL; + loadmodel->skinframes->merged = NULL; + loadmodel->numskins = 1; } -// zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data - zymswapintblock((void *) (pheader->lump_poses.start + pbase), pheader->lump_poses.length); + // go through the lumps, swapping things -// zymlump_t lump_bones; // zymbone_t bone[numbones]; - bone = (void *) (pheader->lump_bones.start + pbase); - for (i = 0;i < pheader->numbones;i++) { - SWAPLONG(bone[i].flags); - SWAPLONG(bone[i].parent); - if (bone[i].parent >= i) - Host_Error("Mod_LoadZymoticModel: bone[i].parent >= i in %s\n", loadmodel->name); + int i, numposes; + zymscene_t *scene; + // zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct) + loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); + scene = (void *) (pheader->lump_scenes.start + pbase); + numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]); + for (i = 0;i < pheader->numscenes;i++) + { + memcpy(loadmodel->animscenes[i].name, scene->name, 32); + loadmodel->animscenes[i].firstframe = BigLong(scene->start); + loadmodel->animscenes[i].framecount = BigLong(scene->length); + loadmodel->animscenes[i].framerate = BigFloat(scene->framerate); + loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0; + if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes) + Host_Error("Mod_LoadZymoticModel: scene firstframe (%i) >= numposes (%i)\n", loadmodel->animscenes[i].firstframe, numposes); + if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes) + Host_Error("Mod_LoadZymoticModel: scene firstframe (%i) + framecount (%i) >= numposes (%i)\n", loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes); + if (loadmodel->animscenes[i].framerate < 0) + Host_Error("Mod_LoadZymoticModel: scene framerate (%f) < 0\n", loadmodel->animscenes[i].framerate); + scene++; + } } -// zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better) - zymswapintblock((void *) (pheader->lump_vertbonecounts.start + pbase), pheader->lump_vertbonecounts.length); - bonecount = (void *) (pheader->lump_vertbonecounts.start + pbase); - for (i = 0;i < pheader->numbones;i++) - if (bonecount[i] < 1) - Host_Error("Mod_LoadZymoticModel: bone vertex count < 1 in %s\n", loadmodel->name); + { + int i; + float *poses; + // zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data + loadmodel->zymdata_poses = Mem_Alloc(loadmodel->mempool, pheader->lump_poses.length); + poses = (void *) (pheader->lump_poses.start + pbase); + for (i = 0;i < pheader->lump_poses.length / 4;i++) + loadmodel->zymdata_poses[i] = BigFloat(poses[i]); + } -// zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct - zymswapintblock((void *) (pheader->lump_verts.start + pbase), pheader->lump_verts.length); + { + int i; + zymbone_t *bone; + // zymlump_t lump_bones; // zymbone_t bone[numbones]; + loadmodel->zymdata_bones = Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(zymbone_t)); + bone = (void *) (pheader->lump_bones.start + pbase); + for (i = 0;i < pheader->numbones;i++) + { + memcpy(loadmodel->zymdata_bones[i].name, bone[i].name, sizeof(bone[i].name)); + loadmodel->zymdata_bones[i].flags = BigLong(bone[i].flags); + loadmodel->zymdata_bones[i].parent = BigLong(bone[i].parent); + if (loadmodel->zymdata_bones[i].parent >= i) + Host_Error("Mod_LoadZymoticModel: bone[%i].parent >= %i in %s\n", i, i, loadmodel->name); + } + } -// zymlump_t lump_texcoords; // float texcoords[numvertices][2]; - zymswapintblock((void *) (pheader->lump_texcoords.start + pbase), pheader->lump_texcoords.length); + { + int i, *bonecount; + // zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better) + loadmodel->zymdata_vertbonecounts = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int)); + bonecount = (void *) (pheader->lump_vertbonecounts.start + pbase); + for (i = 0;i < pheader->numverts;i++) + { + loadmodel->zymdata_vertbonecounts[i] = BigLong(bonecount[i]); + if (loadmodel->zymdata_vertbonecounts[i] < 1) + Host_Error("Mod_LoadZymoticModel: bone vertex count < 1 in %s\n", loadmodel->name); + } + } -// zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices) - zymswapintblock((void *) (pheader->lump_render.start + pbase), pheader->lump_render.length); - // validate renderlist and swap winding order of tris - renderlist = (void *) (pheader->lump_render.start + pbase); - renderlistend = (void *) ((qbyte *) renderlist + pheader->lump_render.length); - i = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]); - if (pheader->lump_render.length != i) - Host_Error("Mod_LoadZymoticModel: renderlist is wrong size in %s (is %i bytes, should be %i bytes)\n", loadmodel->name, pheader->lump_render.length, i); - for (i = 0;i < pheader->numshaders;i++) { - if (renderlist >= renderlistend) - Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (wrong size)\n", loadmodel->name); - count = *renderlist++; - if (renderlist + count * 3 > renderlistend) - Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (wrong size)\n", loadmodel->name); - while (count--) + int i; + zymvertex_t *vertdata; + // zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct + loadmodel->zymdata_verts = Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length); + vertdata = (void *) (pheader->lump_verts.start + pbase); + for (i = 0;i < pheader->lump_verts.length / (int) sizeof(zymvertex_t);i++) { - a = renderlist[0]; - b = renderlist[1]; - c = renderlist[2]; - if (a >= pheader->numverts || b >= pheader->numverts || c >= pheader->numverts) - Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (out of bounds index)\n", loadmodel->name); - renderlist[0] = c; - renderlist[1] = b; - renderlist[2] = a; - renderlist += 3; + loadmodel->zymdata_verts[i].bonenum = BigLong(vertdata[i].bonenum); + loadmodel->zymdata_verts[i].origin[0] = BigFloat(vertdata[i].origin[0]); + loadmodel->zymdata_verts[i].origin[1] = BigFloat(vertdata[i].origin[1]); + loadmodel->zymdata_verts[i].origin[2] = BigFloat(vertdata[i].origin[2]); } } -// zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model - shadername = (void *) (pheader->lump_shaders.start + pbase); - texture = (void *) shadername; - for (i = 0;i < pheader->numshaders;i++) { - rtexture_t *rt; - rt = loadtextureimage(loadmodel->texturepool, shadername, 0, 0, true, r_mipskins.integer, true); - shadername += 32; - *texture++ = rt; // reuse shader name list for texture pointers + int i; + float *intexcoord, *outtexcoord; + // zymlump_t lump_texcoords; // float texcoords[numvertices][2]; + loadmodel->zymdata_texcoords = outtexcoord = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(float[4])); + intexcoord = (void *) (pheader->lump_texcoords.start + pbase); + for (i = 0;i < pheader->numverts;i++) + { + outtexcoord[i*4+0] = BigFloat(intexcoord[i*2+0]); + // flip T coordinate for OpenGL + outtexcoord[i*4+1] = 1 - BigFloat(intexcoord[i*2+1]); + } } -// zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation - zymswapintblock((void *) (pheader->lump_trizone.start + pbase), pheader->lump_trizone.length); + { + int i, count, *renderlist, *renderlistend, *outrenderlist; + // zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices) + loadmodel->zymdata_renderlist = Mem_Alloc(loadmodel->mempool, pheader->lump_render.length); + // byteswap, validate, and swap winding order of tris + count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]); + if (pheader->lump_render.length != count) + Host_Error("Mod_LoadZymoticModel: renderlist is wrong size in %s (is %i bytes, should be %i bytes)\n", loadmodel->name, pheader->lump_render.length, count); + outrenderlist = loadmodel->zymdata_renderlist = Mem_Alloc(loadmodel->mempool, count); + renderlist = (void *) (pheader->lump_render.start + pbase); + renderlistend = (void *) ((qbyte *) renderlist + pheader->lump_render.length); + for (i = 0;i < pheader->numshaders;i++) + { + if (renderlist >= renderlistend) + Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (wrong size)\n", loadmodel->name); + count = BigLong(*renderlist);renderlist++; + if (renderlist + count * 3 > renderlistend) + Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (wrong size)\n", loadmodel->name); + *outrenderlist++ = count; + while (count--) + { + outrenderlist[2] = BigLong(renderlist[0]); + outrenderlist[1] = BigLong(renderlist[1]); + outrenderlist[0] = BigLong(renderlist[2]); + if ((unsigned int)outrenderlist[0] >= (unsigned int)pheader->numverts + || (unsigned int)outrenderlist[1] >= (unsigned int)pheader->numverts + || (unsigned int)outrenderlist[2] >= (unsigned int)pheader->numverts) + Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (out of bounds index)\n", loadmodel->name); + renderlist += 3; + outrenderlist += 3; + } + } + } - // model bbox - modelradius = pheader->radius; - for (i = 0;i < 3;i++) { - loadmodel->normalmins[i] = pheader->mins[i]; - loadmodel->normalmaxs[i] = pheader->maxs[i]; - loadmodel->rotatedmins[i] = -modelradius; - loadmodel->rotatedmaxs[i] = modelradius; - } - corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0])); - corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1])); - loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]); - if (loadmodel->yawmaxs[0] > modelradius) - loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius; - loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0]; - loadmodel->yawmins[2] = loadmodel->normalmins[2]; - loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; + int i; + char *shadername; + // zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model + loadmodel->zymdata_textures = Mem_Alloc(loadmodel->mempool, pheader->numshaders * sizeof(rtexture_t *)); + shadername = (void *) (pheader->lump_shaders.start + pbase); + for (i = 0;i < pheader->numshaders;i++) + loadmodel->zymdata_textures[i] = loadtextureimage(loadmodel->texturepool, shadername + i * 32, 0, 0, true, TEXF_ALPHA | TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0)); + } - loadmodel->Draw = R_DrawAliasModel; - loadmodel->DrawSky = NULL; - loadmodel->DrawShadow = NULL; + { + // zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation + loadmodel->zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris); + memcpy(loadmodel->zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris); + } } -