Cube  Artifact [d1d356a8e6]

Artifact d1d356a8e605f6b22f7536598fa243d2b1d8bcb5200096b07e208a0ea81b4302:


// rendermd2.cpp: loader code adapted from a nehe tutorial

#include "cube.h"

struct md2_header
{
    int magic;
    int version;
    int skinWidth, skinHeight;
    int frameSize;
    int numSkins, numVertices, numTexcoords;
    int numTriangles, numGlCommands, numFrames;
    int offsetSkins, offsetTexcoords, offsetTriangles;
    int offsetFrames, offsetGlCommands, offsetEnd;
};

struct md2_vertex
{
    uchar vertex[3], lightNormalIndex;
};

struct md2_frame
{
    float      scale[3];
    float      translate[3];
    char       name[16];
    md2_vertex vertices[1];
};

struct md2
{
    int numGlCommands;
    int* glCommands;
    int numTriangles;
    int frameSize;
    int numFrames;
    int numVerts;
    char* frames;
    vec **mverts;
    int displaylist;
    int displaylistverts;
    
    mapmodelinfo mmi;
    char *loadname;
    int mdlnum;
    bool loaded;

    bool load(char* filename);
    void render(vec &light, int numFrame, int range, float x, float y, float z, float yaw, float pitch, float scale, float speed, int snap, int basetime);
    void scale(int frame, float scale, int sn);

    md2() : numGlCommands(0), frameSize(0), numFrames(0), displaylist(0), loaded(false) {};

    ~md2()
    {
        if(glCommands)
            delete [] glCommands;
        if(frames)
            delete [] frames;
    }
};


bool md2::load(char* filename)
{
    FILE* file;
    md2_header header;

    if((file= fopen(filename, "rb"))==NULL) return false;

    fread(&header, sizeof(md2_header), 1, file);
    endianswap(&header, sizeof(int), sizeof(md2_header)/sizeof(int));

    if(header.magic!= 844121161 || header.version!=8) return false;

    frames = new char[header.frameSize*header.numFrames];
    if(frames==NULL) return false;

    fseek(file, header.offsetFrames, SEEK_SET);
    fread(frames, header.frameSize*header.numFrames, 1, file);

    for(int i = 0; i < header.numFrames; ++i)
    {
        endianswap(frames + i * header.frameSize, sizeof(float), 6);
    }

    glCommands = new int[header.numGlCommands];
    if(glCommands==NULL) return false;

    fseek(file,       header.offsetGlCommands, SEEK_SET);
    fread(glCommands, header.numGlCommands*sizeof(int), 1, file);

    endianswap(glCommands, sizeof(int), header.numGlCommands);

    numFrames    = header.numFrames;
    numGlCommands= header.numGlCommands;
    frameSize    = header.frameSize;
    numTriangles = header.numTriangles;
    numVerts     = header.numVertices;

    fclose(file);
    
    mverts = new vec*[numFrames];
    loopj(numFrames) mverts[j] = NULL;

    return true;
};

float snap(int sn, float f) { return sn ? (float)(((int)(f+sn*0.5f))&(~(sn-1))) : f; };

void md2::scale(int frame, float scale, int sn)
{
    mverts[frame] = new vec[numVerts];
    md2_frame *cf = (md2_frame *) ((char*)frames+frameSize*frame);
    float sc = 16.0f/scale;
    loop(vi, numVerts)
    {
        uchar *cv = (uchar *)&cf->vertices[vi].vertex;
        vec *v = &(mverts[frame])[vi];
        v->x =  (snap(sn, cv[0]*cf->scale[0])+cf->translate[0])/sc;
        v->y = -(snap(sn, cv[1]*cf->scale[1])+cf->translate[1])/sc;
        v->z =  (snap(sn, cv[2]*cf->scale[2])+cf->translate[2])/sc;
    };
};

void md2::render(vec &light, int frame, int range, float x, float y, float z, float yaw, float pitch, float sc, float speed, int snap, int basetime)
{
    loopi(range) if(!mverts[frame+i]) scale(frame+i, sc, snap);
    
    glPushMatrix ();
    glTranslatef(x, y, z);
    glRotatef(yaw+180, 0, -1, 0);
    glRotatef(pitch, 0, 0, 1);
    
	glColor3fv((float *)&light);

    if(displaylist && frame==0 && range==1)
    {
		glCallList(displaylist);
		xtraverts += displaylistverts;
    }
    else
    {
		if(frame==0 && range==1)
		{
			static int displaylistn = 10;
			glNewList(displaylist = displaylistn++, GL_COMPILE);
			displaylistverts = xtraverts;
		};
		
		int time = lastmillis-basetime;
		int fr1 = (int)(time/speed);
		float frac1 = (time-fr1*speed)/speed;
		float frac2 = 1-frac1;
		fr1 = fr1%range+frame;
		int fr2 = fr1+1;
		if(fr2>=frame+range) fr2 = frame;
		vec *verts1 = mverts[fr1];
		vec *verts2 = mverts[fr2];

		for(int *command = glCommands; (*command)!=0;)
		{
			int numVertex = *command++;
			if(numVertex>0) { glBegin(GL_TRIANGLE_STRIP); }
			else            { glBegin(GL_TRIANGLE_FAN); numVertex = -numVertex; };

			loopi(numVertex)
			{
				float tu = *((float*)command++);
				float tv = *((float*)command++);
				glTexCoord2f(tu, tv);
				int vn = *command++;
				vec &v1 = verts1[vn];
				vec &v2 = verts2[vn];
				#define ip(c) v1.c*frac2+v2.c*frac1
				glVertex3f(ip(x), ip(z), ip(y));
			};

			xtraverts += numVertex;

			glEnd();
		};
		
		if(displaylist)
		{
			glEndList();
			displaylistverts = xtraverts-displaylistverts;
		};
	};

    glPopMatrix();
}

hashtable<md2 *> *mdllookup = NULL;
vector<md2 *> mapmodels;
const int FIRSTMDL = 20;

void delayedload(md2 *m)
{ 
    if(!m->loaded)
    {
        sprintf_sd(name1)("packages/models/%s/tris.md2", m->loadname);
        if(!m->load(path(name1))) fatal("loadmodel: ", name1);
        sprintf_sd(name2)("packages/models/%s/skin.jpg", m->loadname);
        int xs, ys;
        installtex(FIRSTMDL+m->mdlnum, path(name2), xs, ys);
        m->loaded = true;
    };
};

int modelnum = 0;

md2 *loadmodel(char *name)
{
    if(!mdllookup) mdllookup = new hashtable<md2 *>;
    md2 **mm = mdllookup->access(name);
    if(mm) return *mm;
    md2 *m = new md2();
    m->mdlnum = modelnum++;
    mapmodelinfo mmi = { 2, 2, 0, 0, "" }; 
    m->mmi = mmi;
    m->loadname = newstring(name);
    mdllookup->access(m->loadname, &m);
    return m;
};

void mapmodel(char *rad, char *h, char *zoff, char *snap, char *name)
{
	md2 *m = loadmodel(name);
    mapmodelinfo mmi = { atoi(rad), atoi(h), atoi(zoff), atoi(snap), m->loadname }; 
    m->mmi = mmi;
    mapmodels.add(m);
};

void mapmodelreset() { mapmodels.setsize(0); };

mapmodelinfo &getmminfo(int i) { return i<mapmodels.length() ? mapmodels[i]->mmi : *(mapmodelinfo *)0; };

COMMAND(mapmodel, ARG_5STR);
COMMAND(mapmodelreset, ARG_NONE);

void rendermodel(char *mdl, int frame, int range, int tex, float rad, float x, float y, float z, float yaw, float pitch, bool teammate, float scale, float speed, int snap, int basetime)
{
    md2 *m = loadmodel(mdl); 
    
    if(isoccluded(player1->o.x, player1->o.y, x-rad, z-rad, rad*2)) return;

    delayedload(m);
    
    int xs, ys;
    glBindTexture(GL_TEXTURE_2D, tex ? lookuptexture(tex, xs, ys) : FIRSTMDL+m->mdlnum);
    
    int ix = (int)x;
    int iy = (int)z;
    vec light = { 1.0f, 1.0f, 1.0f }; 
    
    if(!OUTBORD(ix, iy))
    {
         sqr *s = S(ix,iy);  
         float ll = 256.0f; // 0.96f;
         float of = 0.0f; // 0.1f;      
         light.x = s->r/ll+of;
         light.y = s->g/ll+of;
         light.z = s->b/ll+of;
    };
    
    if(teammate)
    {
        light.x *= 0.6f;
        light.y *= 0.7f;
        light.z *= 1.2f;
    };

    m->render(light, frame, range, x, y, z, yaw, pitch, scale, speed, snap, basetime);
};