Convert md2 and mapmodelinfo to ObjC

FossilOrigin-Name: cfbd2ec1e63de153d5113d4f69ba8556107d9b1891e907b06745407573a45287
This commit is contained in:
Jonathan Schleifer 2025-03-04 00:51:34 +00:00
parent 6f64252d65
commit a94e06cb3b
5 changed files with 210 additions and 138 deletions

View file

@ -105,10 +105,17 @@ struct header // map file format header
struct block { struct block {
int x, y, xs, ys; int x, y, xs, ys;
}; };
struct mapmodelinfo {
int rad, h, zoff, snap; @interface MapModelInfo : OFObject
const char *name; @property (nonatomic) int rad, h, zoff, snap;
}; @property (copy, nonatomic) OFString *name;
- (instancetype)initWithRad:(int)rad
h:(int)h
zoff:(int)zoff
snap:(int)snap
name:(OFString *)name;
@end
enum { enum {
GUN_FIST = 0, GUN_FIST = 0,

View file

@ -36,17 +36,17 @@ renderentities()
{ {
entity &e = ents[i]; entity &e = ents[i];
if (e.type == MAPMODEL) { if (e.type == MAPMODEL) {
mapmodelinfo *mmi = getmminfo(e.attr2); MapModelInfo *mmi = getmminfo(e.attr2);
if (!mmi) if (mmi == nil)
continue; continue;
@autoreleasepool { @autoreleasepool {
rendermodel(@(mmi->name), 0, 1, e.attr4, rendermodel(mmi.name, 0, 1, e.attr4,
(float)mmi->rad, e.x, (float)mmi.rad, e.x,
(float)S(e.x, e.y)->floor + mmi->zoff + (float)S(e.x, e.y)->floor + mmi.zoff +
e.attr3, e.attr3,
e.y, e.y,
(float)((e.attr1 + 7) - (e.attr1 + 7) % 15), (float)((e.attr1 + 7) - (e.attr1 + 7) % 15),
0, false, 1.0f, 10.0f, mmi->snap); 0, false, 1.0f, 10.0f, mmi.snap);
} }
} else { } else {
if (OUTBORD(e.x, e.y)) if (OUTBORD(e.x, e.y))

View file

@ -59,21 +59,21 @@ mmcollide(dynent *d, float &hi, float &lo) // collide with a mapmodel
entity &e = ents[i]; entity &e = ents[i];
if (e.type != MAPMODEL) if (e.type != MAPMODEL)
continue; continue;
mapmodelinfo *mmi = getmminfo(e.attr2); MapModelInfo *mmi = getmminfo(e.attr2);
if (!mmi || !mmi->h) if (mmi == nil || !mmi.h)
continue; continue;
const float r = mmi->rad + d->radius; const float r = mmi.rad + d->radius;
if (fabs(e.x - d->o.x) < r && fabs(e.y - d->o.y) < r) { if (fabs(e.x - d->o.x) < r && fabs(e.y - d->o.y) < r) {
float mmz = float mmz =
(float)(S(e.x, e.y)->floor + mmi->zoff + e.attr3); (float)(S(e.x, e.y)->floor + mmi.zoff + e.attr3);
if (d->o.z - d->eyeheight < mmz) { if (d->o.z - d->eyeheight < mmz) {
if (mmz < hi) if (mmz < hi)
hi = mmz; hi = mmz;
} else if (mmz + mmi->h > lo) } else if (mmz + mmi.h > lo)
lo = mmz + mmi->h; lo = mmz + mmi.h;
}; }
}; }
}; }
// all collision happens here // all collision happens here
// spawn is a dirty side effect used in spawning // spawn is a dirty side effect used in spawning

View file

@ -212,7 +212,7 @@ extern void cleansound();
extern void rendermodel(OFString *mdl, int frame, int range, int tex, float rad, extern void rendermodel(OFString *mdl, int frame, int range, int tex, float rad,
float x, float y, float z, float yaw, float pitch, bool teammate, float x, float y, float z, float yaw, float pitch, bool teammate,
float scale, float speed, int snap = 0, int basetime = 0); float scale, float speed, int snap = 0, int basetime = 0);
extern mapmodelinfo *getmminfo(int i); extern MapModelInfo *getmminfo(int i);
// server // server
extern void initserver(bool dedicated, int uprate, const char *sdesc, extern void initserver(bool dedicated, int uprate, const char *sdesc,

View file

@ -24,44 +24,62 @@ struct md2_frame {
md2_vertex vertices[1]; md2_vertex vertices[1];
}; };
struct md2 { @interface MD2 : OFObject {
int numGlCommands; int _numGlCommands;
int *glCommands; int *_glCommands;
int numTriangles; int _numTriangles;
int frameSize; int _frameSize;
int numFrames; int _numFrames;
int numVerts; int _numVerts;
char *frames; char *_frames;
OFVector3D **mverts; OFVector3D **_mverts;
int displaylist; int _displaylist;
int displaylistverts; int _displaylistverts;
mapmodelinfo mmi;
char *loadname;
int mdlnum;
bool loaded;
bool load(char *filename);
void render(OFVector3D &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 @property (nonatomic) MapModelInfo *mmi;
md2::load(char *filename) @property (copy, nonatomic) OFString *loadname;
@property (nonatomic) int mdlnum;
@property (nonatomic) bool loaded;
- (bool)loadWithPath:(char *)filename;
- (void)renderWithLight:(OFVector3D &)light
frame:(int)frame
range:(int)range
x:(float)x
y:(float)y
z:(float)z
yaw:(float)yaw
pitch:(float)pitch
scale:(float)scale
speed:(float)speed
snap:(int)snap
basetime:(int)basetime;
- (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)snap;
@end
static OFMutableDictionary<OFString *, MD2 *> *mdllookup = nil;
static OFMutableArray<MD2 *> *mapmodels = nil;
@implementation MD2
+ (void)initialize
{
if (self != [MD2 class])
return;
mdllookup = [[OFMutableDictionary alloc] init];
mapmodels = [[OFMutableArray alloc] init];
}
- (void)dealloc
{
if (_glCommands)
delete[] _glCommands;
if (_frames)
delete[] _frames;
}
- (bool)loadWithPath:(char *)filename
{ {
FILE *file; FILE *file;
md2_header header; md2_header header;
@ -75,68 +93,77 @@ md2::load(char *filename)
if (header.magic != 844121161 || header.version != 8) if (header.magic != 844121161 || header.version != 8)
return false; return false;
frames = new char[header.frameSize * header.numFrames]; _frames = new char[header.frameSize * header.numFrames];
if (frames == NULL) if (_frames == NULL)
return false; return false;
fseek(file, header.offsetFrames, SEEK_SET); fseek(file, header.offsetFrames, SEEK_SET);
fread(frames, header.frameSize * header.numFrames, 1, file); fread(_frames, header.frameSize * header.numFrames, 1, file);
for (int i = 0; i < header.numFrames; ++i) { for (int i = 0; i < header.numFrames; ++i)
endianswap(frames + i * header.frameSize, sizeof(float), 6); endianswap(_frames + i * header.frameSize, sizeof(float), 6);
}
glCommands = new int[header.numGlCommands]; _glCommands = new int[header.numGlCommands];
if (glCommands == NULL) if (_glCommands == NULL)
return false; return false;
fseek(file, header.offsetGlCommands, SEEK_SET); fseek(file, header.offsetGlCommands, SEEK_SET);
fread(glCommands, header.numGlCommands * sizeof(int), 1, file); fread(_glCommands, header.numGlCommands * sizeof(int), 1, file);
endianswap(glCommands, sizeof(int), header.numGlCommands); endianswap(_glCommands, sizeof(int), header.numGlCommands);
numFrames = header.numFrames; _numFrames = header.numFrames;
numGlCommands = header.numGlCommands; _numGlCommands = header.numGlCommands;
frameSize = header.frameSize; _frameSize = header.frameSize;
numTriangles = header.numTriangles; _numTriangles = header.numTriangles;
numVerts = header.numVertices; _numVerts = header.numVertices;
fclose(file); fclose(file);
mverts = new OFVector3D *[numFrames]; _mverts = new OFVector3D *[_numFrames];
loopj(numFrames) mverts[j] = NULL; loopj(_numFrames) _mverts[j] = NULL;
return true; return true;
}; }
float float
snap(int sn, float f) snap(int sn, float f)
{ {
return sn ? (float)(((int)(f + sn * 0.5f)) & (~(sn - 1))) : f; return sn ? (float)(((int)(f + sn * 0.5f)) & (~(sn - 1))) : f;
}; }
void - (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)sn
md2::scale(int frame, float scale, int sn)
{ {
mverts[frame] = new OFVector3D[numVerts]; _mverts[frame] = new OFVector3D[_numVerts];
md2_frame *cf = (md2_frame *)((char *)frames + frameSize * frame); md2_frame *cf = (md2_frame *)((char *)_frames + _frameSize * frame);
float sc = 16.0f / scale; float sc = 16.0f / scale;
loop(vi, numVerts) loop(vi, _numVerts)
{ {
uchar *cv = (uchar *)&cf->vertices[vi].vertex; uchar *cv = (uchar *)&cf->vertices[vi].vertex;
OFVector3D *v = &(mverts[frame])[vi]; OFVector3D *v = &(_mverts[frame])[vi];
v->x = (snap(sn, cv[0] * cf->scale[0]) + cf->translate[0]) / sc; v->x = (snap(sn, cv[0] * cf->scale[0]) + cf->translate[0]) / sc;
v->y = v->y =
-(snap(sn, cv[1] * cf->scale[1]) + cf->translate[1]) / sc; -(snap(sn, cv[1] * cf->scale[1]) + cf->translate[1]) / sc;
v->z = (snap(sn, cv[2] * cf->scale[2]) + cf->translate[2]) / sc; v->z = (snap(sn, cv[2] * cf->scale[2]) + cf->translate[2]) / sc;
}; }
}; }
void - (void)renderWithLight:(OFVector3D &)light
md2::render(OFVector3D &light, int frame, int range, float x, float y, float z, frame:(int)frame
float yaw, float pitch, float sc, float speed, int snap, int basetime) range:(int)range
x:(float)x
y:(float)y
z:(float)z
yaw:(float)yaw
pitch:(float)pitch
scale:(float)sc
speed:(float)speed
snap:(int)sn
basetime:(int)basetime
{ {
loopi(range) if (!mverts[frame + i]) scale(frame + i, sc, snap); loopi(range) if (!_mverts[frame + i])[self scaleWithFrame:frame + i
scale:sc
snap:sn];
glPushMatrix(); glPushMatrix();
glTranslatef(x, y, z); glTranslatef(x, y, z);
@ -145,15 +172,15 @@ md2::render(OFVector3D &light, int frame, int range, float x, float y, float z,
glColor3fv((float *)&light); glColor3fv((float *)&light);
if (displaylist && frame == 0 && range == 1) { if (_displaylist && frame == 0 && range == 1) {
glCallList(displaylist); glCallList(_displaylist);
xtraverts += displaylistverts; xtraverts += _displaylistverts;
} else { } else {
if (frame == 0 && range == 1) { if (frame == 0 && range == 1) {
static int displaylistn = 10; static int displaylistn = 10;
glNewList(displaylist = displaylistn++, GL_COMPILE); glNewList(_displaylist = displaylistn++, GL_COMPILE);
displaylistverts = xtraverts; _displaylistverts = xtraverts;
}; }
int time = lastmillis - basetime; int time = lastmillis - basetime;
int fr1 = (int)(time / speed); int fr1 = (int)(time / speed);
@ -163,17 +190,17 @@ md2::render(OFVector3D &light, int frame, int range, float x, float y, float z,
int fr2 = fr1 + 1; int fr2 = fr1 + 1;
if (fr2 >= frame + range) if (fr2 >= frame + range)
fr2 = frame; fr2 = frame;
OFVector3D *verts1 = mverts[fr1]; OFVector3D *verts1 = _mverts[fr1];
OFVector3D *verts2 = mverts[fr2]; OFVector3D *verts2 = _mverts[fr2];
for (int *command = glCommands; (*command) != 0;) { for (int *command = _glCommands; (*command) != 0;) {
int numVertex = *command++; int numVertex = *command++;
if (numVertex > 0) { if (numVertex > 0) {
glBegin(GL_TRIANGLE_STRIP); glBegin(GL_TRIANGLE_STRIP);
} else { } else {
glBegin(GL_TRIANGLE_FAN); glBegin(GL_TRIANGLE_FAN);
numVertex = -numVertex; numVertex = -numVertex;
}; }
loopi(numVertex) loopi(numVertex)
{ {
@ -185,57 +212,61 @@ md2::render(OFVector3D &light, int frame, int range, float x, float y, float z,
OFVector3D &v2 = verts2[vn]; OFVector3D &v2 = verts2[vn];
#define ip(c) v1.c *frac2 + v2.c *frac1 #define ip(c) v1.c *frac2 + v2.c *frac1
glVertex3f(ip(x), ip(z), ip(y)); glVertex3f(ip(x), ip(z), ip(y));
}; }
xtraverts += numVertex; xtraverts += numVertex;
glEnd(); glEnd();
}; }
if (displaylist) { if (_displaylist) {
glEndList(); glEndList();
displaylistverts = xtraverts - displaylistverts; _displaylistverts = xtraverts - _displaylistverts;
}; }
}; }
glPopMatrix(); glPopMatrix();
} }
hashtable<md2 *> *mdllookup = NULL;
vector<md2 *> mapmodels;
const int FIRSTMDL = 20; const int FIRSTMDL = 20;
void void
delayedload(md2 *m) delayedload(MD2 *m)
{ {
if (!m->loaded) { if (!m.loaded) {
sprintf_sd(name1)("packages/models/%s/tris.md2", m->loadname); @autoreleasepool {
if (!m->load(path(name1))) sprintf_sd(name1)("packages/models/%s/tris.md2",
m.loadname.UTF8String);
if (![m loadWithPath:path(name1)])
fatal("loadmodel: ", name1); fatal("loadmodel: ", name1);
sprintf_sd(name2)("packages/models/%s/skin.jpg", m->loadname); sprintf_sd(name2)("packages/models/%s/skin.jpg",
m.loadname.UTF8String);
int xs, ys; int xs, ys;
installtex(FIRSTMDL + m->mdlnum, path(name2), xs, ys); installtex(FIRSTMDL + m.mdlnum, path(name2), xs, ys);
m->loaded = true; m.loaded = true;
}
} }
} }
int modelnum = 0; int modelnum = 0;
md2 * MD2 *
loadmodel(OFString *name) loadmodel(OFString *name)
{ {
@autoreleasepool { @autoreleasepool {
if (!mdllookup) MD2 *m = mdllookup[name];
mdllookup = new hashtable<md2 *>; if (m != nil)
md2 **mm = mdllookup->access(name.UTF8String); return m;
if (mm) m = [[MD2 alloc] init];
return *mm; m.mdlnum = modelnum++;
md2 *m = new md2(); MapModelInfo *mmi = [[MapModelInfo alloc] initWithRad:2
m->mdlnum = modelnum++; h:2
mapmodelinfo mmi = {2, 2, 0, 0, ""}; zoff:0
m->mmi = mmi; snap:0
m->loadname = newstring(name.UTF8String); name:@""];
mdllookup->access(m->loadname, &m); m.mmi = mmi;
m.loadname = name;
mdllookup[name] = m;
return m; return m;
} }
} }
@ -244,25 +275,29 @@ void
mapmodel( mapmodel(
OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name)
{ {
md2 *m = loadmodel(name); MD2 *m = loadmodel(name);
mapmodelinfo mmi = {(int)rad.longLongValue, (int)h.longLongValue, MapModelInfo *mmi =
(int)zoff.longLongValue, (int)snap.longLongValue, m->loadname}; [[MapModelInfo alloc] initWithRad:(int)rad.longLongValue
m->mmi = mmi; h:(int)h.longLongValue
mapmodels.add(m); zoff:(int)zoff.longLongValue
snap:(int)snap.longLongValue
name:m.loadname];
m.mmi = mmi;
[mapmodels addObject:m];
} }
COMMAND(mapmodel, ARG_5STR) COMMAND(mapmodel, ARG_5STR)
void void
mapmodelreset() mapmodelreset()
{ {
mapmodels.setsize(0); [mapmodels removeAllObjects];
} }
COMMAND(mapmodelreset, ARG_NONE) COMMAND(mapmodelreset, ARG_NONE)
mapmodelinfo * MapModelInfo *
getmminfo(int i) getmminfo(int i)
{ {
return i < mapmodels.length() ? &mapmodels[i]->mmi : NULL; return i < mapmodels.count ? mapmodels[i].mmi : nil;
} }
void void
@ -270,7 +305,7 @@ rendermodel(OFString *mdl, int frame, int range, int tex, float rad, float x,
float y, float z, float yaw, float pitch, bool teammate, float scale, float y, float z, float yaw, float pitch, bool teammate, float scale,
float speed, int snap, int basetime) float speed, int snap, int basetime)
{ {
md2 *m = loadmodel(mdl); MD2 *m = loadmodel(mdl);
if (isoccluded(player1->o.x, player1->o.y, x - rad, z - rad, rad * 2)) if (isoccluded(player1->o.x, player1->o.y, x - rad, z - rad, rad * 2))
return; return;
@ -279,7 +314,7 @@ rendermodel(OFString *mdl, int frame, int range, int tex, float rad, float x,
int xs, ys; int xs, ys;
glBindTexture(GL_TEXTURE_2D, glBindTexture(GL_TEXTURE_2D,
tex ? lookuptexture(tex, xs, ys) : FIRSTMDL + m->mdlnum); tex ? lookuptexture(tex, xs, ys) : FIRSTMDL + m.mdlnum);
int ix = (int)x; int ix = (int)x;
int iy = (int)z; int iy = (int)z;
@ -292,14 +327,44 @@ rendermodel(OFString *mdl, int frame, int range, int tex, float rad, float x,
light.x = s->r / ll + of; light.x = s->r / ll + of;
light.y = s->g / ll + of; light.y = s->g / ll + of;
light.z = s->b / ll + of; light.z = s->b / ll + of;
}; }
if (teammate) { if (teammate) {
light.x *= 0.6f; light.x *= 0.6f;
light.y *= 0.7f; light.y *= 0.7f;
light.z *= 1.2f; light.z *= 1.2f;
}; }
m->render(light, frame, range, x, y, z, yaw, pitch, scale, speed, snap, [m renderWithLight:light
basetime); frame:frame
}; range:range
x:x
y:y
z:z
yaw:yaw
pitch:pitch
scale:scale
speed:speed
snap:snap
basetime:basetime];
}
@end
@implementation MapModelInfo
- (instancetype)initWithRad:(int)rad
h:(int)h
zoff:(int)zoff
snap:(int)snap
name:(OFString *)name
{
self = [super init];
_rad = rad;
_h = h;
_zoff = zoff;
_snap = snap;
_name = [name copy];
return self;
}
@end