mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-13 16:44:50 +02:00
#3 movement using overlap info, separate mesh builder class
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
343
src/controller.h
343
src/controller.h
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
#define GRAVITY 7.0f
|
#define GRAVITY 7.0f
|
||||||
|
#define NO_OVERLAP 0x7FFFFFFF
|
||||||
|
|
||||||
struct Controller {
|
struct Controller {
|
||||||
TR::Level *level;
|
TR::Level *level;
|
||||||
@@ -29,6 +30,8 @@ struct Controller {
|
|||||||
onGround = inWater = false;
|
onGround = inWater = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void update() {}
|
||||||
|
|
||||||
void updateEntity() {
|
void updateEntity() {
|
||||||
TR::Entity &e = getEntity();
|
TR::Entity &e = getEntity();
|
||||||
e.x = int(pos.x);
|
e.x = int(pos.x);
|
||||||
@@ -64,20 +67,24 @@ struct Controller {
|
|||||||
return level->rooms[getEntity().room];
|
return level->rooms[getEntity().room];
|
||||||
}
|
}
|
||||||
|
|
||||||
TR::Room::Sector& getSector(int &dx, int &dz) {
|
TR::Room::Sector& getSector(int x, int z, int &dx, int &dz) {
|
||||||
TR::Room &room = getRoom();
|
TR::Room &room = getRoom();
|
||||||
TR::Entity &entity = getEntity();
|
|
||||||
|
int sx = x - room.info.x;
|
||||||
dx = entity.x - room.info.x;
|
int sz = z - room.info.z;
|
||||||
dz = entity.z - room.info.z;
|
dx = sx & 1023; // mod 1024
|
||||||
int sx = dx / 1024;
|
dz = sz & 1023;
|
||||||
int sz = dz / 1024;
|
sx >>= 10; // div 1024
|
||||||
dx -= sx * 1024;
|
sz >>= 10;
|
||||||
dz -= sz * 1024;
|
|
||||||
|
|
||||||
return room.sectors[sx * room.zSectors + sz];
|
return room.sectors[sx * room.zSectors + sz];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TR::Room::Sector& getSector(int &dx, int &dz) {
|
||||||
|
TR::Entity &entity = getEntity();
|
||||||
|
return getSector(entity.x, entity.z, dx, dz);
|
||||||
|
}
|
||||||
|
|
||||||
bool changeState(int state) {
|
bool changeState(int state) {
|
||||||
TR::Model &model = getModel();
|
TR::Model &model = getModel();
|
||||||
TR::Animation *anim = &level->anims[model.animation];
|
TR::Animation *anim = &level->anims[model.animation];
|
||||||
@@ -107,7 +114,113 @@ struct Controller {
|
|||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update() {}
|
struct FloorInfo {
|
||||||
|
int floor, ceiling;
|
||||||
|
int roomNext, roomBelow, roomAbove;
|
||||||
|
};
|
||||||
|
|
||||||
|
int getOverlap(int fromX, int fromY, int fromZ, int toX, int toZ) {
|
||||||
|
int dx, dz;
|
||||||
|
TR::Room::Sector &s = getSector(fromX, fromZ, dx, dz);
|
||||||
|
|
||||||
|
if (s.boxIndex == 0xFFFF) return NO_OVERLAP;
|
||||||
|
|
||||||
|
TR::Box &b = level->boxes[s.boxIndex];
|
||||||
|
if (b.contains(toX, toZ))
|
||||||
|
return b.floor;
|
||||||
|
|
||||||
|
int floor = NO_OVERLAP;
|
||||||
|
int delta = 0x7FFFFFFF;
|
||||||
|
|
||||||
|
TR::Overlap *o = &level->overlaps[b.overlap & 0x7FFF];
|
||||||
|
do {
|
||||||
|
TR::Box &b = level->boxes[o->boxIndex];
|
||||||
|
if (b.contains(toX, toZ)) { // get min delta
|
||||||
|
int d = abs(fromY - b.floor);
|
||||||
|
if (d < delta) {
|
||||||
|
floor = b.floor;
|
||||||
|
delta = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!(o++)->end);
|
||||||
|
|
||||||
|
return floor;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorInfo getFloorInfo(int x, int z) {
|
||||||
|
int dx, dz;
|
||||||
|
TR::Room::Sector &s = getSector(x, z, dx, dz);
|
||||||
|
|
||||||
|
FloorInfo info;
|
||||||
|
info.floor = 256 * (int)s.floor;
|
||||||
|
info.ceiling = 256 * (int)s.ceiling;
|
||||||
|
info.roomNext = 255;
|
||||||
|
info.roomBelow = s.roomBelow;
|
||||||
|
info.roomAbove = s.roomAbove;
|
||||||
|
|
||||||
|
if (!s.floorIndex) return info;
|
||||||
|
|
||||||
|
TR::FloorData *fd = &level->floors[s.floorIndex];
|
||||||
|
TR::FloorData::Command cmd;
|
||||||
|
|
||||||
|
do {
|
||||||
|
cmd = (*fd++).cmd;
|
||||||
|
|
||||||
|
switch (cmd.func) {
|
||||||
|
|
||||||
|
case TR::FD_PORTAL :
|
||||||
|
info.roomNext = (*fd++).data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TR::FD_FLOOR : // floor & ceiling
|
||||||
|
case TR::FD_CEILING : {
|
||||||
|
TR::FloorData::Slant slant = (*fd++).slant;
|
||||||
|
int sx = (int)slant.x;
|
||||||
|
int sz = (int)slant.z;
|
||||||
|
if (cmd.func == TR::FD_FLOOR) {
|
||||||
|
info.floor -= sx * (sx > 0 ? (dx - 1024) : dx) >> 2;
|
||||||
|
info.floor -= sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||||
|
} else {
|
||||||
|
info.ceiling -= sx * (sx < 0 ? (dx - 1024) : dx) >> 2;
|
||||||
|
info.ceiling += sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TR::FD_TRIGGER : {
|
||||||
|
TR::FloorData::TriggerInfo info = (*fd++).triggerInfo;
|
||||||
|
TR::FloorData::TriggerCommand trigCmd;
|
||||||
|
do {
|
||||||
|
trigCmd = (*fd++).triggerCmd; // trigger action
|
||||||
|
switch (trigCmd.func) {
|
||||||
|
case 0 : break; // activate item
|
||||||
|
case 1 : break; // switch to camera
|
||||||
|
case 2 : break; // camera delay
|
||||||
|
case 3 : break; // flip map
|
||||||
|
case 4 : break; // flip on
|
||||||
|
case 5 : break; // flip off
|
||||||
|
case 6 : break; // look at item
|
||||||
|
case 7 : break; // end level
|
||||||
|
case 8 : break; // play soundtrack
|
||||||
|
case 9 : break; // special hadrdcode trigger
|
||||||
|
case 10 : break; // secret found
|
||||||
|
case 11 : break; // clear bodies
|
||||||
|
case 12 : break; // flyby camera sequence
|
||||||
|
case 13 : break; // play cutscene
|
||||||
|
}
|
||||||
|
// ..
|
||||||
|
} while (!trigCmd.end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default : LOG("unknown func: %d\n", cmd.func);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (!cmd.end);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -136,6 +249,8 @@ struct Lara : Controller {
|
|||||||
TR::Model &model = getModel();
|
TR::Model &model = getModel();
|
||||||
TR::Animation *anim = &level->anims[model.animation];
|
TR::Animation *anim = &level->anims[model.animation];
|
||||||
|
|
||||||
|
fTime += Core::deltaTime;
|
||||||
|
|
||||||
float rot = 0.0f;
|
float rot = 0.0f;
|
||||||
|
|
||||||
enum { LEFT = 1 << 1,
|
enum { LEFT = 1 << 1,
|
||||||
@@ -150,6 +265,8 @@ struct Lara : Controller {
|
|||||||
WATER = 1 << 10,
|
WATER = 1 << 10,
|
||||||
DEATH = 1 << 11 };
|
DEATH = 1 << 11 };
|
||||||
|
|
||||||
|
inWater = (getRoom().flags & TR::ROOM_FLAG_WATER);
|
||||||
|
|
||||||
int mask = 0;
|
int mask = 0;
|
||||||
|
|
||||||
if (Input::down[ikW] || Input::joy.L.y < 0) mask |= FORTH;
|
if (Input::down[ikW] || Input::joy.L.y < 0) mask |= FORTH;
|
||||||
@@ -215,10 +332,13 @@ struct Lara : Controller {
|
|||||||
|
|
||||||
} else if (mask & WATER) { // underwater
|
} else if (mask & WATER) { // underwater
|
||||||
|
|
||||||
if (state == TR::STATE_FORWARD_JUMP || state == TR::STATE_BACK_JUMP || state == TR::STATE_LEFT_JUMP || state == TR::STATE_RIGHT_JUMP || state == TR::STATE_FAST_FALL) {
|
if (state == TR::STATE_FORWARD_JUMP || state == TR::STATE_UP_JUMP || state == TR::STATE_BACK_JUMP || state == TR::STATE_LEFT_JUMP || state == TR::STATE_RIGHT_JUMP || state == TR::STATE_FALL || state == TR::STATE_REACH) {
|
||||||
model.animation = TR::ANIM_WATER_FALL;
|
model.animation = TR::ANIM_WATER_FALL;
|
||||||
fTime = 0.0f;
|
fTime = 0.0f;
|
||||||
state = level->anims[model.animation].state;
|
state = level->anims[model.animation].state;
|
||||||
|
} else if (state == TR::STATE_SWAN_DIVE) {
|
||||||
|
state = TR::STATE_DIVE;
|
||||||
|
angle.x = -PI * 0.5f;
|
||||||
} else
|
} else
|
||||||
if (mask & JUMP)
|
if (mask & JUMP)
|
||||||
state = TR::STATE_SWIM;
|
state = TR::STATE_SWIM;
|
||||||
@@ -233,31 +353,46 @@ struct Lara : Controller {
|
|||||||
state = TR::STATE_REACH;
|
state = TR::STATE_REACH;
|
||||||
else if ((mask & (FORTH | WALK)) == (FORTH | WALK))
|
else if ((mask & (FORTH | WALK)) == (FORTH | WALK))
|
||||||
state = TR::STATE_SWAN_DIVE;
|
state = TR::STATE_SWAN_DIVE;
|
||||||
|
} else if (state != TR::STATE_SWAN_DIVE && state != TR::STATE_REACH && state != TR::STATE_FALL && state != TR::STATE_UP_JUMP && state != TR::STATE_BACK_JUMP && state != TR::STATE_LEFT_JUMP && state != TR::STATE_RIGHT_JUMP) {
|
||||||
|
model.animation = TR::ANIM_FALL;
|
||||||
|
state = level->anims[model.animation].state;
|
||||||
}
|
}
|
||||||
|
// state = TR::STATE_FALL;
|
||||||
// LOG("- speed: %f\n", velocity.length());
|
// LOG("- speed: %f\n", velocity.length());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to set new state
|
// try to set new state
|
||||||
if (!changeState(state)) {
|
if (!changeState(state)) {
|
||||||
int stopState = TR::STATE_FAST_FALL;
|
int stopState = TR::STATE_FALL;
|
||||||
|
|
||||||
if ((mask & (GROUND | WATER)) == (GROUND | WATER))
|
if (state == TR::STATE_DIVE)
|
||||||
|
stopState = state;
|
||||||
|
else if ((mask & (GROUND | WATER)) == (GROUND | WATER))
|
||||||
stopState = TR::STATE_SURF_TREAD;
|
stopState = TR::STATE_SURF_TREAD;
|
||||||
else if (mask & WATER)
|
else if (mask & WATER)
|
||||||
stopState = TR::STATE_TREAD;
|
stopState = TR::STATE_TREAD;
|
||||||
else if (mask & GROUND)
|
else if (mask & GROUND)
|
||||||
stopState = TR::STATE_STOP;
|
stopState = TR::STATE_STOP;
|
||||||
|
|
||||||
if (state != stopState)
|
changeState(stopState);
|
||||||
changeState(stopState);
|
/*
|
||||||
|
if (state == stopState || !changeState(stopState)) {
|
||||||
|
int stopAnim = -1;
|
||||||
|
switch (stopState) {
|
||||||
|
case TR::STATE_FALL : stopAnim = TR::ANIM_FALL; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stopAnim > -1) {
|
||||||
|
model.animation = stopAnim;
|
||||||
|
fTime = 0.0f;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
anim = &level->anims[model.animation]; // get new animation and state (if it has been changed)
|
anim = &level->anims[model.animation]; // get new animation and state (if it has been changed)
|
||||||
state = anim->state;
|
state = anim->state;
|
||||||
|
|
||||||
fTime += Core::deltaTime;
|
|
||||||
int fCount = anim->frameEnd - anim->frameStart + 1;
|
int fCount = anim->frameEnd - anim->frameStart + 1;
|
||||||
int fIndex = int(fTime * 30.0f);
|
int fIndex = int(fTime * 30.0f);
|
||||||
|
|
||||||
@@ -350,8 +485,8 @@ struct Lara : Controller {
|
|||||||
|
|
||||||
if (state == TR::STATE_SWIM) {
|
if (state == TR::STATE_SWIM) {
|
||||||
velocity = vec3(angle.x, angle.y) * 35.0f;
|
velocity = vec3(angle.x, angle.y) * 35.0f;
|
||||||
} else if (state == TR::STATE_GLIDE || state == TR::STATE_TREAD)
|
} else
|
||||||
velocity = velocity - velocity * Core::deltaTime;
|
velocity = velocity - velocity * min(1.0f, Core::deltaTime * 2.0f);
|
||||||
|
|
||||||
// TODO: apply flow velocity
|
// TODO: apply flow velocity
|
||||||
} else { // on ground
|
} else { // on ground
|
||||||
@@ -397,15 +532,20 @@ struct Lara : Controller {
|
|||||||
case 0x05 : { // play sound
|
case 0x05 : { // play sound
|
||||||
int frame = (*ptr++);
|
int frame = (*ptr++);
|
||||||
int id = (*ptr++) & 0x3FFF;
|
int id = (*ptr++) & 0x3FFF;
|
||||||
if (fIndex == frame - anim->frameStart && fIndex != lastFrame) {
|
int idx = frame - anim->frameStart;
|
||||||
|
|
||||||
|
// if (fIndex != lastFrame)
|
||||||
|
// LOG("play sound at %d current %d last %d (%d)\n", idx, fIndex, lastFrame, (int)id);
|
||||||
|
|
||||||
|
if (idx > lastFrame && idx <= fIndex) {
|
||||||
int16 a = level->soundsMap[id];
|
int16 a = level->soundsMap[id];
|
||||||
TR::SoundInfo &b = level->soundsInfo[a];
|
TR::SoundInfo &b = level->soundsInfo[a];
|
||||||
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
|
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
|
||||||
uint32 c = level->soundOffsets[b.offset + rand() % ((b.flags & 0xFF) >> 2)];
|
uint32 c = level->soundOffsets[b.offset + rand() % ((b.flags & 0xFF) >> 2)];
|
||||||
LOG("count %d\n", int(((b.flags & 0xFF) >> 2)));
|
|
||||||
|
|
||||||
void *p = &level->soundData[c];
|
void *p = &level->soundData[c];
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
// LOG("play\n");
|
||||||
PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
|
PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -425,15 +565,16 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// check for next animation
|
// check for next animation
|
||||||
if (endFrame) {
|
if (endFrame) {
|
||||||
model.animation = anim->nextAnimation;
|
model.animation = anim->nextAnimation;
|
||||||
TR::Animation *nextAnim = &level->anims[anim->nextAnimation];
|
TR::Animation *nextAnim = &level->anims[anim->nextAnimation];
|
||||||
fTime = (anim->nextFrame - nextAnim->frameStart) / 30.0f;
|
fIndex = anim->nextFrame - nextAnim->frameStart;
|
||||||
|
fTime = fIndex / 30.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
move(velocity * dt);
|
move(velocity * dt);
|
||||||
collide();
|
collide();
|
||||||
|
|
||||||
@@ -444,21 +585,16 @@ struct Lara : Controller {
|
|||||||
vec3 p = pos;
|
vec3 p = pos;
|
||||||
pos = pos + offset;
|
pos = pos + offset;
|
||||||
|
|
||||||
updateEntity();
|
int d = getOverlap((int)p.x, (int)p.y, (int)p.z, (int)pos.x, (int)pos.z);
|
||||||
|
|
||||||
inWater = getRoom().flags & TR::ROOM_FLAG_WATER;
|
int state = level->anims[getModel().animation].state;
|
||||||
|
bool stop = false;
|
||||||
|
|
||||||
TR::Room &room = getRoom();
|
if ((d == NO_OVERLAP) ||
|
||||||
TR::Entity &entity = getEntity();
|
((state == TR::STATE_WALK || state == TR::STATE_BACK || state == TR::STATE_STEP_LEFT || state == TR::STATE_STEP_RIGHT) && (int)p.y - d < -256) ||
|
||||||
|
((int)p.y - d > 256)) {
|
||||||
|
|
||||||
int dx, dz;
|
|
||||||
TR::Room::Sector &s = getSector(dx, dz);
|
|
||||||
|
|
||||||
int d = entity.y - s.floor * 256;
|
|
||||||
if (d >= 256 * 4) {
|
|
||||||
LOG("wall %d\n", d);
|
|
||||||
pos = p;
|
pos = p;
|
||||||
updateEntity();
|
|
||||||
|
|
||||||
TR::Model &model = getModel();
|
TR::Model &model = getModel();
|
||||||
TR::Animation *anim = &level->anims[model.animation];
|
TR::Animation *anim = &level->anims[model.animation];
|
||||||
@@ -470,6 +606,7 @@ struct Lara : Controller {
|
|||||||
else
|
else
|
||||||
model.animation = TR::ANIM_STAND;
|
model.animation = TR::ANIM_STAND;
|
||||||
velocity.x = velocity.z = 0.0f;
|
velocity.x = velocity.z = 0.0f;
|
||||||
|
fTime = 0;
|
||||||
} else if (inWater) { // in water
|
} else if (inWater) { // in water
|
||||||
// do nothing
|
// do nothing
|
||||||
//velocity.x = velocity.z = 0.0f;
|
//velocity.x = velocity.z = 0.0f;
|
||||||
@@ -478,96 +615,52 @@ struct Lara : Controller {
|
|||||||
velocity.x = -velocity.x * 0.5f;
|
velocity.x = -velocity.x * 0.5f;
|
||||||
velocity.z = -velocity.z * 0.5f;
|
velocity.z = -velocity.z * 0.5f;
|
||||||
velocity.y = 0.0f;
|
velocity.y = 0.0f;
|
||||||
|
fTime = 0;
|
||||||
}
|
}
|
||||||
fTime = 0;
|
|
||||||
|
} else {
|
||||||
|
TR::Entity &entity = getEntity();
|
||||||
|
entity.x = (int)pos.x;
|
||||||
|
entity.y = (int)pos.y;
|
||||||
|
entity.z = (int)pos.z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void collide() {
|
void collide() {
|
||||||
int dx, dz;
|
|
||||||
TR::Room::Sector &s = getSector(dx, dz);
|
|
||||||
TR::Entity &entity = getEntity();
|
TR::Entity &entity = getEntity();
|
||||||
|
|
||||||
float floor = s.floor * 256.0f;
|
FloorInfo info = getFloorInfo(entity.x, entity.z);
|
||||||
float ceiling = s.ceiling * 256.0f;
|
|
||||||
|
/*
|
||||||
float fx = dx / 1024.0f, fz = dz / 1024.0f;
|
|
||||||
|
|
||||||
uint16 cmd, *d = &level->floors[s.floorIndex];
|
|
||||||
|
|
||||||
if (s.floorIndex)
|
|
||||||
do {
|
|
||||||
cmd = *d++;
|
|
||||||
int func = cmd & 0x00FF; // function
|
|
||||||
int sub = (cmd & 0x7F00) >> 8; // sub function
|
|
||||||
|
|
||||||
switch (func) {
|
|
||||||
case 1 :
|
|
||||||
entity.room = *d++;
|
|
||||||
break;
|
|
||||||
case 2 :
|
|
||||||
case 3 : {
|
|
||||||
int sx = (int8)(*d & 0x00FF);
|
|
||||||
int sz = (int8)((*d & 0xFF00) >> 8);
|
|
||||||
|
|
||||||
if (func == 2) {
|
|
||||||
if (sx > 0)
|
|
||||||
floor += sx * (1024 - dx) >> 2;
|
|
||||||
else
|
|
||||||
floor -= sx * dx >> 2;
|
|
||||||
|
|
||||||
if (sz > 0)
|
|
||||||
floor += sz * (1024 - dz) >> 2;
|
|
||||||
else
|
|
||||||
floor -= sz * dz >> 2;
|
|
||||||
} else {
|
|
||||||
if (sx < 0)
|
|
||||||
ceiling += sx * (1024 - dx) >> 2;
|
|
||||||
else
|
|
||||||
ceiling -= sx * dx >> 2;
|
|
||||||
|
|
||||||
if (sz > 0)
|
|
||||||
ceiling -= sz * (1024 - dz) >> 2;
|
|
||||||
else
|
|
||||||
ceiling += sz * dz >> 2;
|
|
||||||
}
|
|
||||||
d++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4 : {
|
|
||||||
/*
|
|
||||||
if (sub == 0x00) LOG("trigger\n");
|
|
||||||
if (sub == 0x01) LOG("pad\n");
|
|
||||||
if (sub == 0x02) LOG("switch\n");
|
|
||||||
if (sub == 0x03) LOG("key\n");
|
|
||||||
if (sub == 0x04) LOG("pickup\n");
|
|
||||||
if (sub == 0x05) LOG("heavy-trigger\n");
|
|
||||||
if (sub == 0x06) LOG("anti-pad\n");
|
|
||||||
if (sub == 0x07) LOG("combat\n");
|
|
||||||
if (sub == 0x08) LOG("dummy\n");
|
|
||||||
if (sub == 0x09) LOG("anti-trigger\n");
|
|
||||||
*/
|
|
||||||
uint16 act;
|
|
||||||
do {
|
|
||||||
act = *d++; // trigger action
|
|
||||||
} while (!(act & 0x8000));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default :
|
|
||||||
LOG("unknown func: %d\n", func);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (!(cmd & 0x8000));
|
|
||||||
|
|
||||||
float hmin = 0.0f, hmax = -768.0f;
|
float hmin = 0.0f, hmax = -768.0f;
|
||||||
if (inWater) {
|
if (inWater) {
|
||||||
hmin = 256.0f + 128.0f;
|
hmin = 256.0f + 128.0f;
|
||||||
hmax = -256.0f - 128.0f;
|
hmax = -256.0f - 128.0f;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
onGround = (pos.y >= floor) && (s.roomBelow == 0xFF) && !(getRoom().flags & TR::ROOM_FLAG_WATER);
|
if (info.roomNext != 0xFF)
|
||||||
|
entity.room = info.roomNext;
|
||||||
|
|
||||||
|
if (entity.y >= info.floor) {
|
||||||
|
if (info.roomBelow == 0xFF) {
|
||||||
|
entity.y = info.floor;
|
||||||
|
pos.y = entity.y;
|
||||||
|
velocity.y = 0.0f;
|
||||||
|
} else
|
||||||
|
entity.room = info.roomBelow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.y <= info.ceiling) {
|
||||||
|
if (info.roomAbove == 0xFF) {
|
||||||
|
entity.y = info.ceiling;
|
||||||
|
pos.y = entity.y;
|
||||||
|
velocity.y = -velocity.y;
|
||||||
|
} else
|
||||||
|
entity.room = info.roomAbove;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (pos.y + hmin >= floor) {
|
if (pos.y + hmin >= floor) {
|
||||||
if (s.roomBelow == 0xFF) {
|
if (s.roomBelow == 0xFF) {
|
||||||
pos.y = floor - hmin;
|
pos.y = floor - hmin;
|
||||||
@@ -579,12 +672,30 @@ struct Lara : Controller {
|
|||||||
if (pos.y + hmax <= ceiling) {
|
if (pos.y + hmax <= ceiling) {
|
||||||
if (s.roomAbove == 0xFF) {
|
if (s.roomAbove == 0xFF) {
|
||||||
pos.y = ceiling - hmax;
|
pos.y = ceiling - hmax;
|
||||||
velocity.y = 0.0f;
|
velocity.y = -velocity.y;
|
||||||
} else
|
} else
|
||||||
entity.room = s.roomAbove;
|
entity.room = s.roomAbove;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
entity.y = (int)pos.y;
|
|
||||||
|
int state = level->anims[getModel().animation].state;
|
||||||
|
|
||||||
|
// TODO: use a brain!
|
||||||
|
float extra = 0;
|
||||||
|
if (state == TR::STATE_WALK ||
|
||||||
|
state == TR::STATE_RUN ||
|
||||||
|
state == TR::STATE_STOP ||
|
||||||
|
state == TR::STATE_FAST_BACK ||
|
||||||
|
state == TR::STATE_TURN_RIGHT ||
|
||||||
|
state == TR::STATE_TURN_LEFT ||
|
||||||
|
state == TR::STATE_BACK ||
|
||||||
|
state == TR::STATE_FAST_TURN ||
|
||||||
|
state == TR::STATE_STEP_RIGHT ||
|
||||||
|
state == TR::STATE_STEP_LEFT ||
|
||||||
|
state == TR::STATE_ROLL)
|
||||||
|
extra = 256 + 128;
|
||||||
|
|
||||||
|
onGround = (pos.y + extra >= info.floor) && (info.roomBelow == 0xFF) && !(getRoom().flags & TR::ROOM_FLAG_WATER);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
174
src/debug.h
174
src/debug.h
@@ -112,35 +112,37 @@ namespace Debug {
|
|||||||
|
|
||||||
namespace Level {
|
namespace Level {
|
||||||
|
|
||||||
void debugFloor(const TR::Level &level, const vec3 &f, const vec3 &c, int floorIndex, bool current) {
|
void debugFloor(const TR::Level &level, const vec3 &f, const vec3 &c, int floorIndex, int boxIndex, bool current) {
|
||||||
vec3 vf[4] = { f, f + vec3(1024, 0, 0), f + vec3(1024, 0, 1024), f + vec3(0, 0, 1024) };
|
vec3 vf[4] = { f, f + vec3(1024, 0, 0), f + vec3(1024, 0, 1024), f + vec3(0, 0, 1024) };
|
||||||
vec3 vc[4] = { c, c + vec3(1024, 0, 0), c + vec3(1024, 0, 1024), c + vec3(0, 0, 1024) };
|
vec3 vc[4] = { c, c + vec3(1024, 0, 0), c + vec3(1024, 0, 1024), c + vec3(0, 0, 1024) };
|
||||||
|
|
||||||
uint16 cmd, *d = &level.floors[floorIndex];
|
|
||||||
|
|
||||||
if (floorIndex)
|
if (current)
|
||||||
do {
|
glColor3f(1, 1, 1);
|
||||||
cmd = *d++;
|
else
|
||||||
int func = cmd & 0x00FF; // function
|
glColor3f(0, 1, 0);
|
||||||
int sub = (cmd & 0x7F00) >> 8; // sub function
|
|
||||||
|
|
||||||
if (func == 0x01) { // portal
|
bool isPortal = false;
|
||||||
d++;
|
|
||||||
// d += 2;
|
|
||||||
|
|
||||||
}
|
TR::FloorData *fd = &level.floors[floorIndex];
|
||||||
|
TR::FloorData::Command cmd;
|
||||||
if ((func == 0x02 || func == 0x03) && sub == 0x00) { // floor & ceiling corners
|
do {
|
||||||
int sx = 256 * int((int8)(*d & 0x00FF));
|
cmd = (*fd++).cmd;
|
||||||
int sz = 256 * int((int8)((*d & 0xFF00) >> 8));
|
|
||||||
|
switch (cmd.func) {
|
||||||
auto &p = func == 0x02 ? vf : vc;
|
case TR::FD_PORTAL :
|
||||||
|
isPortal = true;
|
||||||
if (func == 0x02) {
|
fd++;
|
||||||
|
break; // portal
|
||||||
// if (current)
|
case TR::FD_FLOOR : // floor & ceiling
|
||||||
// LOG("%d\n", sx);
|
case TR::FD_CEILING : {
|
||||||
|
TR::FloorData::Slant slant = (*fd++).slant;
|
||||||
|
int sx = 256 * (int)slant.x;
|
||||||
|
int sz = 256 * (int)slant.z;
|
||||||
|
|
||||||
|
auto &p = cmd.func == 0x02 ? vf : vc;
|
||||||
|
|
||||||
|
if (cmd.func == 0x02) { // floor
|
||||||
if (sx > 0) {
|
if (sx > 0) {
|
||||||
p[0].y += sx;
|
p[0].y += sx;
|
||||||
p[3].y += sx;
|
p[3].y += sx;
|
||||||
@@ -156,9 +158,7 @@ namespace Debug {
|
|||||||
p[3].y -= sz;
|
p[3].y -= sz;
|
||||||
p[2].y -= sz;
|
p[2].y -= sz;
|
||||||
}
|
}
|
||||||
|
} else { // ceiling
|
||||||
} else {
|
|
||||||
|
|
||||||
if (sx < 0) {
|
if (sx < 0) {
|
||||||
p[0].y += sx;
|
p[0].y += sx;
|
||||||
p[3].y += sx;
|
p[3].y += sx;
|
||||||
@@ -174,40 +174,39 @@ namespace Debug {
|
|||||||
p[3].y += sz;
|
p[3].y += sz;
|
||||||
p[2].y += sz;
|
p[2].y += sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
d++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (func == 0x04) {
|
|
||||||
//*d++; // trigger setup
|
|
||||||
/*
|
|
||||||
if (sub == 0x00) LOG("trigger\n");
|
|
||||||
if (sub == 0x01) LOG("pad\n");
|
|
||||||
if (sub == 0x02) LOG("switch\n");
|
|
||||||
if (sub == 0x03) LOG("key\n");
|
|
||||||
if (sub == 0x04) LOG("pickup\n");
|
|
||||||
if (sub == 0x05) LOG("heavy-trigger\n");
|
|
||||||
if (sub == 0x06) LOG("anti-pad\n");
|
|
||||||
if (sub == 0x07) LOG("combat\n");
|
|
||||||
if (sub == 0x08) LOG("dummy\n");
|
|
||||||
if (sub == 0x09) LOG("anti-trigger\n");
|
|
||||||
*/
|
|
||||||
uint16 act;
|
|
||||||
do {
|
|
||||||
act = *d++; // trigger action
|
|
||||||
} while (!(act & 0x8000));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TR::FD_TRIGGER : {
|
||||||
} while (!(cmd & 0x8000));
|
TR::FloorData::TriggerInfo info = (*fd++).triggerInfo;
|
||||||
|
TR::FloorData::TriggerCommand trigCmd;
|
||||||
if (current)
|
glColor3f(1, 0, 1);
|
||||||
glColor3f(1, 1, 1);
|
do {
|
||||||
else
|
trigCmd = (*fd++).triggerCmd; // trigger action
|
||||||
glColor3f(0, 1, 0);
|
switch (trigCmd.func) {
|
||||||
|
case 0 : break; // activate item
|
||||||
|
case 1 : break; // switch to camera
|
||||||
|
case 2 : break; // camera delay
|
||||||
|
case 3 : break; // flip map
|
||||||
|
case 4 : break; // flip on
|
||||||
|
case 5 : break; // flip off
|
||||||
|
case 6 : break; // look at item
|
||||||
|
case 7 : break; // end level
|
||||||
|
case 8 : break; // play soundtrack
|
||||||
|
case 9 : break; // special hadrdcode trigger
|
||||||
|
case 10 : break; // secret found
|
||||||
|
case 11 : break; // clear bodies
|
||||||
|
case 12 : break; // flyby camera sequence
|
||||||
|
case 13 : break; // play cutscene
|
||||||
|
}
|
||||||
|
} while (!trigCmd.end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default :
|
||||||
|
if (!cmd.end)
|
||||||
|
LOG("unknown func %d : %d\n", cmd.func, cmd.sub);
|
||||||
|
}
|
||||||
|
} while (!cmd.end);
|
||||||
|
|
||||||
glBegin(GL_LINE_STRIP);
|
glBegin(GL_LINE_STRIP);
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
@@ -217,8 +216,43 @@ namespace Debug {
|
|||||||
glColor3f(1, 0, 0);
|
glColor3f(1, 0, 0);
|
||||||
glBegin(GL_LINE_STRIP);
|
glBegin(GL_LINE_STRIP);
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
glVertex3fv((GLfloat*)&vc[i % 4]);
|
glVertex3fv((GLfloat*)&vc[i % 4]);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
|
if (isPortal) {
|
||||||
|
glColor4f(0.0f, 0.0f, 1.0f, 0.5f);
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (int i = 3; i >= 0; i--)
|
||||||
|
glVertex3fv((GLfloat*)&vf[i]);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boxIndex == 0xFFFF) {
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
float x = f.x + 512.0f, z = f.z + 512.0f;
|
||||||
|
glVertex3f(x, f.y, z);
|
||||||
|
glVertex3f(x, c.y, z);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugBox(const TR::Box &b) {
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
float y = b.floor - 16.0f;
|
||||||
|
glVertex3f(b.minX, y, b.maxZ);
|
||||||
|
glVertex3f(b.maxX, y, b.maxZ);
|
||||||
|
glVertex3f(b.maxX, y, b.minZ);
|
||||||
|
glVertex3f(b.minX, y, b.minZ);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugOverlaps(const TR::Level &level, int boxIndex) {
|
||||||
|
glColor4f(1.0f, 1.0f, 0.0f, 0.25f);
|
||||||
|
TR::Overlap *o = &level.overlaps[level.boxes[boxIndex].overlap & 0x7FFF];
|
||||||
|
do {
|
||||||
|
TR::Box &b = level.boxes[o->boxIndex];
|
||||||
|
debugBox(b);
|
||||||
|
} while (!(o++)->end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugSectors(const TR::Level &level, const vec3 &pos, int roomIndex) {
|
void debugSectors(const TR::Level &level, const vec3 &pos, int roomIndex) {
|
||||||
@@ -229,15 +263,30 @@ namespace Debug {
|
|||||||
for (int z = 0; z < room.zSectors; z++)
|
for (int z = 0; z < room.zSectors; z++)
|
||||||
for (int x = 0; x < room.xSectors; x++) {
|
for (int x = 0; x < room.xSectors; x++) {
|
||||||
auto &s = room.sectors[x * room.zSectors + z];
|
auto &s = room.sectors[x * room.zSectors + z];
|
||||||
vec3 f(x * 1024 + room.info.x, s.floor * 256, z * 1024 + room.info.z);
|
float floor = s.floor * 256;
|
||||||
vec3 c(x * 1024 + room.info.x, s.ceiling * 256, z * 1024 + room.info.z);
|
/*
|
||||||
|
if (s.boxIndex < 0xFFFF) {
|
||||||
|
auto &b = level.boxes[s.boxIndex];
|
||||||
|
// floor = b.floor;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
vec3 f(x * 1024 + room.info.x, floor - 1, z * 1024 + room.info.z);
|
||||||
|
vec3 c(x * 1024 + room.info.x, s.ceiling * 256 + 1, z * 1024 + room.info.z);
|
||||||
|
|
||||||
debugFloor(level, f, c, s.floorIndex, (int)p.x == x && (int)p.z == z);
|
bool current = (int)p.x == x && (int)p.z == z;
|
||||||
|
debugFloor(level, f, c, s.floorIndex, s.boxIndex, current);
|
||||||
|
|
||||||
|
if (current && s.boxIndex != 0xFFFF && level.boxes[s.boxIndex].overlap != 0xFFFF) {
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glColor4f(0.0f, 1.0f, 0.0f, 0.25f);
|
||||||
|
debugBox(level.boxes[s.boxIndex]);
|
||||||
|
debugOverlaps(level, s.boxIndex);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rooms(const TR::Level &level, const vec3 &pos, int roomIndex) {
|
void rooms(const TR::Level &level, const vec3 &pos, int roomIndex) {
|
||||||
Core::setBlending(bmAdd);
|
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
for (int i = 0; i < level.roomsCount; i++) {
|
||||||
@@ -251,11 +300,10 @@ namespace Debug {
|
|||||||
} else
|
} else
|
||||||
glColor3f(1, 1, 1);
|
glColor3f(1, 1, 1);
|
||||||
|
|
||||||
Debug::Draw::box(p, p + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024));
|
// Debug::Draw::box(p, p + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
Core::setBlending(bmAlpha);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void portals(const TR::Level &level) {
|
void portals(const TR::Level &level) {
|
||||||
|
60
src/format.h
60
src/format.h
@@ -11,6 +11,13 @@ namespace TR {
|
|||||||
ROOM_FLAG_VISIBLE = 0x8000
|
ROOM_FLAG_VISIBLE = 0x8000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FD_PORTAL = 1,
|
||||||
|
FD_FLOOR = 2,
|
||||||
|
FD_CEILING = 3,
|
||||||
|
FD_TRIGGER = 4,
|
||||||
|
};
|
||||||
|
|
||||||
#define DATA_PORTAL 0x01
|
#define DATA_PORTAL 0x01
|
||||||
#define DATA_FLOOR 0x02
|
#define DATA_FLOOR 0x02
|
||||||
#define DATA_CEILING 0x03
|
#define DATA_CEILING 0x03
|
||||||
@@ -65,6 +72,7 @@ namespace TR {
|
|||||||
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
|
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
|
||||||
enum LaraAnim : int32 {
|
enum LaraAnim : int32 {
|
||||||
ANIM_STAND = 11,
|
ANIM_STAND = 11,
|
||||||
|
ANIM_FALL = 34,
|
||||||
ANIM_SMASH_JUMP = 32,
|
ANIM_SMASH_JUMP = 32,
|
||||||
ANIM_SMASH_RUN_LEFT = 53,
|
ANIM_SMASH_RUN_LEFT = 53,
|
||||||
ANIM_SMASH_RUN_RIGHT = 54,
|
ANIM_SMASH_RUN_RIGHT = 54,
|
||||||
@@ -82,7 +90,7 @@ namespace TR {
|
|||||||
STATE_TURN_RIGHT,
|
STATE_TURN_RIGHT,
|
||||||
STATE_TURN_LEFT,
|
STATE_TURN_LEFT,
|
||||||
STATE_DEATH,
|
STATE_DEATH,
|
||||||
STATE_FAST_FALL,
|
STATE_FALL,
|
||||||
STATE_HANG,
|
STATE_HANG,
|
||||||
STATE_REACH,
|
STATE_REACH,
|
||||||
STATE_SPLAT,
|
STATE_SPLAT,
|
||||||
@@ -129,25 +137,6 @@ namespace TR {
|
|||||||
STATE_FAST_DIVE,
|
STATE_FAST_DIVE,
|
||||||
STATE_HANDSTAND,
|
STATE_HANDSTAND,
|
||||||
STATE_WATER_OUT,
|
STATE_WATER_OUT,
|
||||||
STATE_CLIMB_START_AND_STANDING,
|
|
||||||
STATE_CLIMB_UP,
|
|
||||||
STATE_CLIMB_LEFT,
|
|
||||||
STATE_CLIMB_END,
|
|
||||||
STATE_CLIMB_RIGHT,
|
|
||||||
STATE_CLIMB_DOWN,
|
|
||||||
STATE_NULL_62,
|
|
||||||
STATE_NULL_63,
|
|
||||||
STATE_NULL_64,
|
|
||||||
STATE_WADE,
|
|
||||||
STATE_WATER_ROLL,
|
|
||||||
STATE_PICK_UP_FLARE,
|
|
||||||
STATE_NULL_68,
|
|
||||||
STATE_NULL_69,
|
|
||||||
STATE_DEATH_SLIDE,
|
|
||||||
STATE_DUCK,
|
|
||||||
STATE_DUCK_72,
|
|
||||||
STATE_DASH,
|
|
||||||
STATE_DASH_DIVE,
|
|
||||||
STATE_MAX };
|
STATE_MAX };
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
@@ -257,6 +246,26 @@ namespace TR {
|
|||||||
} *meshes;
|
} *meshes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union FloorData {
|
||||||
|
uint16 data;
|
||||||
|
struct Command {
|
||||||
|
uint16 func:8, sub:7, end:1;
|
||||||
|
} cmd;
|
||||||
|
struct Slant {
|
||||||
|
int8 x:8, z:8;
|
||||||
|
} slant;
|
||||||
|
struct TriggerInfo {
|
||||||
|
uint16 timer:8, once:1, mask:5, :2;
|
||||||
|
} triggerInfo;
|
||||||
|
struct TriggerCommand {
|
||||||
|
uint16 args:10, func:5, end:1;
|
||||||
|
} triggerCmd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Overlap {
|
||||||
|
uint16 boxIndex:15, end:1;
|
||||||
|
};
|
||||||
|
|
||||||
struct Mesh {
|
struct Mesh {
|
||||||
Vertex center;
|
Vertex center;
|
||||||
int32 radius;
|
int32 radius;
|
||||||
@@ -417,7 +426,11 @@ namespace TR {
|
|||||||
int32 minZ, maxZ; // Horizontal dimensions in global units
|
int32 minZ, maxZ; // Horizontal dimensions in global units
|
||||||
int32 minX, maxX;
|
int32 minX, maxX;
|
||||||
int16 floor; // Height value in global units
|
int16 floor; // Height value in global units
|
||||||
int16 overlap; // Index into Overlaps[].
|
uint16 overlap; // Index into Overlaps[].
|
||||||
|
|
||||||
|
bool contains(int x, int z) {
|
||||||
|
return x >= minX && x <= maxX && z >= minZ && z <= maxZ;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Zone {
|
struct Zone {
|
||||||
@@ -434,6 +447,7 @@ namespace TR {
|
|||||||
uint16 chance; // If !=0 and ((rand()&0x7fff) > Chance), this sound is not played
|
uint16 chance; // If !=0 and ((rand()&0x7fff) > Chance), this sound is not played
|
||||||
uint16 flags; // Bits 0-1: Looped flag, bits 2-5: num samples, bits 6-7: UNUSED
|
uint16 flags; // Bits 0-1: Looped flag, bits 2-5: num samples, bits 6-7: UNUSED
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
struct Level {
|
struct Level {
|
||||||
@@ -450,7 +464,7 @@ namespace TR {
|
|||||||
Room *rooms;
|
Room *rooms;
|
||||||
|
|
||||||
int32 floorsCount;
|
int32 floorsCount;
|
||||||
uint16 *floors;
|
FloorData *floors;
|
||||||
|
|
||||||
int32 meshDataSize;
|
int32 meshDataSize;
|
||||||
uint16 *meshData;
|
uint16 *meshData;
|
||||||
@@ -500,7 +514,7 @@ namespace TR {
|
|||||||
int32 boxesCount;
|
int32 boxesCount;
|
||||||
Box *boxes;
|
Box *boxes;
|
||||||
int32 overlapsCount;
|
int32 overlapsCount;
|
||||||
uint16 *overlaps;
|
Overlap *overlaps;
|
||||||
Zone *zones;
|
Zone *zones;
|
||||||
|
|
||||||
int32 animTexturesDataSize;
|
int32 animTexturesDataSize;
|
||||||
|
430
src/level.h
430
src/level.h
@@ -21,35 +21,21 @@ struct Level {
|
|||||||
TR::Level level;
|
TR::Level level;
|
||||||
Shader *shaders[shMAX];
|
Shader *shaders[shMAX];
|
||||||
Texture *atlas;
|
Texture *atlas;
|
||||||
Mesh *mesh;
|
MeshBuilder *mesh;
|
||||||
|
|
||||||
Controller *lara;
|
Controller *lara;
|
||||||
|
|
||||||
float time;
|
float time;
|
||||||
|
|
||||||
struct RoomRange {
|
|
||||||
MeshRange geometry;
|
|
||||||
MeshRange sprites;
|
|
||||||
} *roomRanges;
|
|
||||||
MeshRange *spriteRanges;
|
|
||||||
|
|
||||||
Camera camera;
|
Camera camera;
|
||||||
|
|
||||||
int mCount;
|
|
||||||
struct MeshInfo : MeshRange {
|
|
||||||
int offset;
|
|
||||||
TR::Vertex center;
|
|
||||||
int32 radius;
|
|
||||||
} *meshInfo;
|
|
||||||
|
|
||||||
Level(Stream &stream) : level{stream}, time(0.0f) {
|
Level(Stream &stream) : level{stream}, time(0.0f) {
|
||||||
shaders[shStatic] = new Shader(SHADER);
|
shaders[shStatic] = new Shader(SHADER);
|
||||||
shaders[shCaustics] = new Shader(SHADER, "#define CAUSTICS\n");
|
shaders[shCaustics] = new Shader(SHADER, "#define CAUSTICS\n");
|
||||||
shaders[shSprite] = new Shader(SHADER, "#define SPRITE\n");
|
shaders[shSprite] = new Shader(SHADER, "#define SPRITE\n");
|
||||||
|
|
||||||
|
|
||||||
initAtlas();
|
initAtlas();
|
||||||
initMesh();
|
|
||||||
|
mesh = new MeshBuilder(level);
|
||||||
|
|
||||||
int entity = 0;
|
int entity = 0;
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
@@ -74,9 +60,6 @@ struct Level {
|
|||||||
delete shaders[i];
|
delete shaders[i];
|
||||||
delete atlas;
|
delete atlas;
|
||||||
delete mesh;
|
delete mesh;
|
||||||
delete[] roomRanges;
|
|
||||||
delete[] meshInfo;
|
|
||||||
delete[] spriteRanges;
|
|
||||||
|
|
||||||
delete lara;
|
delete lara;
|
||||||
}
|
}
|
||||||
@@ -116,394 +99,6 @@ struct Level {
|
|||||||
delete[] data;
|
delete[] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSprite(Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 x, int16 y, int16 z, const TR::SpriteTexture &sprite, uint8 intensity) {
|
|
||||||
int vIndex = vCount - vStart;
|
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
|
||||||
indices[iCount + 1] = vIndex + 1;
|
|
||||||
indices[iCount + 2] = vIndex + 2;
|
|
||||||
|
|
||||||
indices[iCount + 3] = vIndex + 0;
|
|
||||||
indices[iCount + 4] = vIndex + 2;
|
|
||||||
indices[iCount + 5] = vIndex + 3;
|
|
||||||
|
|
||||||
iCount += 6;
|
|
||||||
|
|
||||||
Vertex *quad = &vertices[vCount];
|
|
||||||
|
|
||||||
quad[0].coord = quad[1].coord = quad[2].coord = quad[3].coord = { x, y, z };
|
|
||||||
|
|
||||||
int tx = (sprite.tile % 4) * 256;
|
|
||||||
int ty = (sprite.tile / 4) * 256;
|
|
||||||
|
|
||||||
int16 u0 = ((tx + sprite.u) << 5) + 16;
|
|
||||||
int16 v0 = ((ty + sprite.v) << 5) + 16;
|
|
||||||
int16 u1 = u0 + (sprite.w >> 3);
|
|
||||||
int16 v1 = v0 + (sprite.h >> 3);
|
|
||||||
|
|
||||||
quad[0].texCoord = { u0, v0 };
|
|
||||||
quad[1].texCoord = { u1, v0 };
|
|
||||||
quad[2].texCoord = { u1, v1 };
|
|
||||||
quad[3].texCoord = { u0, v1 };
|
|
||||||
|
|
||||||
quad[0].normal = { sprite.r, sprite.t, 0, 0 };
|
|
||||||
quad[1].normal = { sprite.l, sprite.t, 0, 0 };
|
|
||||||
quad[2].normal = { sprite.l, sprite.b, 0, 0 };
|
|
||||||
quad[3].normal = { sprite.r, sprite.b, 0, 0 };
|
|
||||||
|
|
||||||
quad[0].color = quad[1].color = quad[2].color = quad[3].color = { intensity, intensity, intensity, 255 };
|
|
||||||
|
|
||||||
vCount += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void initMesh() {
|
|
||||||
// TODO: sort by texture attribute (t.attribute == 2 ? bmAdd : bmAlpha)
|
|
||||||
|
|
||||||
roomRanges = new RoomRange[level.roomsCount];
|
|
||||||
|
|
||||||
int iCount = 0, vCount = 0;
|
|
||||||
|
|
||||||
// get size of mesh for rooms (geometry & sprites)
|
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
|
||||||
TR::Room::Data &d = level.rooms[i].data;
|
|
||||||
RoomRange &r = roomRanges[i];
|
|
||||||
|
|
||||||
r.geometry.vStart = vCount;
|
|
||||||
r.geometry.iStart = iCount;
|
|
||||||
iCount += d.rCount * 6 + d.tCount * 3;
|
|
||||||
vCount += d.rCount * 4 + d.tCount * 3;
|
|
||||||
r.geometry.iCount = iCount - r.geometry.iStart;
|
|
||||||
|
|
||||||
r.sprites.vStart = vCount;
|
|
||||||
r.sprites.iStart = iCount;
|
|
||||||
iCount += d.sCount * 6;
|
|
||||||
vCount += d.sCount * 4;
|
|
||||||
r.sprites.iCount = iCount - r.sprites.iStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get objects mesh info
|
|
||||||
#define OFFSET(bytes) (ptr = (TR::Mesh*)((char*)ptr + (bytes) - sizeof(char*)))
|
|
||||||
|
|
||||||
mCount = 0;
|
|
||||||
TR::Mesh *ptr = (TR::Mesh*)level.meshData;
|
|
||||||
while ( ((int)ptr - (int)level.meshData) < level.meshDataSize * 2 ) {
|
|
||||||
mCount++;
|
|
||||||
|
|
||||||
OFFSET(ptr->vCount * sizeof(TR::Vertex));
|
|
||||||
if (ptr->nCount > 0)
|
|
||||||
OFFSET(ptr->nCount * sizeof(TR::Vertex));
|
|
||||||
else
|
|
||||||
OFFSET(-ptr->nCount * sizeof(int16));
|
|
||||||
|
|
||||||
iCount += ptr->rCount * 6;
|
|
||||||
vCount += ptr->rCount * 4;
|
|
||||||
OFFSET(ptr->rCount * sizeof(TR::Rectangle));
|
|
||||||
|
|
||||||
iCount += ptr->tCount * 3;
|
|
||||||
vCount += ptr->tCount * 3;
|
|
||||||
OFFSET(ptr->tCount * sizeof(TR::Triangle));
|
|
||||||
|
|
||||||
iCount += ptr->crCount * 6;
|
|
||||||
vCount += ptr->crCount * 4;
|
|
||||||
OFFSET(ptr->crCount * sizeof(TR::Rectangle));
|
|
||||||
|
|
||||||
iCount += ptr->ctCount * 3;
|
|
||||||
vCount += ptr->ctCount * 3;
|
|
||||||
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
|
|
||||||
ptr = (TR::Mesh*)(((int)ptr + 3) & -4);
|
|
||||||
}
|
|
||||||
meshInfo = new MeshInfo[mCount];
|
|
||||||
|
|
||||||
// get size of mesh for sprite sequences
|
|
||||||
spriteRanges = new MeshRange[level.spriteSequencesCount];
|
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
|
||||||
// TODO: sequences not only first frame
|
|
||||||
spriteRanges[i].vStart = vCount;
|
|
||||||
spriteRanges[i].iStart = iCount;
|
|
||||||
spriteRanges[i].iCount = 6;
|
|
||||||
iCount += 6;
|
|
||||||
vCount += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make meshes buffer (single vertex buffer object for all geometry & sprites on level)
|
|
||||||
Index *indices = new Index[iCount];
|
|
||||||
Vertex *vertices = new Vertex[vCount];
|
|
||||||
iCount = vCount = 0;
|
|
||||||
|
|
||||||
// build rooms
|
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
|
||||||
TR::Room::Data &d = level.rooms[i].data;
|
|
||||||
|
|
||||||
// rooms geometry
|
|
||||||
int vStart = vCount;
|
|
||||||
for (int j = 0; j < d.rCount; j++) {
|
|
||||||
auto &f = d.rectangles[j];
|
|
||||||
auto &t = level.objectTextures[f.texture];
|
|
||||||
|
|
||||||
int tile = t.tileAndFlag & 0x7FFF;
|
|
||||||
int tx = (tile % 4) * 256;
|
|
||||||
int ty = (tile / 4) * 256;
|
|
||||||
|
|
||||||
int vIndex = vCount - vStart;
|
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
|
||||||
indices[iCount + 1] = vIndex + 1;
|
|
||||||
indices[iCount + 2] = vIndex + 2;
|
|
||||||
|
|
||||||
indices[iCount + 3] = vIndex + 0;
|
|
||||||
indices[iCount + 4] = vIndex + 2;
|
|
||||||
indices[iCount + 5] = vIndex + 3;
|
|
||||||
|
|
||||||
iCount += 6;
|
|
||||||
|
|
||||||
for (int k = 0; k < 4; k++) {
|
|
||||||
auto &v = d.vertices[f.vertices[k]];
|
|
||||||
uint8 a = 255 - (v.lighting >> 5);
|
|
||||||
|
|
||||||
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z };
|
|
||||||
vertices[vCount].color = { a, a, a, 255 };
|
|
||||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
|
||||||
vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16;
|
|
||||||
vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16;
|
|
||||||
vCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < d.tCount; j++) {
|
|
||||||
auto &f = d.triangles[j];
|
|
||||||
auto &t = level.objectTextures[f.texture];
|
|
||||||
|
|
||||||
int tile = t.tileAndFlag & 0x7FFF;
|
|
||||||
int tx = (tile % 4) * 256;
|
|
||||||
int ty = (tile / 4) * 256;
|
|
||||||
|
|
||||||
int vIndex = vCount - vStart;
|
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
|
||||||
indices[iCount + 1] = vIndex + 1;
|
|
||||||
indices[iCount + 2] = vIndex + 2;
|
|
||||||
|
|
||||||
iCount += 3;
|
|
||||||
|
|
||||||
for (int k = 0; k < 3; k++) {
|
|
||||||
auto &v = d.vertices[f.vertices[k]];
|
|
||||||
uint8 a = 255 - (v.lighting >> 5);
|
|
||||||
|
|
||||||
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z };
|
|
||||||
vertices[vCount].color = { a, a, a, 255 };
|
|
||||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
|
||||||
vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16;
|
|
||||||
vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16;
|
|
||||||
vCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rooms sprites
|
|
||||||
TR::Room::Info &info = level.rooms[i].info;
|
|
||||||
vStart = vCount;
|
|
||||||
for (int j = 0; j < d.sCount; j++) {
|
|
||||||
TR::Room::Data::Sprite &f = d.sprites[j];
|
|
||||||
TR::Room::Data::Vertex &v = d.vertices[f.vertex];
|
|
||||||
TR::SpriteTexture &sprite = level.spriteTextures[f.texture];
|
|
||||||
uint8 intensity = 255 - (v.lighting >> 5);
|
|
||||||
addSprite(indices, vertices, iCount, vCount, vStart, v.vertex.x, v.vertex.y, v.vertex.z, sprite, intensity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// build objects geometry
|
|
||||||
mCount = 0;
|
|
||||||
ptr = (TR::Mesh*)level.meshData;
|
|
||||||
while ( ((int)ptr - (int)level.meshData) < level.meshDataSize * sizeof(uint16) ) {
|
|
||||||
MeshInfo &info = meshInfo[mCount++];
|
|
||||||
info.offset = (int)ptr - (int)level.meshData;
|
|
||||||
info.vStart = vCount;
|
|
||||||
info.iStart = iCount;
|
|
||||||
info.center = ptr->center;
|
|
||||||
info.radius = ptr->radius;
|
|
||||||
|
|
||||||
TR::Vertex *mVertices = (TR::Vertex*)&ptr->vertices;
|
|
||||||
|
|
||||||
OFFSET(ptr->vCount * sizeof(TR::Vertex));
|
|
||||||
|
|
||||||
TR::Vertex *normals = NULL;
|
|
||||||
int16 *lights = NULL;
|
|
||||||
int nCount = ptr->nCount;
|
|
||||||
|
|
||||||
if (ptr->nCount > 0) {
|
|
||||||
normals = (TR::Vertex*)&ptr->normals;
|
|
||||||
OFFSET(ptr->nCount * sizeof(TR::Vertex));
|
|
||||||
} else {
|
|
||||||
lights = (int16*)&ptr->lights;
|
|
||||||
OFFSET(-ptr->nCount * sizeof(int16));
|
|
||||||
}
|
|
||||||
|
|
||||||
int vStart = vCount;
|
|
||||||
// rectangles
|
|
||||||
for (int j = 0; j < ptr->rCount; j++) {
|
|
||||||
auto &f = ((TR::Rectangle*)&ptr->rectangles)[j];
|
|
||||||
auto &t = level.objectTextures[f.texture];
|
|
||||||
|
|
||||||
int tile = t.tileAndFlag & 0x7FFF;
|
|
||||||
int tx = (tile % 4) * 256;
|
|
||||||
int ty = (tile / 4) * 256;
|
|
||||||
|
|
||||||
int vIndex = vCount - vStart;
|
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
|
||||||
indices[iCount + 1] = vIndex + 1;
|
|
||||||
indices[iCount + 2] = vIndex + 2;
|
|
||||||
|
|
||||||
indices[iCount + 3] = vIndex + 0;
|
|
||||||
indices[iCount + 4] = vIndex + 2;
|
|
||||||
indices[iCount + 5] = vIndex + 3;
|
|
||||||
|
|
||||||
iCount += 6;
|
|
||||||
|
|
||||||
for (int k = 0; k < 4; k++) {
|
|
||||||
auto &v = mVertices[f.vertices[k]];
|
|
||||||
|
|
||||||
vertices[vCount].coord = { v.x, v.y, v.z };
|
|
||||||
|
|
||||||
if (nCount > 0) {
|
|
||||||
TR::Vertex &n = normals[f.vertices[k]];
|
|
||||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
|
||||||
vertices[vCount].color = { 255, 255, 255, 255 };
|
|
||||||
} else {
|
|
||||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
|
||||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
|
||||||
vertices[vCount].color = { a, a, a, 255 };
|
|
||||||
}
|
|
||||||
vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16;
|
|
||||||
vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16;
|
|
||||||
vCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OFFSET(ptr->rCount * sizeof(TR::Rectangle));
|
|
||||||
|
|
||||||
// triangles
|
|
||||||
for (int j = 0; j < ptr->tCount; j++) {
|
|
||||||
auto &f = ((TR::Triangle*)&ptr->triangles)[j];
|
|
||||||
auto &t = level.objectTextures[f.texture];
|
|
||||||
|
|
||||||
int tile = t.tileAndFlag & 0x7FFF;
|
|
||||||
int tx = (tile % 4) * 256;
|
|
||||||
int ty = (tile / 4) * 256;
|
|
||||||
|
|
||||||
int vIndex = vCount - vStart;
|
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
|
||||||
indices[iCount + 1] = vIndex + 1;
|
|
||||||
indices[iCount + 2] = vIndex + 2;
|
|
||||||
|
|
||||||
iCount += 3;
|
|
||||||
|
|
||||||
for (int k = 0; k < 3; k++) {
|
|
||||||
auto &v = mVertices[f.vertices[k]];
|
|
||||||
vertices[vCount].coord = { v.x, v.y, v.z };
|
|
||||||
|
|
||||||
if (nCount > 0) {
|
|
||||||
TR::Vertex &n = normals[f.vertices[k]];
|
|
||||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
|
||||||
vertices[vCount].color = { 255, 255, 255, 255 };
|
|
||||||
} else {
|
|
||||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
|
||||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
|
||||||
vertices[vCount].color = { a, a, a, 255 };
|
|
||||||
}
|
|
||||||
vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16;
|
|
||||||
vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16;
|
|
||||||
vCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OFFSET(ptr->tCount * sizeof(TR::Triangle));
|
|
||||||
|
|
||||||
// color rectangles
|
|
||||||
for (int j = 0; j < ptr->crCount; j++) {
|
|
||||||
auto &f = ((TR::Rectangle*)&ptr->crectangles)[j];
|
|
||||||
auto &c = level.palette[f.texture & 0xFF];
|
|
||||||
|
|
||||||
int vIndex = vCount - vStart;
|
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
|
||||||
indices[iCount + 1] = vIndex + 1;
|
|
||||||
indices[iCount + 2] = vIndex + 2;
|
|
||||||
|
|
||||||
indices[iCount + 3] = vIndex + 0;
|
|
||||||
indices[iCount + 4] = vIndex + 2;
|
|
||||||
indices[iCount + 5] = vIndex + 3;
|
|
||||||
|
|
||||||
iCount += 6;
|
|
||||||
|
|
||||||
for (int k = 0; k < 4; k++) {
|
|
||||||
auto &v = mVertices[f.vertices[k]];
|
|
||||||
|
|
||||||
vertices[vCount].coord = { v.x, v.y, v.z };
|
|
||||||
|
|
||||||
if (nCount > 0) {
|
|
||||||
TR::Vertex &n = normals[f.vertices[k]];
|
|
||||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
|
||||||
vertices[vCount].color = { c.r, c.g, c.b, 255 };
|
|
||||||
} else {
|
|
||||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
|
||||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
|
||||||
vertices[vCount].color = { a, a, a, 255 }; // TODO: apply color
|
|
||||||
}
|
|
||||||
vertices[vCount].texCoord = { 1022 << 5, 1022 << 5 };
|
|
||||||
vCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OFFSET(ptr->crCount * sizeof(TR::Rectangle));
|
|
||||||
|
|
||||||
// color triangles
|
|
||||||
for (int j = 0; j < ptr->ctCount; j++) {
|
|
||||||
auto &f = ((TR::Triangle*)&ptr->ctriangles)[j];
|
|
||||||
auto &c = level.palette[f.texture & 0xFF];
|
|
||||||
|
|
||||||
int vIndex = vCount - vStart;
|
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
|
||||||
indices[iCount + 1] = vIndex + 1;
|
|
||||||
indices[iCount + 2] = vIndex + 2;
|
|
||||||
|
|
||||||
iCount += 3;
|
|
||||||
|
|
||||||
for (int k = 0; k < 3; k++) {
|
|
||||||
auto &v = mVertices[f.vertices[k]];
|
|
||||||
|
|
||||||
vertices[vCount].coord = { v.x, v.y, v.z };
|
|
||||||
|
|
||||||
if (nCount > 0) {
|
|
||||||
TR::Vertex &n = normals[f.vertices[k]];
|
|
||||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
|
||||||
vertices[vCount].color = { c.r, c.g, c.b, 255 };
|
|
||||||
} else {
|
|
||||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
|
||||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
|
||||||
vertices[vCount].color = { a, a, a, 255 }; // TODO: apply color
|
|
||||||
}
|
|
||||||
vertices[vCount].texCoord = { 1022 << 5, 1022 << 5 };
|
|
||||||
vCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
|
|
||||||
|
|
||||||
ptr = (TR::Mesh*)(((int)ptr + 3) & -4);
|
|
||||||
|
|
||||||
info.iCount = iCount - info.iStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// build sprite sequences
|
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
|
||||||
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart];
|
|
||||||
addSprite(indices, vertices, iCount, vCount, vCount, 0, -16, 0, sprite, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh = new Mesh(indices, iCount, vertices, vCount);
|
|
||||||
delete[] indices;
|
|
||||||
delete[] vertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
TR::StaticMesh* getMeshByID(int id) {
|
TR::StaticMesh* getMeshByID(int id) {
|
||||||
for (int i = 0; i < level.staticMeshesCount; i++)
|
for (int i = 0; i < level.staticMeshesCount; i++)
|
||||||
if (level.staticMeshes[i].id == id)
|
if (level.staticMeshes[i].id == id)
|
||||||
@@ -543,15 +138,15 @@ struct Level {
|
|||||||
sh->setParam(uLightColor, Core::lightColor);
|
sh->setParam(uLightColor, Core::lightColor);
|
||||||
|
|
||||||
// render room geometry
|
// render room geometry
|
||||||
mesh->render(roomRanges[index].geometry);
|
mesh->renderRoomGeometry(index);
|
||||||
|
|
||||||
// render room sprites
|
// render room sprites
|
||||||
if (roomRanges[index].sprites.iCount) {
|
if (mesh->hasRoomSprites(index)) {
|
||||||
sh = shaders[shSprite];
|
sh = shaders[shSprite];
|
||||||
sh->bind();
|
sh->bind();
|
||||||
sh->setParam(uModel, Core::mModel);
|
sh->setParam(uModel, Core::mModel);
|
||||||
sh->setParam(uColor, Core::color);
|
sh->setParam(uColor, Core::color);
|
||||||
mesh->render(roomRanges[index].sprites);
|
mesh->renderRoomSprites(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::mModel = m;
|
Core::mModel = m;
|
||||||
@@ -597,18 +192,17 @@ struct Level {
|
|||||||
camera.frustum = camFrustum; // pop camera frustum
|
camera.frustum = camFrustum; // pop camera frustum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void renderMesh(uint32 meshOffset) {
|
void renderMesh(uint32 meshOffset) {
|
||||||
if (!level.meshOffsets[meshOffset] && meshOffset)
|
if (!level.meshOffsets[meshOffset] && meshOffset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < mCount; i++)
|
for (int i = 0; i < mesh->mCount; i++)
|
||||||
if (meshInfo[i].offset == level.meshOffsets[meshOffset]) {
|
if (mesh->meshInfo[i].offset == level.meshOffsets[meshOffset]) {
|
||||||
MeshInfo &m = meshInfo[i];
|
MeshBuilder::MeshInfo &m = mesh->meshInfo[i];
|
||||||
|
|
||||||
if (camera.frustum->isVisible(Core::mModel * m.center, m.radius)) {
|
if (camera.frustum->isVisible(Core::mModel * m.center, m.radius)) {
|
||||||
Core::active.shader->setParam(uModel, Core::mModel);
|
Core::active.shader->setParam(uModel, Core::mModel);
|
||||||
mesh->render(m);
|
mesh->renderMesh(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -816,7 +410,7 @@ struct Level {
|
|||||||
Core::active.shader->setParam(uColor, Core::color);
|
Core::active.shader->setParam(uColor, Core::color);
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++)
|
for (int i = 0; i < level.spriteSequencesCount; i++)
|
||||||
if (entity.id == level.spriteSequences[i].id) {
|
if (entity.id == level.spriteSequences[i].id) {
|
||||||
mesh->render(spriteRanges[i]);
|
mesh->renderSprite(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -901,7 +495,7 @@ struct Level {
|
|||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Debug::begin();
|
Debug::begin();
|
||||||
Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||||
Debug::Level::lights(level);
|
// Debug::Level::lights(level);
|
||||||
Debug::Level::portals(level);
|
Debug::Level::portals(level);
|
||||||
Debug::end();
|
Debug::end();
|
||||||
#endif
|
#endif
|
||||||
|
405
src/mesh.h
405
src/mesh.h
@@ -2,6 +2,7 @@
|
|||||||
#define H_MESH
|
#define H_MESH
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
typedef unsigned short Index;
|
typedef unsigned short Index;
|
||||||
|
|
||||||
@@ -57,4 +58,408 @@ struct Mesh {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MeshBuilder {
|
||||||
|
// rooms
|
||||||
|
struct RoomRange {
|
||||||
|
MeshRange geometry;
|
||||||
|
MeshRange sprites;
|
||||||
|
} *roomRanges;
|
||||||
|
|
||||||
|
// objects meshes
|
||||||
|
struct MeshInfo : MeshRange {
|
||||||
|
int offset;
|
||||||
|
TR::Vertex center;
|
||||||
|
int32 radius;
|
||||||
|
} *meshInfo;
|
||||||
|
int mCount;
|
||||||
|
|
||||||
|
// sprite sequences
|
||||||
|
MeshRange *spriteRanges;
|
||||||
|
|
||||||
|
// indexed mesh
|
||||||
|
Mesh *mesh;
|
||||||
|
|
||||||
|
MeshBuilder(const TR::Level &level) {
|
||||||
|
roomRanges = new RoomRange[level.roomsCount];
|
||||||
|
|
||||||
|
int iCount = 0, vCount = 0;
|
||||||
|
|
||||||
|
// get size of mesh for rooms (geometry & sprites)
|
||||||
|
for (int i = 0; i < level.roomsCount; i++) {
|
||||||
|
TR::Room::Data &d = level.rooms[i].data;
|
||||||
|
RoomRange &r = roomRanges[i];
|
||||||
|
|
||||||
|
r.geometry.vStart = vCount;
|
||||||
|
r.geometry.iStart = iCount;
|
||||||
|
iCount += d.rCount * 6 + d.tCount * 3;
|
||||||
|
vCount += d.rCount * 4 + d.tCount * 3;
|
||||||
|
r.geometry.iCount = iCount - r.geometry.iStart;
|
||||||
|
|
||||||
|
r.sprites.vStart = vCount;
|
||||||
|
r.sprites.iStart = iCount;
|
||||||
|
iCount += d.sCount * 6;
|
||||||
|
vCount += d.sCount * 4;
|
||||||
|
r.sprites.iCount = iCount - r.sprites.iStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get objects mesh info
|
||||||
|
#define OFFSET(bytes) (ptr = (TR::Mesh*)((char*)ptr + (bytes) - sizeof(char*)))
|
||||||
|
|
||||||
|
mCount = 0;
|
||||||
|
TR::Mesh *ptr = (TR::Mesh*)level.meshData;
|
||||||
|
while ( ((int)ptr - (int)level.meshData) < level.meshDataSize * 2 ) {
|
||||||
|
mCount++;
|
||||||
|
|
||||||
|
OFFSET(ptr->vCount * sizeof(TR::Vertex));
|
||||||
|
if (ptr->nCount > 0)
|
||||||
|
OFFSET(ptr->nCount * sizeof(TR::Vertex));
|
||||||
|
else
|
||||||
|
OFFSET(-ptr->nCount * sizeof(int16));
|
||||||
|
|
||||||
|
iCount += ptr->rCount * 6;
|
||||||
|
vCount += ptr->rCount * 4;
|
||||||
|
OFFSET(ptr->rCount * sizeof(TR::Rectangle));
|
||||||
|
|
||||||
|
iCount += ptr->tCount * 3;
|
||||||
|
vCount += ptr->tCount * 3;
|
||||||
|
OFFSET(ptr->tCount * sizeof(TR::Triangle));
|
||||||
|
|
||||||
|
iCount += ptr->crCount * 6;
|
||||||
|
vCount += ptr->crCount * 4;
|
||||||
|
OFFSET(ptr->crCount * sizeof(TR::Rectangle));
|
||||||
|
|
||||||
|
iCount += ptr->ctCount * 3;
|
||||||
|
vCount += ptr->ctCount * 3;
|
||||||
|
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
|
||||||
|
ptr = (TR::Mesh*)(((int)ptr + 3) & -4);
|
||||||
|
}
|
||||||
|
meshInfo = new MeshInfo[mCount];
|
||||||
|
|
||||||
|
// get size of mesh for sprite sequences
|
||||||
|
spriteRanges = new MeshRange[level.spriteSequencesCount];
|
||||||
|
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
||||||
|
// TODO: sequences not only first frame
|
||||||
|
spriteRanges[i].vStart = vCount;
|
||||||
|
spriteRanges[i].iStart = iCount;
|
||||||
|
spriteRanges[i].iCount = 6;
|
||||||
|
iCount += 6;
|
||||||
|
vCount += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make meshes buffer (single vertex buffer object for all geometry & sprites on level)
|
||||||
|
Index *indices = new Index[iCount];
|
||||||
|
Vertex *vertices = new Vertex[vCount];
|
||||||
|
iCount = vCount = 0;
|
||||||
|
|
||||||
|
// build rooms
|
||||||
|
for (int i = 0; i < level.roomsCount; i++) {
|
||||||
|
TR::Room::Data &d = level.rooms[i].data;
|
||||||
|
|
||||||
|
// rooms geometry
|
||||||
|
int vStart = vCount;
|
||||||
|
for (int j = 0; j < d.rCount; j++) {
|
||||||
|
auto &f = d.rectangles[j];
|
||||||
|
auto &t = level.objectTextures[f.texture];
|
||||||
|
|
||||||
|
int tile = t.tileAndFlag & 0x7FFF;
|
||||||
|
int tx = (tile % 4) * 256;
|
||||||
|
int ty = (tile / 4) * 256;
|
||||||
|
|
||||||
|
addQuad(indices, iCount, vCount, vStart);
|
||||||
|
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
auto &v = d.vertices[f.vertices[k]];
|
||||||
|
uint8 a = 255 - (v.lighting >> 5);
|
||||||
|
|
||||||
|
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z };
|
||||||
|
vertices[vCount].color = { a, a, a, 255 };
|
||||||
|
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||||
|
vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16;
|
||||||
|
vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16;
|
||||||
|
vCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < d.tCount; j++) {
|
||||||
|
auto &f = d.triangles[j];
|
||||||
|
auto &t = level.objectTextures[f.texture];
|
||||||
|
|
||||||
|
int tile = t.tileAndFlag & 0x7FFF;
|
||||||
|
int tx = (tile % 4) * 256;
|
||||||
|
int ty = (tile / 4) * 256;
|
||||||
|
|
||||||
|
addTriangle(indices, iCount, vCount, vStart);
|
||||||
|
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
auto &v = d.vertices[f.vertices[k]];
|
||||||
|
uint8 a = 255 - (v.lighting >> 5);
|
||||||
|
|
||||||
|
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z };
|
||||||
|
vertices[vCount].color = { a, a, a, 255 };
|
||||||
|
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||||
|
vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16;
|
||||||
|
vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16;
|
||||||
|
vCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rooms sprites
|
||||||
|
TR::Room::Info &info = level.rooms[i].info;
|
||||||
|
vStart = vCount;
|
||||||
|
for (int j = 0; j < d.sCount; j++) {
|
||||||
|
TR::Room::Data::Sprite &f = d.sprites[j];
|
||||||
|
TR::Room::Data::Vertex &v = d.vertices[f.vertex];
|
||||||
|
TR::SpriteTexture &sprite = level.spriteTextures[f.texture];
|
||||||
|
uint8 intensity = 255 - (v.lighting >> 5);
|
||||||
|
addSprite(indices, vertices, iCount, vCount, vStart, v.vertex.x, v.vertex.y, v.vertex.z, sprite, intensity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build objects geometry
|
||||||
|
mCount = 0;
|
||||||
|
ptr = (TR::Mesh*)level.meshData;
|
||||||
|
while ( ((int)ptr - (int)level.meshData) < level.meshDataSize * sizeof(uint16) ) {
|
||||||
|
MeshInfo &info = meshInfo[mCount++];
|
||||||
|
info.offset = (int)ptr - (int)level.meshData;
|
||||||
|
info.vStart = vCount;
|
||||||
|
info.iStart = iCount;
|
||||||
|
info.center = ptr->center;
|
||||||
|
info.radius = ptr->radius;
|
||||||
|
|
||||||
|
TR::Vertex *mVertices = (TR::Vertex*)&ptr->vertices;
|
||||||
|
|
||||||
|
OFFSET(ptr->vCount * sizeof(TR::Vertex));
|
||||||
|
|
||||||
|
TR::Vertex *normals = NULL;
|
||||||
|
int16 *lights = NULL;
|
||||||
|
int nCount = ptr->nCount;
|
||||||
|
|
||||||
|
if (ptr->nCount > 0) {
|
||||||
|
normals = (TR::Vertex*)&ptr->normals;
|
||||||
|
OFFSET(ptr->nCount * sizeof(TR::Vertex));
|
||||||
|
} else {
|
||||||
|
lights = (int16*)&ptr->lights;
|
||||||
|
OFFSET(-ptr->nCount * sizeof(int16));
|
||||||
|
}
|
||||||
|
|
||||||
|
int vStart = vCount;
|
||||||
|
// rectangles
|
||||||
|
for (int j = 0; j < ptr->rCount; j++) {
|
||||||
|
auto &f = ((TR::Rectangle*)&ptr->rectangles)[j];
|
||||||
|
auto &t = level.objectTextures[f.texture];
|
||||||
|
|
||||||
|
int tile = t.tileAndFlag & 0x7FFF;
|
||||||
|
int tx = (tile % 4) * 256;
|
||||||
|
int ty = (tile / 4) * 256;
|
||||||
|
|
||||||
|
addQuad(indices, iCount, vCount, vStart);
|
||||||
|
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
auto &v = mVertices[f.vertices[k]];
|
||||||
|
|
||||||
|
vertices[vCount].coord = { v.x, v.y, v.z };
|
||||||
|
|
||||||
|
if (nCount > 0) {
|
||||||
|
TR::Vertex &n = normals[f.vertices[k]];
|
||||||
|
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||||
|
vertices[vCount].color = { 255, 255, 255, 255 };
|
||||||
|
} else {
|
||||||
|
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||||
|
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||||
|
vertices[vCount].color = { a, a, a, 255 };
|
||||||
|
}
|
||||||
|
vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16;
|
||||||
|
vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16;
|
||||||
|
vCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OFFSET(ptr->rCount * sizeof(TR::Rectangle));
|
||||||
|
|
||||||
|
// triangles
|
||||||
|
for (int j = 0; j < ptr->tCount; j++) {
|
||||||
|
auto &f = ((TR::Triangle*)&ptr->triangles)[j];
|
||||||
|
auto &t = level.objectTextures[f.texture];
|
||||||
|
|
||||||
|
int tile = t.tileAndFlag & 0x7FFF;
|
||||||
|
int tx = (tile % 4) * 256;
|
||||||
|
int ty = (tile / 4) * 256;
|
||||||
|
|
||||||
|
addTriangle(indices, iCount, vCount, vStart);
|
||||||
|
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
auto &v = mVertices[f.vertices[k]];
|
||||||
|
vertices[vCount].coord = { v.x, v.y, v.z };
|
||||||
|
|
||||||
|
if (nCount > 0) {
|
||||||
|
TR::Vertex &n = normals[f.vertices[k]];
|
||||||
|
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||||
|
vertices[vCount].color = { 255, 255, 255, 255 };
|
||||||
|
} else {
|
||||||
|
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||||
|
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||||
|
vertices[vCount].color = { a, a, a, 255 };
|
||||||
|
}
|
||||||
|
vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16;
|
||||||
|
vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16;
|
||||||
|
vCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OFFSET(ptr->tCount * sizeof(TR::Triangle));
|
||||||
|
|
||||||
|
// color rectangles
|
||||||
|
for (int j = 0; j < ptr->crCount; j++) {
|
||||||
|
auto &f = ((TR::Rectangle*)&ptr->crectangles)[j];
|
||||||
|
auto &c = level.palette[f.texture & 0xFF];
|
||||||
|
|
||||||
|
addQuad(indices, iCount, vCount, vStart);
|
||||||
|
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
auto &v = mVertices[f.vertices[k]];
|
||||||
|
|
||||||
|
vertices[vCount].coord = { v.x, v.y, v.z };
|
||||||
|
|
||||||
|
if (nCount > 0) {
|
||||||
|
TR::Vertex &n = normals[f.vertices[k]];
|
||||||
|
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||||
|
vertices[vCount].color = { c.r, c.g, c.b, 255 };
|
||||||
|
} else {
|
||||||
|
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||||
|
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||||
|
vertices[vCount].color = { a, a, a, 255 }; // TODO: apply color
|
||||||
|
}
|
||||||
|
vertices[vCount].texCoord = { 1022 << 5, 1022 << 5 };
|
||||||
|
vCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OFFSET(ptr->crCount * sizeof(TR::Rectangle));
|
||||||
|
|
||||||
|
// color triangles
|
||||||
|
for (int j = 0; j < ptr->ctCount; j++) {
|
||||||
|
auto &f = ((TR::Triangle*)&ptr->ctriangles)[j];
|
||||||
|
auto &c = level.palette[f.texture & 0xFF];
|
||||||
|
|
||||||
|
addTriangle(indices, iCount, vCount, vStart);
|
||||||
|
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
auto &v = mVertices[f.vertices[k]];
|
||||||
|
|
||||||
|
vertices[vCount].coord = { v.x, v.y, v.z };
|
||||||
|
|
||||||
|
if (nCount > 0) {
|
||||||
|
TR::Vertex &n = normals[f.vertices[k]];
|
||||||
|
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||||
|
vertices[vCount].color = { c.r, c.g, c.b, 255 };
|
||||||
|
} else {
|
||||||
|
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||||
|
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||||
|
vertices[vCount].color = { a, a, a, 255 }; // TODO: apply color
|
||||||
|
}
|
||||||
|
vertices[vCount].texCoord = { 1022 << 5, 1022 << 5 };
|
||||||
|
vCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
|
||||||
|
|
||||||
|
ptr = (TR::Mesh*)(((int)ptr + 3) & -4);
|
||||||
|
|
||||||
|
info.iCount = iCount - info.iStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build sprite sequences
|
||||||
|
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
||||||
|
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart];
|
||||||
|
addSprite(indices, vertices, iCount, vCount, vCount, 0, -16, 0, sprite, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh = new Mesh(indices, iCount, vertices, vCount);
|
||||||
|
delete[] indices;
|
||||||
|
delete[] vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
~MeshBuilder() {
|
||||||
|
delete[] roomRanges;
|
||||||
|
delete[] meshInfo;
|
||||||
|
delete[] spriteRanges;
|
||||||
|
delete mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTriangle(Index *indices, int &iCount, int vCount, int vStart) {
|
||||||
|
int vIndex = vCount - vStart;
|
||||||
|
|
||||||
|
indices[iCount + 0] = vIndex + 0;
|
||||||
|
indices[iCount + 1] = vIndex + 1;
|
||||||
|
indices[iCount + 2] = vIndex + 2;
|
||||||
|
|
||||||
|
iCount += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addQuad(Index *indices, int &iCount, int vCount, int vStart) {
|
||||||
|
int vIndex = vCount - vStart;
|
||||||
|
|
||||||
|
indices[iCount + 0] = vIndex + 0;
|
||||||
|
indices[iCount + 1] = vIndex + 1;
|
||||||
|
indices[iCount + 2] = vIndex + 2;
|
||||||
|
|
||||||
|
indices[iCount + 3] = vIndex + 0;
|
||||||
|
indices[iCount + 4] = vIndex + 2;
|
||||||
|
indices[iCount + 5] = vIndex + 3;
|
||||||
|
|
||||||
|
iCount += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSprite(Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 x, int16 y, int16 z, const TR::SpriteTexture &sprite, uint8 intensity) {
|
||||||
|
addQuad(indices, iCount, vCount, vStart);
|
||||||
|
|
||||||
|
Vertex *quad = &vertices[vCount];
|
||||||
|
|
||||||
|
quad[0].coord = quad[1].coord = quad[2].coord = quad[3].coord = { x, y, z };
|
||||||
|
|
||||||
|
int tx = (sprite.tile % 4) * 256;
|
||||||
|
int ty = (sprite.tile / 4) * 256;
|
||||||
|
|
||||||
|
int16 u0 = ((tx + sprite.u) << 5) + 16;
|
||||||
|
int16 v0 = ((ty + sprite.v) << 5) + 16;
|
||||||
|
int16 u1 = u0 + (sprite.w >> 3);
|
||||||
|
int16 v1 = v0 + (sprite.h >> 3);
|
||||||
|
|
||||||
|
quad[0].texCoord = { u0, v0 };
|
||||||
|
quad[1].texCoord = { u1, v0 };
|
||||||
|
quad[2].texCoord = { u1, v1 };
|
||||||
|
quad[3].texCoord = { u0, v1 };
|
||||||
|
|
||||||
|
quad[0].normal = { sprite.r, sprite.t, 0, 0 };
|
||||||
|
quad[1].normal = { sprite.l, sprite.t, 0, 0 };
|
||||||
|
quad[2].normal = { sprite.l, sprite.b, 0, 0 };
|
||||||
|
quad[3].normal = { sprite.r, sprite.b, 0, 0 };
|
||||||
|
|
||||||
|
quad[0].color = quad[1].color = quad[2].color = quad[3].color = { intensity, intensity, intensity, 255 };
|
||||||
|
|
||||||
|
vCount += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind() {
|
||||||
|
mesh->bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderRoomGeometry(int roomIndex) {
|
||||||
|
mesh->render(roomRanges[roomIndex].geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderRoomSprites(int roomIndex) {
|
||||||
|
mesh->render(roomRanges[roomIndex].sprites);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasRoomSprites(int roomIndex) {
|
||||||
|
return roomRanges[roomIndex].sprites.iCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderMesh(int meshIndex) {
|
||||||
|
mesh->render(meshInfo[meshIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderSprite(int spriteIndex) {
|
||||||
|
mesh->render(spriteRanges[spriteIndex]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@@ -20,6 +20,7 @@
|
|||||||
#else
|
#else
|
||||||
#define ASSERT(expr)
|
#define ASSERT(expr)
|
||||||
#define LOG(...) ((void)0)
|
#define LOG(...) ((void)0)
|
||||||
|
// #define LOG(...) printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user