diff --git a/src/camera.h b/src/camera.h index 095e896..44927a0 100644 --- a/src/camera.h +++ b/src/camera.h @@ -4,45 +4,45 @@ #include "core.h" struct Camera { - float fov, znear, zfar; - vec3 pos, angle, offset; + float fov, znear, zfar; + vec3 pos, angle, offset; - void update() { - #ifdef FREE_CAMERA - vec3 dir = vec3(sinf(angle.y - PI) * cosf(-angle.x), -sinf(-angle.x), cosf(angle.y - PI) * cosf(-angle.x)); - vec3 v = vec3(0); + void update() { + #ifdef FREE_CAMERA + vec3 dir = vec3(sinf(angle.y - PI) * cosf(-angle.x), -sinf(-angle.x), cosf(angle.y - PI) * cosf(-angle.x)); + vec3 v = vec3(0); - if (Input::down[ikW]) v = v + dir; - if (Input::down[ikS]) v = v - dir; - if (Input::down[ikD]) v = v + dir.cross(vec3(0, 1, 0)); - if (Input::down[ikA]) v = v - dir.cross(vec3(0, 1, 0)); - pos = pos + v.normal() * (Core::deltaTime * 2048.0f); - #endif + if (Input::down[ikW]) v = v + dir; + if (Input::down[ikS]) v = v - dir; + if (Input::down[ikD]) v = v + dir.cross(vec3(0, 1, 0)); + if (Input::down[ikA]) v = v - dir.cross(vec3(0, 1, 0)); + pos = pos + v.normal() * (Core::deltaTime * 2048.0f); + #endif - if (Input::down[ikMouseL]) { - vec2 delta = Input::mouse.pos - Input::mouse.start.L; - angle.x -= delta.y * 0.01f; - angle.y -= delta.x * 0.01f; - angle.x = min(max(angle.x, -PI * 0.5f + EPS), PI * 0.5f - EPS); - Input::mouse.start.L = Input::mouse.pos; - } - } + if (Input::down[ikMouseL]) { + vec2 delta = Input::mouse.pos - Input::mouse.start.L; + angle.x -= delta.y * 0.01f; + angle.y -= delta.x * 0.01f; + angle.x = min(max(angle.x, -PI * 0.5f + EPS), PI * 0.5f - EPS); + Input::mouse.start.L = Input::mouse.pos; + } + } - void setup() { - Core::mView.identity(); - Core::mView.translate(vec3(-offset.x, -offset.y, -offset.z)); - Core::mView.rotateZ(-angle.z); - Core::mView.rotateX(-angle.x); - Core::mView.rotateY(-angle.y); - Core::mView.translate(vec3(-pos.x, -pos.y, -pos.z)); - Core::mView.scale(vec3(-1, -1, 1)); + void setup() { + Core::mView.identity(); + Core::mView.translate(vec3(-offset.x, -offset.y, -offset.z)); + Core::mView.rotateZ(-angle.z); + Core::mView.rotateX(-angle.x); + Core::mView.rotateY(-angle.y); + Core::mView.translate(vec3(-pos.x, -pos.y, -pos.z)); + Core::mView.scale(vec3(-1, -1, 1)); - Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar); - - Core::mViewProj = Core::mProj * Core::mView; + Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar); - Core::viewPos = Core::mView.inverse().getPos(); - } + Core::mViewProj = Core::mProj * Core::mView; + + Core::viewPos = Core::mView.inverse().getPos(); + } }; #endif \ No newline at end of file diff --git a/src/controller.h b/src/controller.h index aa66cc5..5a7ac01 100644 --- a/src/controller.h +++ b/src/controller.h @@ -6,456 +6,453 @@ #define GRAVITY 7.0f struct Controller { - TR::Level *level; - int entity; + TR::Level *level; + int entity; - TR::Animation *anim; - float fTime; + TR::Animation *anim; + float fTime; - vec3 pos, velocity; - float angle; + vec3 pos, velocity; + float angle; - int state; // target state - int lastFrame; + int state; // target state + int lastFrame; - int sc; - bool lState; - bool onGround; + int sc; + bool lState; + bool onGround; - Controller(TR::Level *level, int entity) : level(level), entity(entity), pos(0.0f), velocity(0.0f), angle(0.0f), fTime(0.0f) { - anim = &level->anims[getModel().animation]; - lastFrame = 0; + Controller(TR::Level *level, int entity) : level(level), entity(entity), pos(0.0f), velocity(0.0f), angle(0.0f), fTime(0.0f) { + anim = &level->anims[getModel().animation]; + lastFrame = 0; - TR::Entity &e = level->entities[entity]; - pos = vec3(e.x, e.y, e.z); - angle = e.rotation / 16384.0f * PI * 0.5f; + TR::Entity &e = level->entities[entity]; + pos = vec3(e.x, e.y, e.z); + angle = e.rotation / 16384.0f * PI * 0.5f; - sc = 0; - lState = false; + sc = 0; + lState = false; - state = TR::STATE_STOP; - } + state = TR::STATE_STOP; + } - void update() { - float rot = 0.0f; - - enum { LEFT = 1, RIGHT = 2, FORTH = 4, BACK = 8, JUMP = 16, WALK = 32, ACTION = 64, WEAPON = 128, ROLL = 256, GROUND = 512, WATER = 1024, DEATH = 2048, - PULL = 4096, PICKUP = 8192, SWITCH_ON = 16 * 1024, SWITCH_OFF = 32 * 1024, KEY = 64 * 1024, PUZZLE = 128 * 1024, HANG = 256 * 1024, FALL = 512 * 1024, COMPRESS = 1024 * 1024}; - int mask = 0; + void update() { + float rot = 0.0f; - if (Input::down[ikW] || Input::joy.L.y < 0) mask |= FORTH; - if (Input::down[ikS] || Input::joy.L.y > 0) mask |= BACK; - if (Input::down[ikA] || Input::joy.L.x < 0) mask |= LEFT; - if (Input::down[ikD] || Input::joy.L.x > 0) mask |= RIGHT; - if (Input::down[ikSpace] || Input::down[ikJoyX]) mask |= JUMP; - if (Input::down[ikShift] || Input::down[ikJoyLT]) mask |= WALK; - if (Input::down[ikE] || /*Input::down[ikMouseL] ||*/ Input::down[ikJoyA]) mask |= ACTION; - if (Input::down[ikQ] || Input::down[ikMouseR] || Input::down[ikJoyY]) mask |= WEAPON; - if (onGround) mask |= GROUND; - if (getRoom().flags & 1) mask |= WATER; - if (velocity.y > 2048) mask |= FALL; - if (anim->state == TR::STATE_COMPRESS) mask |= COMPRESS; + enum { LEFT = 1, RIGHT = 2, FORTH = 4, BACK = 8, + JUMP = 16, WALK = 32, ACTION = 64, WEAPON = 128, ROLL = 256, + GROUND = 512, WATER = 1024, DEATH = 2048, + PULL = 4096, PICKUP = 8192, SWITCH_ON = 16 * 1024, SWITCH_OFF = 32 * 1024, KEY = 64 * 1024, PUZZLE = 128 * 1024, HANG = 256 * 1024, FALL = 512 * 1024, COMPRESS = 1024 * 1024}; + int mask = 0; + + if (Input::down[ikW] || Input::joy.L.y < 0) mask |= FORTH; + if (Input::down[ikS] || Input::joy.L.y > 0) mask |= BACK; + if (Input::down[ikA] || Input::joy.L.x < 0) mask |= LEFT; + if (Input::down[ikD] || Input::joy.L.x > 0) mask |= RIGHT; + if (Input::down[ikSpace] || Input::down[ikJoyX]) mask |= JUMP; + if (Input::down[ikShift] || Input::down[ikJoyLT]) mask |= WALK; + if (Input::down[ikE] || /*Input::down[ikMouseL] ||*/ Input::down[ikJoyA]) mask |= ACTION; + if (Input::down[ikQ] || Input::down[ikMouseR] || Input::down[ikJoyY]) mask |= WEAPON; + if (onGround) mask |= GROUND; + if (getRoom().flags & 1) mask |= WATER; + if (velocity.y > 2048) mask |= FALL; + if (anim->state == TR::STATE_COMPRESS) mask |= COMPRESS; + + int origMask = mask; + if (origMask & (FORTH | BACK)) + mask &= ~(LEFT | RIGHT); + + int stateMask[TR::STATE_MAX]; + for (int i = 0; i < TR::STATE_MAX; i++) + stateMask[i] = -1; + + stateMask[TR::STATE_WALK] = GROUND | FORTH | WALK; + stateMask[TR::STATE_RUN] = GROUND | FORTH; + stateMask[TR::STATE_STOP] = GROUND; + stateMask[TR::STATE_FORWARD_JUMP] = GROUND | JUMP | FORTH; +// stateMask[TR::STATE_FAST_TURN] = 0; + stateMask[TR::STATE_FAST_BACK] = GROUND | BACK; + stateMask[TR::STATE_TURN_RIGHT] = GROUND | RIGHT; + stateMask[TR::STATE_TURN_LEFT] = GROUND | LEFT; + stateMask[TR::STATE_DEATH] = DEATH; + stateMask[TR::STATE_FAST_FALL] = FALL; + stateMask[TR::STATE_HANG] = HANG | ACTION; + stateMask[TR::STATE_REACH] = ACTION; +// stateMask[TR::STATE_SPLAT] +// stateMask[TR::STATE_TREAD] +// stateMask[TR::STATE_FAST_TURN_14] + stateMask[TR::STATE_COMPRESS] = GROUND | JUMP; + stateMask[TR::STATE_BACK] = GROUND | WALK | BACK; + stateMask[TR::STATE_SWIM] = WATER | FORTH; +// stateMask[TR::STATE_GLIDE] +// stateMask[TR::STATE_NULL_19] +// stateMask[TR::STATE_FAST_TURN_20] + stateMask[TR::STATE_FAST_TURN_20] = GROUND | LEFT | RIGHT; + stateMask[TR::STATE_STEP_RIGHT] = GROUND | WALK | RIGHT; + stateMask[TR::STATE_STEP_LEFT] = GROUND | WALK | LEFT; + stateMask[TR::STATE_ROLL] = GROUND | ROLL; +// stateMask[TR::STATE_SLIDE] + stateMask[TR::STATE_BACK_JUMP] = GROUND | COMPRESS | BACK; + stateMask[TR::STATE_RIGHT_JUMP] = GROUND | COMPRESS | RIGHT; + stateMask[TR::STATE_LEFT_JUMP] = GROUND | COMPRESS | LEFT; + stateMask[TR::STATE_UP_JUMP] = GROUND | COMPRESS; + + stateMask[TR::STATE_DIVE] = WATER; + + stateMask[TR::STATE_PUSH_PULL_READY] = GROUND | ACTION | PULL; + stateMask[TR::STATE_PICK_UP] = GROUND | ACTION | PICKUP; + stateMask[TR::STATE_SWITCH_ON] = GROUND | ACTION | SWITCH_ON; + stateMask[TR::STATE_SWITCH_OFF] = GROUND | ACTION | SWITCH_OFF; + stateMask[TR::STATE_USE_KEY] = GROUND | ACTION | KEY; + stateMask[TR::STATE_USE_PUZZLE] = GROUND | ACTION | PUZZLE; + + stateMask[TR::STATE_SWAN_DIVE] = JUMP | WALK | FORTH; - int origMask = mask; - if (origMask & (FORTH | BACK)) - mask &= ~(LEFT | RIGHT); + fTime += Core::deltaTime; + int fCount = anim->frameEnd - anim->frameStart + 1; + int fIndex = int(fTime * 30.0f); + state = -1; + int maxMask = 0; + if (stateMask[anim->state] != mask) + for (int i = 0; i < anim->scCount; i++) { + TR::AnimState &sc = level->states[anim->scOffset + i]; + if (sc.state >= TR::STATE_MAX || stateMask[sc.state] == -1) + LOG("unknown state %d\n", sc.state); + else + if (stateMask[sc.state] > maxMask && ((stateMask[sc.state] & mask) == stateMask[sc.state])) { + maxMask = stateMask[sc.state]; + state = anim->scOffset + i; + } + } - int stateMask[TR::STATE_MAX]; - for (int i = 0; i < TR::STATE_MAX; i++) - stateMask[i] = -1; - - stateMask[TR::STATE_WALK] = GROUND | FORTH | WALK; - stateMask[TR::STATE_RUN] = GROUND | FORTH; - stateMask[TR::STATE_STOP] = GROUND; - stateMask[TR::STATE_FORWARD_JUMP] = GROUND | JUMP | FORTH; -// stateMask[TR::STATE_FAST_TURN] = 0; - stateMask[TR::STATE_FAST_BACK] = GROUND | BACK; - stateMask[TR::STATE_TURN_RIGHT] = GROUND | RIGHT; - stateMask[TR::STATE_TURN_LEFT] = GROUND | LEFT; - stateMask[TR::STATE_DEATH] = DEATH; - stateMask[TR::STATE_FAST_FALL] = FALL; - stateMask[TR::STATE_HANG] = HANG | ACTION; - stateMask[TR::STATE_REACH] = ACTION; -// stateMask[TR::STATE_SPLAT] -// stateMask[TR::STATE_TREAD] -// stateMask[TR::STATE_FAST_TURN_14] - stateMask[TR::STATE_COMPRESS] = GROUND | JUMP; - stateMask[TR::STATE_BACK] = GROUND | WALK | BACK; - stateMask[TR::STATE_SWIM] = WATER | FORTH; -// stateMask[TR::STATE_GLIDE] -// stateMask[TR::STATE_NULL_19] -// stateMask[TR::STATE_FAST_TURN_20] - stateMask[TR::STATE_FAST_TURN_20] = GROUND | LEFT | RIGHT; - stateMask[TR::STATE_STEP_RIGHT] = GROUND | WALK | RIGHT; - stateMask[TR::STATE_STEP_LEFT] = GROUND | WALK | LEFT; - stateMask[TR::STATE_ROLL] = GROUND | ROLL; -// stateMask[TR::STATE_SLIDE] - stateMask[TR::STATE_BACK_JUMP] = GROUND | COMPRESS | BACK; - stateMask[TR::STATE_RIGHT_JUMP] = GROUND | COMPRESS | RIGHT; - stateMask[TR::STATE_LEFT_JUMP] = GROUND | COMPRESS | LEFT; - stateMask[TR::STATE_UP_JUMP] = GROUND | COMPRESS; - - stateMask[TR::STATE_DIVE] = WATER; - - stateMask[TR::STATE_PUSH_PULL_READY] = GROUND | ACTION | PULL; - stateMask[TR::STATE_PICK_UP] = GROUND | ACTION | PICKUP; - stateMask[TR::STATE_SWITCH_ON] = GROUND | ACTION | SWITCH_ON; - stateMask[TR::STATE_SWITCH_OFF] = GROUND | ACTION | SWITCH_OFF; - stateMask[TR::STATE_USE_KEY] = GROUND | ACTION | KEY; - stateMask[TR::STATE_USE_PUZZLE] = GROUND | ACTION | PUZZLE; - - stateMask[TR::STATE_SWAN_DIVE] = JUMP | WALK | FORTH; - - - fTime += Core::deltaTime; - int fCount = anim->frameEnd - anim->frameStart + 1; - int fIndex = int(fTime * 30.0f); - - state = -1; - int maxMask = 0; - if (stateMask[anim->state] != mask) - for (int i = 0; i < anim->scCount; i++) { - TR::AnimState &sc = level->states[anim->scOffset + i]; - if (sc.state >= TR::STATE_MAX || stateMask[sc.state] == -1) - LOG("unknown state %d\n", sc.state); - else - if (stateMask[sc.state] > maxMask && ((stateMask[sc.state] & mask) == stateMask[sc.state])) { - maxMask = stateMask[sc.state]; - state = anim->scOffset + i; - } - } - - if (state > -1 && anim->state != level->states[state].state) { - TR::AnimState &sc = level->states[state]; - for (int j = 0; j < sc.rangesCount; j++) { - TR::AnimRange &range = level->ranges[sc.rangesOffset + j]; - if ( anim->frameStart + fIndex >= range.low && anim->frameStart + fIndex <= range.high) { - int st = anim->state; - anim = &level->anims[range.nextAnimation]; - fIndex = range.nextFrame - anim->frameStart; - fCount = anim->frameEnd - anim->frameStart + 1; - fTime = fIndex / 30.0f; - break; - } - } - } + if (state > -1 && anim->state != level->states[state].state) { + TR::AnimState &sc = level->states[state]; + for (int j = 0; j < sc.rangesCount; j++) { + TR::AnimRange &range = level->ranges[sc.rangesOffset + j]; + if ( anim->frameStart + fIndex >= range.low && anim->frameStart + fIndex <= range.high) { + int st = anim->state; + anim = &level->anims[range.nextAnimation]; + fIndex = range.nextFrame - anim->frameStart; + fCount = anim->frameEnd - anim->frameStart + 1; + fTime = fIndex / 30.0f; + break; + } + } + } #ifdef _DEBUG - if (Input::down[ikEnter]) { - if (!lState) { - lState = true; - // state = TR::STATE_ROLL; - // fTime = 0; + if (Input::down[ikEnter]) { + if (!lState) { + lState = true; + // state = TR::STATE_ROLL; + // fTime = 0; - // sc = (sc + 1) % level->statesCount; - // anim = &level->anims[146];//level->ranges[ level->states[sc].rangesOffset ].nextAnimation ]; - // fTime = 0; - // state = level->states[sc].state; - - LOG("state: %d\n", anim->state); - for (int i = 0; i < anim->scCount; i++) { - auto &sc = level->states[anim->scOffset + i]; - LOG("-> %d : ", (int)sc.state); - for (int j = 0; j < sc.rangesCount; j++) { - TR::AnimRange &range = level->ranges[sc.rangesOffset + j]; - LOG("%d ", range.nextAnimation); - //range. - } - LOG("\n"); - } - - } - } else - lState = false; + // sc = (sc + 1) % level->statesCount; + // anim = &level->anims[146];//level->ranges[ level->states[sc].rangesOffset ].nextAnimation ]; + // fTime = 0; + // state = level->states[sc].state; + + LOG("state: %d\n", anim->state); + for (int i = 0; i < anim->scCount; i++) { + auto &sc = level->states[anim->scOffset + i]; + LOG("-> %d : ", (int)sc.state); + for (int j = 0; j < sc.rangesCount; j++) { + TR::AnimRange &range = level->ranges[sc.rangesOffset + j]; + LOG("%d ", range.nextAnimation); + //range. + } + LOG("\n"); + } + + } + } else + lState = false; #endif - if (anim->state == TR::STATE_RUN || - anim->state == TR::STATE_FAST_BACK || - anim->state == TR::STATE_WALK || - anim->state == TR::STATE_BACK || - anim->state == TR::STATE_TURN_LEFT || - anim->state == TR::STATE_TURN_RIGHT) { + if (anim->state == TR::STATE_RUN || + anim->state == TR::STATE_FAST_BACK || + anim->state == TR::STATE_WALK || + anim->state == TR::STATE_BACK || + anim->state == TR::STATE_TURN_LEFT || + anim->state == TR::STATE_TURN_RIGHT) { - if (origMask & LEFT) angle -= Core::deltaTime * PI; - if (origMask & RIGHT) angle += Core::deltaTime * PI; - } + if (origMask & LEFT) angle -= Core::deltaTime * PI; + if (origMask & RIGHT) angle += Core::deltaTime * PI; + } - float d = 0.0f; - switch (anim->state) { - case TR::STATE_BACK : - case TR::STATE_BACK_JUMP : - case TR::STATE_FAST_BACK : - d = PI; - break; - case TR::STATE_STEP_LEFT : - case TR::STATE_LEFT_JUMP : - d = -PI * 0.5f; - break; - case TR::STATE_STEP_RIGHT : - case TR::STATE_RIGHT_JUMP : - d = PI * 0.5f; - break; - } - d += angle; + float d = 0.0f; + switch (anim->state) { + case TR::STATE_BACK : + case TR::STATE_BACK_JUMP : + case TR::STATE_FAST_BACK : + d = PI; + break; + case TR::STATE_STEP_LEFT : + case TR::STATE_LEFT_JUMP : + d = -PI * 0.5f; + break; + case TR::STATE_STEP_RIGHT : + case TR::STATE_RIGHT_JUMP : + d = PI * 0.5f; + break; + } + d += angle; - bool endFrame = fIndex >= fCount; + bool endFrame = fIndex >= fCount; - int16 *ptr = &level->commands[anim->animCommand]; + int16 *ptr = &level->commands[anim->animCommand]; - for (int i = 0; i < anim->acCount; i++) { - switch (*ptr++) { - case 0x01 : { // cmd position - int16 sx = *ptr++; - int16 sy = *ptr++; - int16 sz = *ptr++; - LOG("move: %d %d\n", (int)sx, (int)sy, (int)sz); - break; - } - case 0x02 : { // cmd jump speed - int16 sy = *ptr++; - int16 sz = *ptr++; - if (endFrame) { - LOG("jump: %d %d\n", (int)sy, (int)sz); - velocity.x = sinf(d) * sz; - velocity.y = sy; - velocity.z = cosf(d) * sz; - onGround = false; - } - break; - } - case 0x03 : // empty hands - break; - case 0x04 : // kill - break; - case 0x05 : { // play sound - int frame = (*ptr++); - int id = (*ptr++) & 0x3FFF; - if (fIndex == frame - anim->frameStart && fIndex != lastFrame) { - auto a = level->soundsMap[id]; - auto b = level->soundsInfo[a].index; - auto c = level->soundOffsets[b]; + for (int i = 0; i < anim->acCount; i++) { + switch (*ptr++) { + case 0x01 : { // cmd position + int16 sx = *ptr++; + int16 sy = *ptr++; + int16 sz = *ptr++; + LOG("move: %d %d %d\n", (int)sx, (int)sy, (int)sz); + break; + } + case 0x02 : { // cmd jump speed + int16 sy = *ptr++; + int16 sz = *ptr++; + if (endFrame) { + LOG("jump: %d %d\n", (int)sy, (int)sz); + velocity.x = sinf(d) * sz; + velocity.y = sy; + velocity.z = cosf(d) * sz; + onGround = false; + } + break; + } + case 0x03 : // empty hands + break; + case 0x04 : // kill + break; + case 0x05 : { // play sound + int frame = (*ptr++); + int id = (*ptr++) & 0x3FFF; + if (fIndex == frame - anim->frameStart && fIndex != lastFrame) { + auto a = level->soundsMap[id]; + auto b = level->soundsInfo[a].index; + auto c = level->soundOffsets[b]; - void *p = &level->soundData[c]; + void *p = &level->soundData[c]; - // PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY); - } - break; - } - case 0x06 : - if (fIndex != lastFrame && fIndex + anim->frameStart == ptr[0]) { - if (ptr[1] == 0) { - angle = angle + PI; - } - } - ptr += 2; - break; - } - } + // PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY); + } + break; + } + case 0x06 : + if (fIndex != lastFrame && fIndex + anim->frameStart == ptr[0]) { + if (ptr[1] == 0) { + angle = angle + PI; + } + } + ptr += 2; + break; + } + } - float dt = Core::deltaTime * 30.0f; + float dt = Core::deltaTime * 30.0f; - if (onGround) { - float speed = anim->speed.toFloat() + anim->accel.toFloat() * (fTime * 30.0f); - velocity.x = sinf(d) * speed; - velocity.z = cosf(d) * speed; - } - velocity.y += GRAVITY * dt; + if (onGround) { + float speed = anim->speed.toFloat() + anim->accel.toFloat() * (fTime * 30.0f); + velocity.x = sinf(d) * speed; + velocity.z = cosf(d) * speed; + } + velocity.y += GRAVITY * dt; - if (endFrame) { - fIndex = anim->nextFrame; - int id = anim->nextAnimation; - anim = &level->anims[anim->nextAnimation]; - fIndex -= anim->frameStart; - fTime = fIndex / 30.0f; - fCount = anim->frameEnd - anim->frameStart + 1; - } - + if (endFrame) { + fIndex = anim->nextFrame; + int id = anim->nextAnimation; + anim = &level->anims[anim->nextAnimation]; + fIndex -= anim->frameStart; + fTime = fIndex / 30.0f; + fCount = anim->frameEnd - anim->frameStart + 1; + } - move(velocity * dt); - collide(); + move(velocity * dt); + collide(); - lastFrame = fIndex; - } + lastFrame = fIndex; + } - void move(const vec3 &offset) { - vec3 p = pos; - pos = pos + offset; + void move(const vec3 &offset) { + vec3 p = pos; + pos = pos + offset; - updateEntity(); + updateEntity(); - TR::Room &room = getRoom(); - TR::Entity &entity = getEntity(); + TR::Room &room = getRoom(); + TR::Entity &entity = getEntity(); - int dx, dz; - TR::Room::Sector &s = getSector(dx, dz); + int dx, dz; + TR::Room::Sector &s = getSector(dx, dz); - int d = entity.y - s.floor * 256; - if (d >= 256 * 4) { - pos.x = p.x;//vec3(entity.x, entity.y, entity.z); - pos.z = p.z; - updateEntity(); - if (d >= 256 * 4) - anim = &level->anims[53]; // forward smash - else - anim = &level->anims[11]; // instant stand - state = anim->state; - fTime = 0; - } - } + int d = entity.y - s.floor * 256; + if (d >= 256 * 4) { + pos.x = p.x;//vec3(entity.x, entity.y, entity.z); + pos.z = p.z; + updateEntity(); + if (d >= 256 * 4) + anim = &level->anims[53]; // forward smash + else + anim = &level->anims[11]; // instant stand + state = anim->state; + fTime = 0; + } + } - void updateEntity() { - TR::Entity &e = getEntity(); - e.x = int(pos.x); - e.y = int(pos.y); - e.z = int(pos.z); - e.rotation = int(angle / (PI * 0.5f) * 16384.0f); - } + void updateEntity() { + TR::Entity &e = getEntity(); + e.x = int(pos.x); + e.y = int(pos.y); + e.z = int(pos.z); + e.rotation = int(angle / (PI * 0.5f) * 16384.0f); + } - bool insideRoom(const vec3 &pos, int room) { - TR::Room &r = level->rooms[room]; - vec3 min = vec3(r.info.x, r.info.yTop, r.info.z); - vec3 max = min + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024); + bool insideRoom(const vec3 &pos, int room) { + TR::Room &r = level->rooms[room]; + vec3 min = vec3(r.info.x, r.info.yTop, r.info.z); + vec3 max = min + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024); - return pos.x >= min.x && pos.x <= max.x && - pos.y >= min.y && pos.y <= max.y && - pos.z >= min.z && pos.z <= max.z; - } + return pos.x >= min.x && pos.x <= max.x && + pos.y >= min.y && pos.y <= max.y && + pos.z >= min.z && pos.z <= max.z; + } - TR::Entity& getEntity() { - return level->entities[entity]; - } + TR::Entity& getEntity() { + return level->entities[entity]; + } - TR::Model& getModel() { - TR::Entity &entity = getEntity(); - for (int i = 0; i < level->modelsCount; i++) - if (entity.id == level->models[i].id) - return level->models[i]; - } + TR::Model& getModel() { + TR::Entity &entity = getEntity(); + for (int i = 0; i < level->modelsCount; i++) + if (entity.id == level->models[i].id) + return level->models[i]; + ASSERT(false); + return level->models[0]; + } - TR::Room& getRoom() { - return level->rooms[getEntity().room]; - } + TR::Room& getRoom() { + return level->rooms[getEntity().room]; + } - TR::Room::Sector& getSector(int &dx, int &dz) { - TR::Room &room = getRoom(); - TR::Entity &entity = getEntity(); + TR::Room::Sector& getSector(int &dx, int &dz) { + TR::Room &room = getRoom(); + TR::Entity &entity = getEntity(); - dx = entity.x - room.info.x; - dz = entity.z - room.info.z; - int sx = dx / 1024; - int sz = dz / 1024; - dx -= sx * 1024; - dz -= sz * 1024; + dx = entity.x - room.info.x; + dz = entity.z - room.info.z; + int sx = dx / 1024; + int sz = dz / 1024; + dx -= sx * 1024; + dz -= sz * 1024; - return room.sectors[sx * room.zSectors + sz]; - } + return room.sectors[sx * room.zSectors + sz]; + } - void collide() { - int dx, dz; - TR::Room::Sector &s = getSector(dx, dz); - TR::Entity &entity = getEntity(); - - float bottom = s.floor * 256; + void collide() { + int dx, dz; + TR::Room::Sector &s = getSector(dx, dz); + TR::Entity &entity = getEntity(); - float fx = dx / 1024.0f, fz = dz / 1024.0f; + float bottom = (int)s.floor * 256; - // dx -= 512; - // dz -= 512; + float fx = dx / 1024.0f, fz = dz / 1024.0f; - uint16 cmd, *d = &level->floors[s.floorIndex]; + 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 + 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 : { - int8 sx = (int8)(*d & 0x00FF); - int8 sz = (int8)((*d & 0xFF00) >> 8); + switch (func) { + case 1 : + entity.room = *d++; + break; + case 2 : + case 3 : { + int8 sx = (int8)(*d & 0x00FF); + int8 sz = (int8)((*d & 0xFF00) >> 8); - if (func == 2) { - if (sx > 0) - bottom += (int)sx * (1024 - dx) >> 2; - else - bottom -= (int)sx * dx >> 2; - - if (sz > 0) - bottom += (int)sz * (1024 - dz) >> 2; - else - bottom -= (int)sz * dz >> 2; - } else { - /* - if (sx < 0) { - p[0].y += sx; - p[3].y += sx; - } else { - p[1].y -= sx; - p[2].y -= sx; - } + if (func == 2) { + if (sx > 0) + bottom += (int)sx * (1024 - dx) >> 2; + else + bottom -= (int)sx * dx >> 2; - if (sz > 0) { - p[0].y -= sz; - p[1].y -= sz; - } else { - p[3].y += sz; - p[2].y += sz; - } - */ - } - d++; - break; - } - case 4 : { - /* - //*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; - } - default : - LOG("unknown func: %d\n", func); - } + if (sz > 0) + bottom += (int)sz * (1024 - dz) >> 2; + else + bottom -= (int)sz * dz >> 2; + } else { + /* + if (sx < 0) { + p[0].y += sx; + p[3].y += sx; + } else { + p[1].y -= sx; + p[2].y -= sx; + } - } while (!(cmd & 0x8000)); + if (sz > 0) { + p[0].y -= sz; + p[1].y -= sz; + } else { + p[3].y += sz; + p[2].y += sz; + } + */ + } + 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)); - onGround = pos.y > bottom; - if (onGround) { - onGround = true; - if (s.roomBelow != 255) { - entity.room = s.roomBelow; - onGround = false; - return; - } - pos.y = bottom; - velocity.y = 0.0f; - } + onGround = pos.y > bottom; + if (onGround) { + onGround = true; + if (s.roomBelow != 255) { + entity.room = s.roomBelow; + onGround = false; + return; + } + pos.y = bottom; + velocity.y = 0.0f; + } - entity.y = (int)pos.y; - } + entity.y = (int)pos.y; + } }; diff --git a/src/core.h b/src/core.h index 497d1b2..fdf3de1 100644 --- a/src/core.h +++ b/src/core.h @@ -3,9 +3,9 @@ #include #ifdef WIN32 - #include - #include - #include + #include + #include + #include #elif __EMSCRIPTEN__ #include #include @@ -18,56 +18,56 @@ #include "input.h" #ifdef WIN32 - #if defined(_MSC_VER) // Visual Studio - #define GetProcOGL(x) *(void**)&x=(void*)wglGetProcAddress(#x); - #else // GCC - #define GetProcOGL(x) x=(typeof(x))wglGetProcAddress(#x); - #endif + #if defined(_MSC_VER) // Visual Studio + #define GetProcOGL(x) *(void**)&x=(void*)wglGetProcAddress(#x); + #else // GCC + #define GetProcOGL(x) x=(typeof(x))wglGetProcAddress(#x); + #endif // Texture - PFNGLACTIVETEXTUREPROC glActiveTexture; + PFNGLACTIVETEXTUREPROC glActiveTexture; // Shader - PFNGLCREATEPROGRAMPROC glCreateProgram; - PFNGLDELETEPROGRAMPROC glDeleteProgram; - PFNGLLINKPROGRAMPROC glLinkProgram; - PFNGLUSEPROGRAMPROC glUseProgram; - PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; - PFNGLCREATESHADERPROC glCreateShader; - PFNGLDELETESHADERPROC glDeleteShader; - PFNGLSHADERSOURCEPROC glShaderSource; - PFNGLATTACHSHADERPROC glAttachShader; - PFNGLCOMPILESHADERPROC glCompileShader; - PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; - PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; - PFNGLUNIFORM1IVPROC glUniform1iv; - PFNGLUNIFORM3FVPROC glUniform3fv; - PFNGLUNIFORM4FVPROC glUniform4fv; - PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; - PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; - PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; - PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; - PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; + PFNGLCREATEPROGRAMPROC glCreateProgram; + PFNGLDELETEPROGRAMPROC glDeleteProgram; + PFNGLLINKPROGRAMPROC glLinkProgram; + PFNGLUSEPROGRAMPROC glUseProgram; + PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; + PFNGLCREATESHADERPROC glCreateShader; + PFNGLDELETESHADERPROC glDeleteShader; + PFNGLSHADERSOURCEPROC glShaderSource; + PFNGLATTACHSHADERPROC glAttachShader; + PFNGLCOMPILESHADERPROC glCompileShader; + PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; + PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; + PFNGLUNIFORM1IVPROC glUniform1iv; + PFNGLUNIFORM3FVPROC glUniform3fv; + PFNGLUNIFORM4FVPROC glUniform4fv; + PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; + PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; + PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; + PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; + PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; // Mesh - PFNGLGENBUFFERSARBPROC glGenBuffers; - PFNGLDELETEBUFFERSARBPROC glDeleteBuffers; - PFNGLBINDBUFFERARBPROC glBindBuffer; - PFNGLBUFFERDATAARBPROC glBufferData; + PFNGLGENBUFFERSARBPROC glGenBuffers; + PFNGLDELETEBUFFERSARBPROC glDeleteBuffers; + PFNGLBINDBUFFERARBPROC glBindBuffer; + PFNGLBUFFERDATAARBPROC glBufferData; #endif namespace Core { - int width, height; - float deltaTime; - mat4 mView, mProj, mViewProj, mModel; - vec3 viewPos; - vec3 lightPos; - vec4 lightColor; - vec3 ambient; - vec4 color; + int width, height; + float deltaTime; + mat4 mView, mProj, mViewProj, mModel; + vec3 viewPos; + vec3 lightPos; + vec4 lightColor; + vec3 ambient; + vec4 color; - struct { - int dips; - int tris; - } stats; + struct { + int dips; + int tris; + } stats; } #include "texture.h" @@ -79,89 +79,89 @@ enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen }; namespace Core { - void init() { - #ifdef WIN32 - GetProcOGL(glActiveTexture); + void init() { + #ifdef WIN32 + GetProcOGL(glActiveTexture); - GetProcOGL(glCreateProgram); - GetProcOGL(glDeleteProgram); - GetProcOGL(glLinkProgram); - GetProcOGL(glUseProgram); - GetProcOGL(glGetProgramInfoLog); - GetProcOGL(glCreateShader); - GetProcOGL(glDeleteShader); - GetProcOGL(glShaderSource); - GetProcOGL(glAttachShader); - GetProcOGL(glCompileShader); - GetProcOGL(glGetShaderInfoLog); - GetProcOGL(glGetUniformLocation); - GetProcOGL(glUniform1iv); - GetProcOGL(glUniform3fv); - GetProcOGL(glUniform4fv); - GetProcOGL(glUniformMatrix4fv); - GetProcOGL(glBindAttribLocation); - GetProcOGL(glEnableVertexAttribArray); - GetProcOGL(glDisableVertexAttribArray); - GetProcOGL(glVertexAttribPointer); + GetProcOGL(glCreateProgram); + GetProcOGL(glDeleteProgram); + GetProcOGL(glLinkProgram); + GetProcOGL(glUseProgram); + GetProcOGL(glGetProgramInfoLog); + GetProcOGL(glCreateShader); + GetProcOGL(glDeleteShader); + GetProcOGL(glShaderSource); + GetProcOGL(glAttachShader); + GetProcOGL(glCompileShader); + GetProcOGL(glGetShaderInfoLog); + GetProcOGL(glGetUniformLocation); + GetProcOGL(glUniform1iv); + GetProcOGL(glUniform3fv); + GetProcOGL(glUniform4fv); + GetProcOGL(glUniformMatrix4fv); + GetProcOGL(glBindAttribLocation); + GetProcOGL(glEnableVertexAttribArray); + GetProcOGL(glDisableVertexAttribArray); + GetProcOGL(glVertexAttribPointer); - GetProcOGL(glGenBuffers); - GetProcOGL(glDeleteBuffers); - GetProcOGL(glBindBuffer); - GetProcOGL(glBufferData); - #endif - } + GetProcOGL(glGenBuffers); + GetProcOGL(glDeleteBuffers); + GetProcOGL(glBindBuffer); + GetProcOGL(glBufferData); + #endif + } - void free() { - // - } + void free() { + // + } - void clear(const vec4 &color) { - glClearColor(color.x, color.y, color.z, color.w); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + void clear(const vec4 &color) { + glClearColor(color.x, color.y, color.z, color.w); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } - void setViewport(int x, int y, int width, int height) { - glViewport(x, y, width, height); - } + void setViewport(int x, int y, int width, int height) { + glViewport(x, y, width, height); + } - void setCulling(CullMode mode) { - switch (mode) { - case cfNone : - glDisable(GL_CULL_FACE); - case cfBack : - glCullFace(GL_BACK); - break; - case cfFront : - glCullFace(GL_FRONT); - break; - } + void setCulling(CullMode mode) { + switch (mode) { + case cfNone : + glDisable(GL_CULL_FACE); + case cfBack : + glCullFace(GL_BACK); + break; + case cfFront : + glCullFace(GL_FRONT); + break; + } - if (mode != bmNone) - glEnable(GL_CULL_FACE); - } + if (mode != cfNone) + glEnable(GL_CULL_FACE); + } - void setBlending(BlendMode mode) { - switch (mode) { - case bmNone : - glDisable(GL_BLEND); - break; - case bmAlpha : - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case bmAdd : - glBlendFunc(GL_ONE, GL_ONE); - break; - case bmMultiply : - glBlendFunc(GL_DST_COLOR, GL_ZERO); - break; - case bmScreen : - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); - break; - } + void setBlending(BlendMode mode) { + switch (mode) { + case bmNone : + glDisable(GL_BLEND); + break; + case bmAlpha : + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case bmAdd : + glBlendFunc(GL_ONE, GL_ONE); + break; + case bmMultiply : + glBlendFunc(GL_DST_COLOR, GL_ZERO); + break; + case bmScreen : + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + break; + } - if (mode != bmNone) - glEnable(GL_BLEND); - } + if (mode != bmNone) + glEnable(GL_BLEND); + } } #endif \ No newline at end of file diff --git a/src/debug.h b/src/debug.h index 54f8c80..d32fba1 100644 --- a/src/debug.h +++ b/src/debug.h @@ -5,109 +5,109 @@ namespace Debug { - namespace Draw { + namespace Draw { - void begin() { - glMatrixMode(GL_PROJECTION); - glLoadMatrixf((GLfloat*)&Core::mProj); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glLoadMatrixf((GLfloat*)&Core::mView); + void begin() { + glMatrixMode(GL_PROJECTION); + glLoadMatrixf((GLfloat*)&Core::mProj); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glLoadMatrixf((GLfloat*)&Core::mView); - glLineWidth(3); - glPointSize(32); + glLineWidth(3); + glPointSize(32); - glUseProgram(0); - } + glUseProgram(0); + } - void end() { - // - } + void end() { + // + } - void box(const vec3 &min, const vec3 &max) { - glBegin(GL_LINES); - glVertex3f(min.x, min.y, min.z); - glVertex3f(max.x, min.y, min.z); - glVertex3f(min.x, max.y, min.z); - glVertex3f(max.x, max.y, min.z); + void box(const vec3 &min, const vec3 &max) { + glBegin(GL_LINES); + glVertex3f(min.x, min.y, min.z); + glVertex3f(max.x, min.y, min.z); + glVertex3f(min.x, max.y, min.z); + glVertex3f(max.x, max.y, min.z); - glVertex3f(min.x, min.y, max.z); - glVertex3f(max.x, min.y, max.z); - glVertex3f(min.x, max.y, max.z); - glVertex3f(max.x, max.y, max.z); + glVertex3f(min.x, min.y, max.z); + glVertex3f(max.x, min.y, max.z); + glVertex3f(min.x, max.y, max.z); + glVertex3f(max.x, max.y, max.z); - glVertex3f(min.x, min.y, min.z); - glVertex3f(min.x, min.y, max.z); - glVertex3f(min.x, max.y, min.z); - glVertex3f(min.x, max.y, max.z); + glVertex3f(min.x, min.y, min.z); + glVertex3f(min.x, min.y, max.z); + glVertex3f(min.x, max.y, min.z); + glVertex3f(min.x, max.y, max.z); - glVertex3f(max.x, min.y, min.z); - glVertex3f(max.x, min.y, max.z); - glVertex3f(max.x, max.y, min.z); - glVertex3f(max.x, max.y, max.z); + glVertex3f(max.x, min.y, min.z); + glVertex3f(max.x, min.y, max.z); + glVertex3f(max.x, max.y, min.z); + glVertex3f(max.x, max.y, max.z); - glVertex3f(min.x, min.y, min.z); - glVertex3f(min.x, max.y, min.z); + glVertex3f(min.x, min.y, min.z); + glVertex3f(min.x, max.y, min.z); - glVertex3f(max.x, min.y, min.z); - glVertex3f(max.x, max.y, min.z); - glVertex3f(min.x, min.y, min.z); - glVertex3f(min.x, max.y, min.z); + glVertex3f(max.x, min.y, min.z); + glVertex3f(max.x, max.y, min.z); + glVertex3f(min.x, min.y, min.z); + glVertex3f(min.x, max.y, min.z); - glVertex3f(max.x, min.y, max.z); - glVertex3f(max.x, max.y, max.z); - glVertex3f(min.x, min.y, max.z); - glVertex3f(min.x, max.y, max.z); - glEnd(); - } + glVertex3f(max.x, min.y, max.z); + glVertex3f(max.x, max.y, max.z); + glVertex3f(min.x, min.y, max.z); + glVertex3f(min.x, max.y, max.z); + glEnd(); + } - void sphere(const vec3 ¢er, const float radius, const vec4 &color) { - const float k = PI * 2.0f / 18.0f; + void sphere(const vec3 ¢er, const float radius, const vec4 &color) { + const float k = PI * 2.0f / 18.0f; - glColor4fv((GLfloat*)&color); - for (int j = 0; j < 3; j++) { - glBegin(GL_LINE_STRIP); - for (int i = 0; i < 19; i++) { - vec3 p = vec3(sinf(i * k), cosf(i * k), 0.0f) * radius; - glVertex3f(p[j] + center.x, p[(j + 1) % 3] + center.y, p[(j + 2) % 3] + center.z); - } - glEnd(); - } - } + glColor4fv((GLfloat*)&color); + for (int j = 0; j < 3; j++) { + glBegin(GL_LINE_STRIP); + for (int i = 0; i < 19; i++) { + vec3 p = vec3(sinf(i * k), cosf(i * k), 0.0f) * radius; + glVertex3f(p[j] + center.x, p[(j + 1) % 3] + center.y, p[(j + 2) % 3] + center.z); + } + glEnd(); + } + } - void mesh(vec3 *vertices, Index *indices, int iCount) { - glBegin(GL_LINES); - for (int i = 0; i < iCount; i += 3) { - vec3 &a = vertices[indices[i + 0]]; - vec3 &b = vertices[indices[i + 1]]; - vec3 &c = vertices[indices[i + 2]]; - glVertex3fv((GLfloat*)&a); - glVertex3fv((GLfloat*)&b); + void mesh(vec3 *vertices, Index *indices, int iCount) { + glBegin(GL_LINES); + for (int i = 0; i < iCount; i += 3) { + vec3 &a = vertices[indices[i + 0]]; + vec3 &b = vertices[indices[i + 1]]; + vec3 &c = vertices[indices[i + 2]]; + glVertex3fv((GLfloat*)&a); + glVertex3fv((GLfloat*)&b); - glVertex3fv((GLfloat*)&b); - glVertex3fv((GLfloat*)&c); + glVertex3fv((GLfloat*)&b); + glVertex3fv((GLfloat*)&c); - glVertex3fv((GLfloat*)&c); - glVertex3fv((GLfloat*)&a); - } - glEnd(); - } + glVertex3fv((GLfloat*)&c); + glVertex3fv((GLfloat*)&a); + } + glEnd(); + } - void axes(float size) { - glBegin(GL_LINES); - glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(size, 0, 0); - glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f( 0, size, 0); - glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f( 0, 0, size); - glEnd(); - } + void axes(float size) { + glBegin(GL_LINES); + glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(size, 0, 0); + glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f( 0, size, 0); + glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f( 0, 0, size); + glEnd(); + } - void point(const vec3 &p, const vec4 &color) { - glColor4fv((GLfloat*)&color); - glBegin(GL_POINTS); - glVertex3fv((GLfloat*)&p); - glEnd(); - } - } + void point(const vec3 &p, const vec4 &color) { + glColor4fv((GLfloat*)&color); + glBegin(GL_POINTS); + glVertex3fv((GLfloat*)&p); + glEnd(); + } + } } #endif \ No newline at end of file diff --git a/src/format.h b/src/format.h index 019924c..c3e48d3 100644 --- a/src/format.h +++ b/src/format.h @@ -6,651 +6,676 @@ #define TR1_DEMO namespace TR { - #define DATA_PORTAL 0x01 - #define DATA_FLOOR 0x02 - #define DATA_CEILING 0x03 - - - #define ENTITY_FLAG_CLEAR 0x0080 - #define ENTITY_FLAG_VISIBLE 0x0100 - #define ENTITY_FLAG_MASK 0x3E00 - - #define ENTITY_LARA 0 - - #define ENTITY_ENEMY_TWIN 6 - #define ENTITY_ENEMY_WOLF 7 - #define ENTITY_ENEMY_BEAR 8 - #define ENTITY_ENEMY_BAT 9 - #define ENTITY_ENEMY_CROCODILE_LAND 10 - #define ENTITY_ENEMY_CROCODILE_WATER 11 - #define ENTITY_ENEMY_LION_MALE 12 - #define ENTITY_ENEMY_LION_FEMALE 13 - #define ENTITY_ENEMY_PUMA 14 - #define ENTITY_ENEMY_GORILLA 15 - #define ENTITY_ENEMY_RAT_LAND 16 - #define ENTITY_ENEMY_RAT_WATER 17 - #define ENTITY_ENEMY_REX 18 - #define ENTITY_ENEMY_RAPTOR 19 - #define ENTITY_ENEMY_MUTANT 20 - - #define ENTITY_ENEMY_CENTAUR 23 - #define ENTITY_ENEMY_MUMMY 24 - #define ENTITY_ENEMY_LARSON 27 - - #define ENTITY_CRYSTAL 83 - - #define ENTITY_MEDIKIT_SMALL 93 - #define ENTITY_MEDIKIT_BIG 94 - - #define ENTITY_VIEW_TARGET 169 - - #define ENTITY_TRAP_FLOOR 35 - #define ENTITY_TRAP_SPIKES 37 - #define ENTITY_TRAP_STONE 38 - #define ENTITY_TRAP_DART 40 - - #define ENTITY_SWITCH 55 - - #define ENTITY_GUN_SHOTGUN 85 - - #define ENTITY_AMMO_UZI 91 - #define ENTITY_AMMO_SHOTGUN 89 - #define ENTITY_AMMO_MAGNUM 90 - - - enum LaraState { - STATE_WALK, - STATE_RUN, - STATE_STOP, - STATE_FORWARD_JUMP, - STATE_FAST_TURN, - STATE_FAST_BACK, - STATE_TURN_RIGHT, - STATE_TURN_LEFT, - STATE_DEATH, - STATE_FAST_FALL, - STATE_HANG, - STATE_REACH, - STATE_SPLAT, - STATE_TREAD, - STATE_FAST_TURN_14, - STATE_COMPRESS, - STATE_BACK, - STATE_SWIM, - STATE_GLIDE, - STATE_NULL_19, - STATE_FAST_TURN_20, - STATE_STEP_RIGHT, - STATE_STEP_LEFT, - STATE_ROLL, - STATE_SLIDE, - STATE_BACK_JUMP, - STATE_RIGHT_JUMP, - STATE_LEFT_JUMP, - STATE_UP_JUMP, - STATE_FALL_BACK, - STATE_HANG_LEFT, - STATE_HANG_RIGHT, - STATE_SLIDE_BACK, - STATE_SURF_TREAD, - STATE_SURF_SWIM, - STATE_DIVE, - STATE_PUSH_BLOCK, - STATE_PULL_BLOCK, - STATE_PUSH_PULL_READY, - STATE_PICK_UP, - STATE_SWITCH_ON, - STATE_SWITCH_OFF, - STATE_USE_KEY, - STATE_USE_PUZZLE, - STATE_UNDERWATER_DEATH, - STATE_ROLL_45, - STATE_SPECIAL, - STATE_SURF_BACK, - STATE_SURF_LEFT, - STATE_SURF_RIGHT, - STATE_NULL_50, - STATE_NULL_51, - STATE_SWAN_DIVE, - STATE_FAST_DIVE, - STATE_HANDSTAND, - 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 }; - - #pragma pack(push, 1) - - struct fixed { - uint16 L; - int16 H; - float toFloat() { - return H + L / 65535.0f; - } - }; - - struct RGB { - uint8 r, g, b; - }; - - struct RGBA { - uint8 r, g, b, a; - }; - - struct Vertex { - int16 x, y, z; - }; - - struct Rectangle { - uint16 vertices[4]; - uint16 texture; // 15 bit - double-sided - }; - - struct Triangle { - uint16 vertices[3]; - uint16 texture; - }; - - struct Tile8 { - uint8 index[256 * 256]; - }; - - struct Room { - - struct Info { - int32 x, z; - int32 yBottom, yTop; - } info; - - struct Data { - uint32 size; // Number of data words (uint16_t's) - - int16 vCount; - struct Vertex { - TR::Vertex vertex; - int16 lighting; // 0 (bright) .. 0x1FFF (dark) - } *vertices; - - int16 rCount; - Rectangle *rectangles; - - int16 tCount; - Triangle *triangles; - - int16 sCount; - struct Sprite { - int16 vertex; - int16 texture; - } *sprites; - } data; - - int16 portalsCount; - struct Portal { - uint16 roomIndex; - Vertex normal; - Vertex vertices[4]; - } *portals; - - uint16 zSectors; - uint16 xSectors; - struct Sector { - uint16 floorIndex; // Index into FloorData[] - uint16 boxIndex; // Index into Boxes[] (-1 if none) - uint8 roomBelow; // 255 is none - int8 floor; // Absolute height of floor * 256 - uint8 roomAbove; // 255 if none - int8 ceiling; // Absolute height of ceiling * 256 - } *sectors; - - int16 ambient; // 0 (bright) .. 0x1FFF (dark) - - int16 lightsCount; - struct Light { - int32 x, y, z; // Position of light, in world coordinates - uint16 Intensity; // Light intensity - uint32 fade; // Falloff value - } *lights; - - uint16 meshesCount; - struct Mesh { - int32 x, y, z; - uint16 rotation; // (rotation >> 14) * 90 - uint16 intensity; // 0 (bright) .. 0x1FFF (dark) - uint16 meshID; - } *meshes; - - int16 alternateRoom; - int16 flags; - }; - - struct Mesh { - Vertex center; - int32 radius; - - int16 vCount; - Vertex *vertices; // List of vertices (relative coordinates) - - int16 nCount; - union { - Vertex *normals; - int16 *lights; // if nCount < 0 -> (abs(nCount)) - }; - - uint16 rCount; - Rectangle *rectangles; - - uint16 tCount; - Triangle *triangles; - - uint16 crCount; - Rectangle *crectangles; - - uint16 ctCount; - Triangle *ctriangles; - }; - - struct Entity { - int16 id; // Object Identifier (matched in Models[], or SpriteSequences[], as appropriate) - int16 room; // which room contains this item - int32 x, y, z; // world coords - int16 rotation; // ((0xc000 >> 14) * 90) degrees - int16 intensity; // (constant lighting; -1 means use mesh lighting) - uint16 flags; // 0x0100 indicates "initially invisible", 0x3e00 is Activation Mask - // 0x3e00 indicates "open" or "activated"; these can be XORed with - // related FloorData::FDlist fields (e.g. for switches) - }; - - struct Animation { - uint32 frameOffset; // Byte offset into Frames[] (divide by 2 for Frames[i]) - uint8 frameRate; // Engine ticks per frame - uint8 frameSize; // Number of int16_t's in Frames[] used by this animation - - uint16 state; - - fixed speed; - fixed accel; - - uint16 frameStart; // First frame in this animation - uint16 frameEnd; // Last frame in this animation - uint16 nextAnimation; - uint16 nextFrame; - - uint16 scCount; - uint16 scOffset; // Offset into StateChanges[] - - uint16 acCount; // How many of them to use. - uint16 animCommand; // Offset into AnimCommand[] - }; - - struct AnimState { - uint16 state; - uint16 rangesCount; // number of ranges - uint16 rangesOffset; // Offset into animRanges[] - }; - - struct AnimRange { - int16 low; // Lowest frame that uses this range - int16 high; // Highest frame that uses this range - int16 nextAnimation; // Animation to dispatch to - int16 nextFrame; // Frame offset to dispatch to - }; - - struct AnimFrame { - int16 minX, minY, minZ; // Bounding box (low) - int16 maxX, maxY, maxZ; // Bounding box (high) - int16 x, y, z; // Starting offset for this model - int16 aCount; - uint16 angles[0]; // angle frames in YXZ order - }; - - struct AnimTexture { - int16 tCount; // Actually, this is the number of texture ID's - 1 - int16 textures[0]; // offsets into ObjectTextures[], in animation order - }; - - struct Node { - uint32 flags; - int32 x, y, z; - }; - - struct Model { - uint32 id; // Item Identifier (matched in Entities[]) - uint16 mCount; // number of meshes in this object - uint16 mStart; // stating mesh (offset into MeshPointers[]) - uint32 node; // offset into MeshTree[] - uint32 frame; // byte offset into Frames[] (divide by 2 for Frames[i]) - uint16 animation; // offset into Animations[] - }; - - struct StaticMesh { - uint32 id; // Static Mesh Identifier - uint16 mesh; // Mesh (offset into MeshPointers[]) - Vertex vBox[2]; - Vertex cBox[2]; - uint16 flags; - }; - - struct ObjectTexture { - uint16 attribute; // 0 - opaque, 1 - transparent, 2 - blend additive - uint16 tileAndFlag; // 0..14 - tile, 15 - is triangle - struct { - uint8 Xcoordinate; // 1 if Xpixel is the low value, 255 if Xpixel is the high value in the object texture - uint8 Xpixel; - uint8 Ycoordinate; // 1 if Ypixel is the low value, 255 if Ypixel is the high value in the object texture - uint8 Ypixel; - } vertices[4]; // The four corners of the texture - }; - - struct SpriteTexture { - uint16 tile; - uint8 u, v; - uint16 w, h; // (ActualValue * 256) + 255 - int16 l, t, r, b; - }; - - struct SpriteSequence { - int32 id; // Sprite identifier - int16 sCount; // Negative of ``how many sprites are in this sequence'' - int16 sStart; // Where (in sprite texture list) this sequence starts - }; - - struct Camera { - int32 x, y, z; - int16 room; - uint16 flags; - }; - - struct CameraFrame { - int16 rotY; - int16 rotZ; - int16 unused1; - int16 posZ; - int16 posY; - int16 posX; - int16 unknown; - int16 rotX; - }; - - struct SoundSource { - int32 x, y, z; // absolute position of sound source (world coordinates) - uint16 id; // internal sample index - uint16 flags; // 0x40, 0x80, or 0xC0 - }; - - struct Box { - int32 minZ, maxZ; // Horizontal dimensions in global units - int32 minX, maxX; - int16 floor; // Height value in global units - int16 overlap; // Index into Overlaps[]. - }; - - struct Zone { - struct { - uint16 groundZone1; - uint16 groundZone2; - uint16 flyZone; - } normal, alternate; - }; - - struct SoundInfo { - uint16 index; // (index into soundsIndices) -- NOT USED IN TR4-5!!! - uint16 volume; - 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 - }; - - struct Level { - char *data; - - uint32 version; // version (4 bytes) - - int32 tilesCount; - Tile8 *tiles; // 8-bit (palettized) textiles 256x256 - - uint32 unused; // 32-bit unused value (4 bytes) - - uint16 roomsCount; - Room *rooms; - - int32 floorsCount; - uint16 *floors; - - int32 meshDataSize; - uint16 *meshData; - - int32 meshOffsetsCount; - uint32 *meshOffsets; - - int32 animsCount; - Animation *anims; - - int32 statesCount; - AnimState *states; - - int32 rangesCount; - AnimRange *ranges; - - int32 commandsCount; - int16 *commands; - - int32 nodesDataSize; - uint32 *nodesData; - - int32 frameDataSize; - uint16 *frameData; - - int32 modelsCount; - Model *models; - - int32 staticMeshesCount; - StaticMesh *staticMeshes; - - int32 objectTexturesCount; - ObjectTexture *objectTextures; - - int32 spriteTexturesCount; - SpriteTexture *spriteTextures; - - int32 spriteSequencesCount; - SpriteSequence *spriteSequences; - - int32 camerasCount; - Camera *camera; - - int32 soundSourcesCount; - SoundSource *soundSources; - - int32 boxesCount; - Box *boxes; - int32 overlapsCount; - uint16 *overlaps; - Zone *zones; - - int32 animTexturesDataSize; - uint16 *animTexturesData; - - int32 entitiesCount; - Entity *entities; - - RGB *palette; - - uint16 cameraFramesCount; - CameraFrame *cameraFrames; - - uint16 demoDataSize; - uint8 *demoData; - - int16 *soundsMap; - - int32 soundsInfoCount; - SoundInfo *soundsInfo; - - int32 soundDataSize; - uint8 *soundData; - - int32 soundOffsetsCount; - uint32 *soundOffsets; - - Level(Stream &stream) { - // read version - stream.read(version); - // tiles - stream.read(tiles, stream.read(tilesCount)); - stream.read(unused); - // rooms - rooms = new Room[stream.read(roomsCount)]; - for (int i = 0; i < roomsCount; i++) { - Room &r = rooms[i]; - Room::Data &d = r.data; - // room info - stream.read(r.info); - // room data - stream.read(d.size); - int pos = stream.pos; - stream.read(d.vertices, stream.read(d.vCount)); - stream.read(d.rectangles, stream.read(d.rCount)); - stream.read(d.triangles, stream.read(d.tCount)); - stream.read(d.sprites, stream.read(d.sCount)); - stream.setPos(pos + d.size * 2); - // portals - stream.read(r.portals, stream.read(r.portalsCount)); - // sectors - stream.read(r.zSectors); - stream.read(r.xSectors); - stream.read(r.sectors, r.zSectors * r.xSectors); - // ambient light luminance - stream.read(r.ambient); - // lights - stream.read(r.lights, stream.read(r.lightsCount)); - // meshes - stream.read(r.meshes, stream.read(r.meshesCount)); - stream.read(r.alternateRoom); - stream.read(r.flags); - } - // floors - stream.read(floors, stream.read(floorsCount)); - // meshes - stream.read(meshData, stream.read(meshDataSize)); - stream.read(meshOffsets, stream.read(meshOffsetsCount)); - // animations - stream.read(anims, stream.read(animsCount)); - stream.read(states, stream.read(statesCount)); - stream.read(ranges, stream.read(rangesCount)); - stream.read(commands, stream.read(commandsCount)); - stream.read(nodesData, stream.read(nodesDataSize)); - stream.read(frameData, stream.read(frameDataSize)); - // models - stream.read(models, stream.read(modelsCount)); - stream.read(staticMeshes, stream.read(staticMeshesCount)); - // textures & UV - stream.read(objectTextures, stream.read(objectTexturesCount)); - stream.read(spriteTextures, stream.read(spriteTexturesCount)); - stream.read(spriteSequences, stream.read(spriteSequencesCount)); - - #ifdef TR1_DEMO - stream.read(palette, 256); - #endif - - // cameras - stream.read(camera, stream.read(camerasCount)); - // sound sources - stream.read(soundSources, stream.read(soundSourcesCount)); - // AI - stream.read(boxes, stream.read(boxesCount)); - stream.read(overlaps, stream.read(overlapsCount)); - stream.read(zones, boxesCount); - // animated textures - stream.read(animTexturesData, stream.read(animTexturesDataSize)); - // entities (enemies, items, lara etc.) - stream.read(entities, stream.read(entitiesCount)); - // palette - stream.seek(32 * 256); // skip lightmap palette - #ifndef TR1_DEMO - stream.read(palette, 256); - #endif - // cinematic frames for cameras - stream.read(cameraFrames, stream.read(cameraFramesCount)); - // demo data - stream.read(demoData, stream.read(demoDataSize)); - // sounds - stream.read(soundsMap, 256); - stream.read(soundsInfo, stream.read(soundsInfoCount)); - stream.read(soundData, stream.read(soundDataSize)); - stream.read(soundOffsets, stream.read(soundOffsetsCount)); - - // modify palette colors from 6-bit Amiga colorspace - int m = 0; - for (int i = 0; i < 256; i++) { - RGB &c = palette[i]; - c.r <<= 2; - c.g <<= 2; - c.b <<= 2; - } - } - - ~Level() { - delete[] tiles; - // rooms - for (int i = 0; i < roomsCount; i++) { - Room &r = rooms[i]; - delete[] r.data.vertices; - delete[] r.data.rectangles; - delete[] r.data.triangles; - delete[] r.data.sprites; - delete[] r.portals; - delete[] r.sectors; - delete[] r.lights; - delete[] r.meshes; - } - delete[] rooms; - delete[] floors; - delete[] meshData; - delete[] meshOffsets; - delete[] anims; - delete[] states; - delete[] ranges; - delete[] commands; - delete[] nodesData; - delete[] frameData; - delete[] models; - delete[] staticMeshes; - delete[] objectTextures; - delete[] spriteTextures; - delete[] spriteSequences; - delete[] camera; - delete[] soundSources; - delete[] boxes; - delete[] overlaps; - delete[] zones; - delete[] animTexturesData; - delete[] entities; - delete[] palette; - delete[] cameraFrames; - delete[] demoData; - delete[] soundsMap; - delete[] soundsInfo; - delete[] soundData; - delete[] soundOffsets; - } - }; - #pragma pack(pop) + #define DATA_PORTAL 0x01 + #define DATA_FLOOR 0x02 + #define DATA_CEILING 0x03 + + + #define ENTITY_FLAG_CLEAR 0x0080 + #define ENTITY_FLAG_VISIBLE 0x0100 + #define ENTITY_FLAG_MASK 0x3E00 + + #define ENTITY_LARA 0 + + #define ENTITY_ENEMY_TWIN 6 + #define ENTITY_ENEMY_WOLF 7 + #define ENTITY_ENEMY_BEAR 8 + #define ENTITY_ENEMY_BAT 9 + #define ENTITY_ENEMY_CROCODILE_LAND 10 + #define ENTITY_ENEMY_CROCODILE_WATER 11 + #define ENTITY_ENEMY_LION_MALE 12 + #define ENTITY_ENEMY_LION_FEMALE 13 + #define ENTITY_ENEMY_PUMA 14 + #define ENTITY_ENEMY_GORILLA 15 + #define ENTITY_ENEMY_RAT_LAND 16 + #define ENTITY_ENEMY_RAT_WATER 17 + #define ENTITY_ENEMY_REX 18 + #define ENTITY_ENEMY_RAPTOR 19 + #define ENTITY_ENEMY_MUTANT 20 + + #define ENTITY_ENEMY_CENTAUR 23 + #define ENTITY_ENEMY_MUMMY 24 + #define ENTITY_ENEMY_LARSON 27 + + #define ENTITY_CRYSTAL 83 + + #define ENTITY_MEDIKIT_SMALL 93 + #define ENTITY_MEDIKIT_BIG 94 + + #define ENTITY_VIEW_TARGET 169 + + #define ENTITY_TRAP_FLOOR 35 + #define ENTITY_TRAP_SPIKES 37 + #define ENTITY_TRAP_STONE 38 + #define ENTITY_TRAP_DART 40 + + #define ENTITY_SWITCH 55 + + #define ENTITY_GUN_SHOTGUN 85 + + #define ENTITY_AMMO_UZI 91 + #define ENTITY_AMMO_SHOTGUN 89 + #define ENTITY_AMMO_MAGNUM 90 + + + enum LaraState { + STATE_WALK, + STATE_RUN, + STATE_STOP, + STATE_FORWARD_JUMP, + STATE_FAST_TURN, + STATE_FAST_BACK, + STATE_TURN_RIGHT, + STATE_TURN_LEFT, + STATE_DEATH, + STATE_FAST_FALL, + STATE_HANG, + STATE_REACH, + STATE_SPLAT, + STATE_TREAD, + STATE_FAST_TURN_14, + STATE_COMPRESS, + STATE_BACK, + STATE_SWIM, + STATE_GLIDE, + STATE_NULL_19, + STATE_FAST_TURN_20, + STATE_STEP_RIGHT, + STATE_STEP_LEFT, + STATE_ROLL, + STATE_SLIDE, + STATE_BACK_JUMP, + STATE_RIGHT_JUMP, + STATE_LEFT_JUMP, + STATE_UP_JUMP, + STATE_FALL_BACK, + STATE_HANG_LEFT, + STATE_HANG_RIGHT, + STATE_SLIDE_BACK, + STATE_SURF_TREAD, + STATE_SURF_SWIM, + STATE_DIVE, + STATE_PUSH_BLOCK, + STATE_PULL_BLOCK, + STATE_PUSH_PULL_READY, + STATE_PICK_UP, + STATE_SWITCH_ON, + STATE_SWITCH_OFF, + STATE_USE_KEY, + STATE_USE_PUZZLE, + STATE_UNDERWATER_DEATH, + STATE_ROLL_45, + STATE_SPECIAL, + STATE_SURF_BACK, + STATE_SURF_LEFT, + STATE_SURF_RIGHT, + STATE_NULL_50, + STATE_NULL_51, + STATE_SWAN_DIVE, + STATE_FAST_DIVE, + STATE_HANDSTAND, + 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 }; + + #pragma pack(push, 1) + + struct fixed { + uint16 L; + int16 H; + float toFloat() { + return H + L / 65535.0f; + } + }; + + struct RGB { + uint8 r, g, b; + }; + + struct RGBA { + uint8 r, g, b, a; + }; + + struct Vertex { + int16 x, y, z; + }; + + struct Rectangle { + uint16 vertices[4]; + uint16 texture; // 15 bit - double-sided + }; + + struct Triangle { + uint16 vertices[3]; + uint16 texture; + }; + + struct Tile8 { + uint8 index[256 * 256]; + }; + + struct Room { + + struct Info { + int32 x, z; + int32 yBottom, yTop; + } info; + + struct Data { + uint32 size; // Number of data words (uint16_t's) + + int16 vCount; + int16 rCount; + int16 tCount; + int16 sCount; + + struct Vertex { + TR::Vertex vertex; + int16 lighting; // 0 (bright) .. 0x1FFF (dark) + } *vertices; + + Rectangle *rectangles; + Triangle *triangles; + + struct Sprite { + int16 vertex; + int16 texture; + } *sprites; + } data; + + uint16 portalsCount; + uint16 zSectors; + uint16 xSectors; + uint16 ambient; // 0 (bright) .. 0x1FFF (dark) + uint16 lightsCount; + uint16 meshesCount; + int16 alternateRoom; + int16 flags; + + struct Portal { + uint16 roomIndex; + Vertex normal; + Vertex vertices[4]; + } *portals; + + struct Sector { + uint16 floorIndex; // Index into FloorData[] + uint16 boxIndex; // Index into Boxes[] (-1 if none) + uint8 roomBelow; // 255 is none + int8 floor; // Absolute height of floor * 256 + uint8 roomAbove; // 255 if none + int8 ceiling; // Absolute height of ceiling * 256 + } *sectors; + + struct Light { + int32 x, y, z; + uint16 align; // ! not exists in file ! + uint16 intensity; + uint32 attenuation; + } *lights; + + struct Mesh { + int32 x, y, z; + uint16 rotation; + uint16 intensity; + uint16 meshID; + uint16 align; // ! not exists in file ! + } *meshes; + }; + + struct Mesh { + Vertex center; + int32 radius; + + int16 vCount; + Vertex *vertices; // List of vertices (relative coordinates) + + int16 nCount; + union { + Vertex *normals; + int16 *lights; // if nCount < 0 -> (abs(nCount)) + }; + + uint16 rCount; + Rectangle *rectangles; + + uint16 tCount; + Triangle *triangles; + + uint16 crCount; + Rectangle *crectangles; + + uint16 ctCount; + Triangle *ctriangles; + }; + + struct Entity { + int16 id; // Object Identifier (matched in Models[], or SpriteSequences[], as appropriate) + int16 room; // which room contains this item + int32 x, y, z; // world coords + int16 rotation; // ((0xc000 >> 14) * 90) degrees + int16 intensity; // (constant lighting; -1 means use mesh lighting) + uint16 flags; // 0x0100 indicates "initially invisible", 0x3e00 is Activation Mask + // 0x3e00 indicates "open" or "activated"; these can be XORed with + // related FloorData::FDlist fields (e.g. for switches) + uint16 align; // ! not exists in file ! + }; + + struct Animation { + uint32 frameOffset; // Byte offset into Frames[] (divide by 2 for Frames[i]) + uint8 frameRate; // Engine ticks per frame + uint8 frameSize; // Number of int16_t's in Frames[] used by this animation + + uint16 state; + + fixed speed; + fixed accel; + + uint16 frameStart; // First frame in this animation + uint16 frameEnd; // Last frame in this animation + uint16 nextAnimation; + uint16 nextFrame; + + uint16 scCount; + uint16 scOffset; // Offset into StateChanges[] + + uint16 acCount; // How many of them to use. + uint16 animCommand; // Offset into AnimCommand[] + }; + + struct AnimState { + uint16 state; + uint16 rangesCount; // number of ranges + uint16 rangesOffset; // Offset into animRanges[] + }; + + struct AnimRange { + int16 low; // Lowest frame that uses this range + int16 high; // Highest frame that uses this range + int16 nextAnimation; // Animation to dispatch to + int16 nextFrame; // Frame offset to dispatch to + }; + + struct AnimFrame { + int16 minX, minY, minZ; // Bounding box (low) + int16 maxX, maxY, maxZ; // Bounding box (high) + int16 x, y, z; // Starting offset for this model + int16 aCount; + uint16 angles[0]; // angle frames in YXZ order + }; + + struct AnimTexture { + int16 tCount; // Actually, this is the number of texture ID's - 1 + int16 textures[0]; // offsets into ObjectTextures[], in animation order + }; + + struct Node { + uint32 flags; + int32 x, y, z; + }; + + struct Model { + uint32 id; // Item Identifier (matched in Entities[]) + uint16 mCount; // number of meshes in this object + uint16 mStart; // stating mesh (offset into MeshPointers[]) + uint32 node; // offset into MeshTree[] + uint32 frame; // byte offset into Frames[] (divide by 2 for Frames[i]) + uint16 animation; // offset into Animations[] + uint16 align; // ! not exists in file ! + }; + + struct StaticMesh { + uint32 id; // Static Mesh Identifier + uint16 mesh; // Mesh (offset into MeshPointers[]) + Vertex vBox[2]; + Vertex cBox[2]; + uint16 flags; + }; + + struct ObjectTexture { + uint16 attribute; // 0 - opaque, 1 - transparent, 2 - blend additive + uint16 tileAndFlag; // 0..14 - tile, 15 - is triangle + struct { + uint8 Xcoordinate; // 1 if Xpixel is the low value, 255 if Xpixel is the high value in the object texture + uint8 Xpixel; + uint8 Ycoordinate; // 1 if Ypixel is the low value, 255 if Ypixel is the high value in the object texture + uint8 Ypixel; + } vertices[4]; // The four corners of the texture + }; + + struct SpriteTexture { + uint16 tile; + uint8 u, v; + uint16 w, h; // (ActualValue * 256) + 255 + int16 l, t, r, b; + }; + + struct SpriteSequence { + int32 id; // Sprite identifier + int16 sCount; // Negative of ``how many sprites are in this sequence'' + int16 sStart; // Where (in sprite texture list) this sequence starts + }; + + struct Camera { + int32 x, y, z; + int16 room; + uint16 flags; + }; + + struct CameraFrame { + int16 rotY; + int16 rotZ; + int16 unused1; + int16 posZ; + int16 posY; + int16 posX; + int16 unknown; + int16 rotX; + }; + + struct SoundSource { + int32 x, y, z; // absolute position of sound source (world coordinates) + uint16 id; // internal sample index + uint16 flags; // 0x40, 0x80, or 0xC0 + }; + + struct Box { + int32 minZ, maxZ; // Horizontal dimensions in global units + int32 minX, maxX; + int16 floor; // Height value in global units + int16 overlap; // Index into Overlaps[]. + }; + + struct Zone { + struct { + uint16 groundZone1; + uint16 groundZone2; + uint16 flyZone; + } normal, alternate; + }; + + struct SoundInfo { + uint16 index; // (index into soundsIndices) -- NOT USED IN TR4-5!!! + uint16 volume; + 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 + }; + #pragma pack(pop) + + struct Level { + char *data; + + uint32 version; // version (4 bytes) + + int32 tilesCount; + Tile8 *tiles; // 8-bit (palettized) textiles 256x256 + + uint32 unused; // 32-bit unused value (4 bytes) + + uint16 roomsCount; + Room *rooms; + + int32 floorsCount; + uint16 *floors; + + int32 meshDataSize; + uint16 *meshData; + + int32 meshOffsetsCount; + uint32 *meshOffsets; + + int32 animsCount; + Animation *anims; + + int32 statesCount; + AnimState *states; + + int32 rangesCount; + AnimRange *ranges; + + int32 commandsCount; + int16 *commands; + + int32 nodesDataSize; + uint32 *nodesData; + + int32 frameDataSize; + uint16 *frameData; + + int32 modelsCount; + Model *models; + + int32 staticMeshesCount; + StaticMesh *staticMeshes; + + int32 objectTexturesCount; + ObjectTexture *objectTextures; + + int32 spriteTexturesCount; + SpriteTexture *spriteTextures; + + int32 spriteSequencesCount; + SpriteSequence *spriteSequences; + + int32 camerasCount; + Camera *camera; + + int32 soundSourcesCount; + SoundSource *soundSources; + + int32 boxesCount; + Box *boxes; + int32 overlapsCount; + uint16 *overlaps; + Zone *zones; + + int32 animTexturesDataSize; + uint16 *animTexturesData; + + int32 entitiesCount; + Entity *entities; + + RGB *palette; + + uint16 cameraFramesCount; + CameraFrame *cameraFrames; + + uint16 demoDataSize; + uint8 *demoData; + + int16 *soundsMap; + + int32 soundsInfoCount; + SoundInfo *soundsInfo; + + int32 soundDataSize; + uint8 *soundData; + + int32 soundOffsetsCount; + uint32 *soundOffsets; + + Level(Stream &stream) { + // read version + stream.read(version); + // tiles + stream.read(tiles, stream.read(tilesCount)); + stream.read(unused); + // rooms + rooms = new Room[stream.read(roomsCount)]; + for (int i = 0; i < roomsCount; i++) { + Room &r = rooms[i]; + Room::Data &d = r.data; + // room info + stream.read(r.info); + // room data + stream.read(d.size); + int pos = stream.pos; + stream.read(d.vertices, stream.read(d.vCount)); + stream.read(d.rectangles, stream.read(d.rCount)); + stream.read(d.triangles, stream.read(d.tCount)); + stream.read(d.sprites, stream.read(d.sCount)); + stream.setPos(pos + d.size * 2); + // portals + stream.read(r.portals, stream.read(r.portalsCount)); + // sectors + stream.read(r.zSectors); + stream.read(r.xSectors); + stream.read(r.sectors, r.zSectors * r.xSectors); + // ambient light luminance + stream.read(r.ambient); + // lights + r.lights = new Room::Light[stream.read(r.lightsCount)]; + for (int i = 0; i < r.lightsCount; i++) { + TR::Room::Light &light = r.lights[i]; + stream.read(light.x); + stream.read(light.y); + stream.read(light.z); + stream.read(light.intensity); + stream.read(light.attenuation); + } + // stream.read(r.lights, stream.read(r.lightsCount)); + // meshes + r.meshes = new Room::Mesh[stream.read(r.meshesCount)]; + for (int i = 0; i < r.meshesCount; i++) + stream.raw(&r.meshes[i], sizeof(r.meshes[i]) - sizeof(r.meshes[i].align)); + // stream.read(r.meshes, stream.read(r.meshesCount)); + // misc flags + stream.read(r.alternateRoom); + stream.read(r.flags); + } + + // floors + stream.read(floors, stream.read(floorsCount)); + // meshes + stream.read(meshData, stream.read(meshDataSize)); + stream.read(meshOffsets, stream.read(meshOffsetsCount)); + // animations + stream.read(anims, stream.read(animsCount)); + stream.read(states, stream.read(statesCount)); + stream.read(ranges, stream.read(rangesCount)); + stream.read(commands, stream.read(commandsCount)); + stream.read(nodesData, stream.read(nodesDataSize)); + stream.read(frameData, stream.read(frameDataSize)); + // models + models = new Model[stream.read(modelsCount)]; + for (int i = 0; i < modelsCount; i++) + stream.raw(&models[i], sizeof(models[i]) - sizeof(models[i].align)); + // stream.read(models, stream.read(modelsCount)); + stream.read(staticMeshes, stream.read(staticMeshesCount)); + // textures & UV + stream.read(objectTextures, stream.read(objectTexturesCount)); + stream.read(spriteTextures, stream.read(spriteTexturesCount)); + stream.read(spriteSequences, stream.read(spriteSequencesCount)); + + #ifdef TR1_DEMO + stream.read(palette, 256); + #endif + + // cameras + stream.read(camera, stream.read(camerasCount)); + // sound sources + stream.read(soundSources, stream.read(soundSourcesCount)); + // AI + stream.read(boxes, stream.read(boxesCount)); + stream.read(overlaps, stream.read(overlapsCount)); + stream.read(zones, boxesCount); + // animated textures + stream.read(animTexturesData, stream.read(animTexturesDataSize)); + // entities (enemies, items, lara etc.) + entities = new Entity[stream.read(entitiesCount)]; + for (int i = 0; i < entitiesCount; i++) + stream.raw(&entities[i], sizeof(entities[i]) - sizeof(entities[i].align)); + // stream.read(entities, stream.read(entitiesCount)); + // palette + stream.seek(32 * 256); // skip lightmap palette + + #ifndef TR1_DEMO + stream.read(palette, 256); + #endif + + // cinematic frames for cameras + stream.read(cameraFrames, stream.read(cameraFramesCount)); + // demo data + stream.read(demoData, stream.read(demoDataSize)); + // sounds + stream.read(soundsMap, 256); + stream.read(soundsInfo, stream.read(soundsInfoCount)); + stream.read(soundData, stream.read(soundDataSize)); + stream.read(soundOffsets, stream.read(soundOffsetsCount)); + + // modify palette colors from 6-bit Amiga colorspace + int m = 0; + for (int i = 0; i < 256; i++) { + RGB &c = palette[i]; + c.r <<= 2; + c.g <<= 2; + c.b <<= 2; + } + } + + ~Level() { + delete[] tiles; + // rooms + for (int i = 0; i < roomsCount; i++) { + Room &r = rooms[i]; + delete[] r.data.vertices; + delete[] r.data.rectangles; + delete[] r.data.triangles; + delete[] r.data.sprites; + delete[] r.portals; + delete[] r.sectors; + delete[] r.lights; + delete[] r.meshes; + } + delete[] rooms; + delete[] floors; + delete[] meshData; + delete[] meshOffsets; + delete[] anims; + delete[] states; + delete[] ranges; + delete[] commands; + delete[] nodesData; + delete[] frameData; + delete[] models; + delete[] staticMeshes; + delete[] objectTextures; + delete[] spriteTextures; + delete[] spriteSequences; + delete[] camera; + delete[] soundSources; + delete[] boxes; + delete[] overlaps; + delete[] zones; + delete[] animTexturesData; + delete[] entities; + delete[] palette; + delete[] cameraFrames; + delete[] demoData; + delete[] soundsMap; + delete[] soundsInfo; + delete[] soundData; + delete[] soundOffsets; + } + }; } #endif \ No newline at end of file diff --git a/src/game.h b/src/game.h index 1b2d76f..b55f24a 100644 --- a/src/game.h +++ b/src/game.h @@ -8,30 +8,31 @@ #include "level.h" namespace Game { - Level *level; + Level *level; - void init() { + void init() { Core::init(); - level = new Level("data\\LEVEL2_DEMO.PHD"); - } + Stream stream("LEVEL2_DEMO.PHD"); + level = new Level(stream); + } - void free() { - delete level; + void free() { + delete level; - Core::free(); - } + Core::free(); + } - void update() { - level->update(); - } + void update() { + level->update(); + } - void render() { - Core::clear(vec4(0.0f)); - Core::setViewport(0, 0, Core::width, Core::height); - Core::setBlending(bmAlpha); + void render() { + Core::clear(vec4(0.0f)); + Core::setViewport(0, 0, Core::width, Core::height); + Core::setBlending(bmAlpha); - level->render(); - } + level->render(); + } } #endif \ No newline at end of file diff --git a/src/input.h b/src/input.h index 6f63898..46b1fea 100644 --- a/src/input.h +++ b/src/input.h @@ -3,83 +3,83 @@ #include "utils.h" -enum InputKey { ikNone, - // keyboard - ikLeft, ikRight, ikUp, ikDown, ikSpace, ikEnter, ikEscape, ikShift, ikCtrl, ikAlt, - ik0, ik1, ik2, ik3, ik4, ik5, ik6, ik7, ik8, ik9, - ikA, ikB, ikC, ikD, ikE, ikF, ikG, ikH, ikI, ikJ, ikK, ikL, ikM, - ikN, ikO, ikP, ikQ, ikR, ikS, ikT, ikU, ikV, ikW, ikX, ikY, ikZ, - // mouse - ikMouseL, ikMouseR, ikMouseM, - // touch - ikTouchA, ikTouchB, - // gamepad - ikJoyA, ikJoyB, ikJoyX, ikJoyY, ikJoyLB, ikJoyRB, ikJoyL, ikJoyR, ikJoySelect, ikJoyStart, ikJoyLT, ikJoyRT, ikJoyDP, - ikMAX }; +enum InputKey { ikNone, + // keyboard + ikLeft, ikRight, ikUp, ikDown, ikSpace, ikEnter, ikEscape, ikShift, ikCtrl, ikAlt, + ik0, ik1, ik2, ik3, ik4, ik5, ik6, ik7, ik8, ik9, + ikA, ikB, ikC, ikD, ikE, ikF, ikG, ikH, ikI, ikJ, ikK, ikL, ikM, + ikN, ikO, ikP, ikQ, ikR, ikS, ikT, ikU, ikV, ikW, ikX, ikY, ikZ, + // mouse + ikMouseL, ikMouseR, ikMouseM, + // touch + ikTouchA, ikTouchB, + // gamepad + ikJoyA, ikJoyB, ikJoyX, ikJoyY, ikJoyLB, ikJoyRB, ikJoyL, ikJoyR, ikJoySelect, ikJoyStart, ikJoyLT, ikJoyRT, ikJoyDP, + ikMAX }; namespace Input { - bool down[ikMAX]; + bool down[ikMAX]; - struct { - vec2 pos; - struct { - vec2 L, R, M; - } start; - } mouse; + struct { + vec2 pos; + struct { + vec2 L, R, M; + } start; + } mouse; - struct { - vec2 L, R; - float LT, RT, DP; - } joy; + struct { + vec2 L, R; + float LT, RT, DP; + } joy; - struct { - vec2 A, B; + struct { + vec2 A, B; - struct { - vec2 A, B; - } start; - } touch; + struct { + vec2 A, B; + } start; + } touch; - void reset() { - memset(down, 0, sizeof(down)); - memset(&mouse, 0, sizeof(mouse)); - memset(&joy, 0, sizeof(joy)); - memset(&touch, 0, sizeof(touch)); - } + void reset() { + memset(down, 0, sizeof(down)); + memset(&mouse, 0, sizeof(mouse)); + memset(&joy, 0, sizeof(joy)); + memset(&touch, 0, sizeof(touch)); + } - void setDown(InputKey key, bool value) { - if (down[key] == value) - return; - - if (value) - switch (key) { - case ikMouseL : mouse.start.L = mouse.pos; break; - case ikMouseR : mouse.start.R = mouse.pos; break; - case ikMouseM : mouse.start.M = mouse.pos; break; - case ikTouchA : touch.start.A = touch.A; break; - case ikTouchB : touch.start.B = touch.B; break; - default : ; - } + void setDown(InputKey key, bool value) { + if (down[key] == value) + return; - down[key] = value; - } + if (value) + switch (key) { + case ikMouseL : mouse.start.L = mouse.pos; break; + case ikMouseR : mouse.start.R = mouse.pos; break; + case ikMouseM : mouse.start.M = mouse.pos; break; + case ikTouchA : touch.start.A = touch.A; break; + case ikTouchB : touch.start.B = touch.B; break; + default : ; + } - void setPos(InputKey key, const vec2 &pos) { - switch (key) { - case ikMouseL : - case ikMouseR : - case ikMouseM : mouse.pos = pos; break; - case ikJoyL : joy.L = pos; break; - case ikJoyR : joy.R = pos; break; - case ikJoyLT : joy.LT = pos.x; break; - case ikJoyRT : joy.RT = pos.x; break; - case ikJoyDP : joy.DP = pos.x; break; - case ikTouchA : touch.A = pos; break; - case ikTouchB : touch.B = pos; break; - default : ; - } - } + down[key] = value; + } + + void setPos(InputKey key, const vec2 &pos) { + switch (key) { + case ikMouseL : + case ikMouseR : + case ikMouseM : mouse.pos = pos; break; + case ikJoyL : joy.L = pos; break; + case ikJoyR : joy.R = pos; break; + case ikJoyLT : joy.LT = pos.x; break; + case ikJoyRT : joy.RT = pos.x; break; + case ikJoyDP : joy.DP = pos.x; break; + case ikTouchA : touch.A = pos; break; + case ikTouchB : touch.B = pos; break; + default : ; + } + } } #endif \ No newline at end of file diff --git a/src/level.h b/src/level.h index 5f8b816..93bd66f 100644 --- a/src/level.h +++ b/src/level.h @@ -8,1024 +8,975 @@ #include "camera.h" #ifdef _DEBUG - #include "debug.h" + #include "debug.h" #endif -const char SHADER[] = - #include "shader.glsl" +const char SHADER[] = + #include "shader.glsl" ; struct Level { - TR::Level level; - Shader *shader; - Texture *atlas; - Mesh *mesh; - - Controller *lara; - - float time; - - MeshRange *rangeRooms; - - Camera camera; - - - int mCount; - struct MeshInfo : MeshRange { - int offset; - TR::Vertex center; - int32 radius; - } *meshInfo; - - Level(const char *name) : level(Stream(name)), time(0.0f) { - shader = new Shader(SHADER); - initAtlas(); - initMesh(); - - int entity = 0; - for (int i = 0; i < level.entitiesCount; i++) - if (level.entities[i].id == ENTITY_LARA) { - entity = i; - break; - } - - lara = new Controller(&level, entity); - - camera.fov = 75.0f; - camera.znear = 0.1f * 2048.0f; - camera.zfar = 1000.0f * 2048.0f; - camera.offset = vec3(0, 0, 768); - camera.pos = vec3(0.0f); - camera.angle = vec3(0, PI, 0); - } - - ~Level() { - delete shader; - delete atlas; - delete mesh; - delete[] rangeRooms; - delete[] meshInfo; - - delete lara; - } - - void initAtlas() { - if (!level.tilesCount) { - atlas = NULL; - return; - } - - TR::RGBA *data = new TR::RGBA[1024 * 1024]; - for (int i = 0; i < level.tilesCount; i++) { - int tx = (i % 4) * 256; - int ty = (i / 4) * 256; - - TR::RGBA *ptr = &data[ty * 1024 + tx]; - for (int y = 0; y < 256; y++) { - for (int x = 0; x < 256; x++) { - int index = level.tiles[i].index[y * 256 + x]; - auto p = level.palette[index]; - ptr[x].r = p.r; - ptr[x].g = p.g; - ptr[x].b = p.b; - ptr[x].a = index == 0 ? 0 : 255; - } - ptr += 1024; - } - } - - for (int y = 1020; y < 1024; y++) - for (int x = 1020; x < 1024; x++) { - int i = y * 1024 + x; - data[i].r = data[i].g = data[i].b = data[i].a = 255; // white texel for colored triangles - } - - atlas = new Texture(1024, 1024, 0, data); - delete[] data; - } - - void initMesh() { - // TODO: sort by texture attribute (t.attribute == 2 ? bmAdd : bmAlpha) - - rangeRooms = new MeshRange[level.roomsCount]; - - int iCount = 0, vCount = 0; - - // get rooms mesh info - for (int i = 0; i < level.roomsCount; i++) { - rangeRooms[i].vStart = vCount; - rangeRooms[i].iStart = iCount; - TR::Room::Data &d = level.rooms[i].data; - iCount += d.rCount * 6 + d.tCount * 3; - vCount += d.rCount * 4 + d.tCount * 3; - rangeRooms[i].iCount = iCount - rangeRooms[i].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) & ~3); - } - meshInfo = new MeshInfo[mCount]; - - Index *indices = new Index[iCount]; - Vertex *vertices = new Vertex[vCount]; - iCount = vCount = 0; - - // rooms geometry - for (int i = 0; i < level.roomsCount; i++) { - TR::Room::Data &d = level.rooms[i].data; - - 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, 0x7FFF }; - vertices[vCount].texCoord = { (int16)((tx + (int)t.vertices[k].Xpixel) << 5) + 16, (int16)((ty + (int)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, 0x7FFF }; - vertices[vCount].texCoord = { (int16)((tx + (int)t.vertices[k].Xpixel) << 5) + 16, (int16)((ty + (int)t.vertices[k].Ypixel) << 5) + 16}; - vCount++; - } - } - } - - // 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, 255 }; - vertices[vCount].color = { a, a, a, 255 }; - } - vertices[vCount].texCoord = { (int16)((tx + (int)t.vertices[k].Xpixel) << 5) + 16, (int16)((ty + (int)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, 255 }; - vertices[vCount].color = { a, a, a, 255 }; - } - vertices[vCount].texCoord = { ((tx + t.vertices[k].Xpixel) << 5) + 16, ((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, 255 }; - 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, 255 }; - 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) & ~3); - - info.iCount = iCount - info.iStart; - } - - mesh = new Mesh(indices, iCount, vertices, vCount); - delete[] indices; - delete[] vertices; - } - - TR::StaticMesh* getMeshByID(int id) { - for (int i = 0; i < level.staticMeshesCount; i++) - if (level.staticMeshes[i].id == id) - return &level.staticMeshes[i]; - return NULL; - } - - //#define SCALE (1.0f / 1024.0f / 2.0f) - - void renderRoom(int index) { - TR::Room &room = level.rooms[index]; - - mat4 m = Core::mModel; - Core::mModel.translate(vec3(room.info.x, 0.0f, room.info.z)); - Core::color = vec4(1.0f); - Core::ambient = vec3(1.0f); - Core::lightColor = vec4(0.0f, 0.0f, 0.0f, 1.0f); - - shader->setParam(uModel, Core::mModel); - shader->setParam(uColor, Core::color); - shader->setParam(uAmbient, Core::ambient); - shader->setParam(uLightColor, Core::lightColor); - - mesh->render(rangeRooms[index]); - Core::mModel = m; - - - // meshes - for (int j = 0; j < room.meshesCount; j++) { - auto rMesh = room.meshes[j]; - auto sMesh = getMeshByID(rMesh.meshID); - ASSERT(sMesh != NULL); - - mat4 m = Core::mModel; - Core::mModel.translate(vec3(rMesh.x, rMesh.y, rMesh.z)); -// Core::mModel.rotateY((rMesh.rotation >> 14) * 90.0f * DEG2RAD); - Core::mModel.rotateY(rMesh.rotation / 16384.0f * PI * 0.5f); - - getLight(vec3(rMesh.x, rMesh.y, rMesh.z), index); - - renderMesh(sMesh->mesh); - - Core::mModel = m; - } - /* - // sprites - Core::setBlending(bmAlpha); - for (int j = 0; j < room.data.sCount; j++) - renderSprite(room, room.data.sprites[j]); - */ - } - - - void renderMesh(uint32 meshOffset) { - if (!level.meshOffsets[meshOffset] && meshOffset) - return; - - for (int i = 0; i < mCount; i++) - if (meshInfo[i].offset == level.meshOffsets[meshOffset]) { - shader->setParam(uModel, Core::mModel); - mesh->render(meshInfo[i]); - break; - } - } - - void renderSprite(const TR::SpriteTexture &sprite) { - float u0 = sprite.u / 256.0f; - float v0 = sprite.v / 255.0f; - float u1 = u0 + sprite.w / (256.0f * 256.0f); - float v1 = v0 + sprite.h / (256.0f * 256.0f); - - mat4 m = Core::mView.inverse(); - vec3 up = m.up.xyz * vec3(-1, -1, 1) * (-1); - vec3 right = m.right.xyz * vec3(-1, -1, 1); - - vec3 p[4]; - p[0] = right * sprite.r + up * sprite.b; - p[1] = right * sprite.l + up * sprite.b; - p[2] = right * sprite.l + up * sprite.t; - p[3] = right * sprite.r + up * sprite.t; - -// bindTexture(sprite.tile); - /* - glBegin(GL_QUADS); - glTexCoord2f(u0, v1); - glVertex3fv((GLfloat*)&p[0]); - glTexCoord2f(u1, v1); - glVertex3fv((GLfloat*)&p[1]); - glTexCoord2f(u1, v0); - glVertex3fv((GLfloat*)&p[2]); - glTexCoord2f(u0, v0); - glVertex3fv((GLfloat*)&p[3]); - glEnd(); - */ - } - - void renderSprite(const TR::Room &room, const TR::Room::Data::Sprite &sprite) { - auto &v = room.data.vertices[sprite.vertex]; - float a = 1.0f - v.lighting / (float)0x1FFF; - /* - glColor3f(a, a, a); - - glPushMatrix(); - glTranslatef(v.vertex.x + room.info.x, v.vertex.y, v.vertex.z + room.info.z); - - renderSprite(level.spriteTextures[sprite.texture]); - - glPopMatrix(); - */ - } - - vec3 getAngle(TR::AnimFrame *frame, int index) { - #define ANGLE_SCALE (2.0f * PI / 1024.0f) - - uint16 b = frame->angles[index * 2 + 0]; - uint16 a = frame->angles[index * 2 + 1]; - - return vec3((a & 0x3FF0) >> 4, ( ((a & 0x000F) << 6) | ((b & 0xFC00) >> 10)), b & 0x03FF) * ANGLE_SCALE; - } - - float lerpAngle(float a, float b, float t) { - float d = b - a; - if (d >= PI) - a += PI * 2.0f; - else - if (d <= -PI) - a -= PI * 2.0f; - return a + (b - a) * t; - } - - quat lerpAngle(const vec3 &a, const vec3 &b, float t) { - // return vec3(lerpAngle(a.x, b.x, t), - // lerpAngle(a.y, b.y, t), - // lerpAngle(a.z, b.z, t)); - - mat4 ma, mb; - ma.identity(); - mb.identity(); - - ma.rotateY(a.y); - ma.rotateX(a.x); - ma.rotateZ(a.z); - - mb.rotateY(b.y); - mb.rotateX(b.x); - mb.rotateZ(b.z); - - return ma.getRot().slerp(mb.getRot(), t).normal(); - } - - void renderModel(const TR::Model &model) { - TR::Animation *anim = &level.anims[model.animation]; - - float fTime = time; - - if (model.id == ENTITY_LARA) { - anim = lara->anim; - fTime = lara->fTime; - } - - float k = fTime * 30.0f / anim->frameRate; - int fIndex = (int)k; - int fCount = (anim->frameEnd - anim->frameStart) / anim->frameRate + 1; - - int fSize = sizeof(TR::AnimFrame) + model.mCount * sizeof(uint16) * 2; - k = k - fIndex; - - - int fIndexA = fIndex % fCount, fIndexB = (fIndex + 1) % fCount; - TR::AnimFrame *frameA = (TR::AnimFrame*)&level.frameData[(anim->frameOffset + fIndexA * fSize) >> 1]; - - TR::Animation *nextAnim = NULL; - - if (fIndexB == 0) { - nextAnim = &level.anims[anim->nextAnimation]; - fIndexB = (anim->nextFrame - nextAnim->frameStart) / anim->frameRate; - } else - nextAnim = anim; - -// LOG("%d %f\n", fIndexA, fTime); - - - TR::AnimFrame *frameB = (TR::AnimFrame*)&level.frameData[(nextAnim->frameOffset + fIndexB * fSize) >> 1]; - - - -// ASSERT(fpSize == fSize); -// fSize = fpSize; - - // LOG("%d\n", fIndex % fCount); - //if (fCount > 1) LOG("%d %d\n", model->id, fCount); - // LOG("%d\n", fIndex % fCount); - - -// Debug::Draw::box(Box(vec3(frameA->minX, frameA->minY, frameA->minZ), vec3(frameA->maxX, frameA->maxY, frameA->maxZ))); - - TR::Node *node = (int)model.node < level.nodesDataSize ? (TR::Node*)&level.nodesData[model.node] : NULL; - - int sIndex = 0; - mat4 stack[20]; - - mat4 m; - m.identity(); - m.translate(vec3(frameA->x, frameA->y, frameA->z).lerp(vec3(frameB->x, frameB->y, frameB->z), k)); - - for (int i = 0; i < model.mCount; i++) { - - if (i > 0 && node) { - TR::Node &t = node[i - 1]; - - if (t.flags & 0x01) m = stack[--sIndex]; - if (t.flags & 0x02) stack[sIndex++] = m; - - ASSERT(sIndex >= 0); - ASSERT(sIndex < 20); - - m.translate(vec3(t.x, t.y, t.z)); - } - - quat q = lerpAngle(getAngle(frameA, i), getAngle(frameB, i), k); - m = m * mat4(q, vec3(0.0f)); - - - // vec3 angle = lerpAngle(getAngle(frameA, i), getAngle(frameB, i), k); - // m.rotateY(angle.y); - // m.rotateX(angle.x); - // m.rotateZ(angle.z); - - mat4 tmp = Core::mModel; - Core::mModel = Core::mModel * m; - renderMesh(model.mStart + i); - Core::mModel = tmp; - } - } - - int getLightIndex(const vec3 &pos, int &room) { - int idx = -1; - float dist; - for (int j = 0; j < level.roomsCount; j++) - for (int i = 0; i < level.rooms[j].lightsCount; i++) { - TR::Room::Light &light = level.rooms[j].lights[i]; - float d = (pos - vec3(light.x, light.y, light.z)).length(); - if (idx == -1 || d < dist) { - idx = i; - dist = d; - room = j; - } - } - return idx; - } - - void getLight(const vec3 &pos, int roomIndex) { - int room; - int idx = getLightIndex(pos, room); - if (idx > -1) { - TR::Room::Light &light = level.rooms[room].lights[idx]; - float c = level.rooms[room].lights[idx].Intensity / 8191.0f; - Core::lightPos = vec3(light.x, light.y, light.z); - Core::lightColor = vec4(c, c, c, light.fade * light.fade); - } else { - Core::lightPos = vec3(0.0f); - Core::lightColor = vec4(0.0f); - } - Core::ambient = vec3(1.0f - level.rooms[roomIndex].ambient / 8191.0f); - shader->setParam(uAmbient, Core::ambient); - shader->setParam(uLightPos, Core::lightPos); - shader->setParam(uLightColor, Core::lightColor); - } - - void renderEntity(const TR::Entity &entity) { - // if (!(entity.flags & ENTITY_FLAG_VISIBLE)) - // return; - - mat4 m = Core::mModel; - Core::mModel.translate(vec3(entity.x, entity.y, entity.z)); - - float c = (entity.intensity > -1) ? (1.0f - entity.intensity / (float)0x1FFF) : 1.0f; - float l = 1.0f; - - Core::color = vec4(c, c, c, 1.0); - shader->setParam(uColor, Core::color); - - getLight(vec3(entity.x, entity.y, entity.z), entity.room); - - for (int i = 0; i < level.modelsCount; i++) - if (entity.id == level.models[i].id) { - Core::mModel.rotateY(entity.rotation / 16384.0f * PI * 0.5f); - renderModel(level.models[i]); - break; - } - /* - for (int i = 0; i < level.spriteSequencesCount; i++) - if (entity.id == level.spriteSequences[i].id) { - renderSprite(level.spriteTextures[level.spriteSequences[i].sStart]); - break; - } - */ - Core::mModel = m; - } - - #ifdef _DEBUG - void debugPortals() { - Core::setBlending(bmAdd); - glColor3f(0, 0.25f, 0.25f); - glDepthMask(GL_FALSE); - - glBegin(GL_QUADS); - for (int i = 0; i < level.roomsCount; i++) { - TR::Room &r = level.rooms[i]; - for (int j = 0; j < r.portalsCount; j++) { - TR::Room::Portal &p = r.portals[j]; - for (int k = 0; k < 4; k++) { - TR::Vertex &v = p.vertices[k]; - glVertex3f(v.x + r.info.x, v.y, v.z + r.info.z); - } - } - } - glEnd(); - - glDepthMask(GL_TRUE); - Core::setBlending(bmAlpha); - } - - void debugFloor(const vec3 &f, const vec3 &c, int floorIndex, bool current) { - 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) }; - - uint16 cmd, *d = &level.floors[floorIndex]; - - if (floorIndex) - do { - cmd = *d++; - int func = cmd & 0x00FF; // function - int sub = (cmd & 0x7F00) >> 8; // sub function - - if (func == 0x01) { // portal - d++; - // d += 2; - - } - - if ((func == 0x02 || func == 0x03) && sub == 0x00) { // floor & ceiling corners - int sx = 256 * int((int8)(*d & 0x00FF)); - int sz = 256 * int((int8)((*d & 0xFF00) >> 8)); - - auto &p = func == 0x02 ? vf : vc; - - if (func == 0x02) { - - // if (current) - // LOG("%d\n", sx); - - if (sx > 0) { - p[0].y += sx; - p[3].y += sx; - } else { - p[1].y -= sx; - p[2].y -= sx; - } - - if (sz > 0) { - p[0].y += sz; - p[1].y += sz; - } else { - p[3].y -= sz; - p[2].y -= sz; - } - - } else { - - if (sx < 0) { - p[0].y += sx; - p[3].y += sx; - } else { - p[1].y -= sx; - p[2].y -= sx; - } - - if (sz > 0) { - p[0].y -= sz; - p[1].y -= sz; - } else { - p[3].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; - } - - } while (!(cmd & 0x8000)); - - if (current) - glColor3f(1, 1, 1); - else - glColor3f(0, 1, 0); - - glBegin(GL_LINE_STRIP); - for (int i = 0; i < 5; i++) - glVertex3fv((GLfloat*)&vf[i % 4]); - glEnd(); - - glColor3f(1, 0, 0); - glBegin(GL_LINE_STRIP); - for (int i = 0; i < 5; i++) - glVertex3fv((GLfloat*)&vc[i % 4]); - glEnd(); - } - - void debugSectors(int index) { - TR::Room &room = level.rooms[index]; - - vec3 p = (lara->pos - vec3(room.info.x, 0, room.info.z)) / vec3(1024, 1, 1024); - - for (int z = 0; z < room.zSectors; z++) - for (int x = 0; x < room.xSectors; x++) { - auto &s = room.sectors[x * room.zSectors + z]; - vec3 f(x * 1024 + room.info.x, s.floor * 256, z * 1024 + room.info.z); - vec3 c(x * 1024 + room.info.x, s.ceiling * 256, z * 1024 + room.info.z); - - debugFloor(f, c, s.floorIndex, (int)p.x == x && (int)p.z == z); - } - } - - void debugRooms() { - Core::setBlending(bmAdd); - glDepthMask(GL_FALSE); - - for (int i = 0; i < level.roomsCount; i++) { - TR::Room &r = level.rooms[i]; - vec3 p = vec3(r.info.x, r.info.yTop, r.info.z); - - if (i == level.entities[lara->entity].room) { - //if (lara->insideRoom(Core::viewPos, i)) { - debugSectors(i); - glColor3f(0, 1, 0); - } else - glColor3f(1, 1, 1); - - Debug::Draw::box(p, p + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024)); - } - - glDepthMask(GL_TRUE); - Core::setBlending(bmAlpha); - } - - void debugMeshes() { - mat4 m = Core::mModel; - for (int i = 0; i < level.meshOffsetsCount; i++) { - renderMesh(i); - Core::mModel.translate(vec3(-128, 0, 0)); - } - Core::mModel = m; - } - - void debugLights() { - int roomIndex = level.entities[lara->entity].room; - int lightIndex = getLightIndex(lara->pos, roomIndex); - - glPointSize(8); - glBegin(GL_POINTS); - for (int i = 0; i < level.roomsCount; i++) - for (int j = 0; j < level.rooms[i].lightsCount; j++) { - TR::Room::Light &l = level.rooms[i].lights[j]; - float a = l.Intensity / 8191.0f; - vec3 p = vec3(l.x, l.y, l.z); - vec4 color = vec4(a, a, a, 1); - Debug::Draw::point(p, color); - if (i == roomIndex && j == lightIndex) - color = vec4(0, 1, 0, 1); - Debug::Draw::sphere(p, l.fade, color); - } - glEnd(); - } - #endif - /* - void debugEntity() { - Core::setCulling(cfNone); - Core::active.shader = NULL; - glUseProgram(0); - - mat4 mProj; - glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat*)&mProj); - - glPushMatrix(); - glScalef(-SCALE, -SCALE, SCALE); - - for (int i = 0; i < entities.count; i++) { - tr_entity *entity = &entities[i]; - - glPushMatrix(); - glTranslatef(entity->x, entity->y, entity->z); - - for (int i = 0; i < models.count; i++) - if (entity->id == models[i].id) { - glRotatef((entity->rotation >> 14) * 90.0f, 0, 1, 0); - tr_anim_frame *frame = (tr_anim_frame*)&frames[models[i].frame >> 1]; - glTranslatef(frame->x, frame->y, frame->z); - break; - } - - mat4 mView, mViewProj; - glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&mView); - mViewProj = mProj * mView; - vec4 p = mViewProj * vec4(0, 0, 0, 1); - if (p.w > 0) { - p.xyz /= p.w; - p.y = -p.y; - - p.xy = (p.xy * 0.5f + 0.5f) * vec2(Core::width, Core::height); - char buf[16]; - sprintf(buf, "%d", entity->id); - - UI::begin(); - font->print(p.xy, vec4(1, 0, 0, 1), buf); - UI::end(); - } - - glPopMatrix(); - } - glPopMatrix(); - - Core::setCulling(cfFront); - Core::active.shader = NULL; - glUseProgram(0); - } - - bool isInsideRoom(const vec3 pos, tr_room *room) { - vec3 min = vec3(room->info.x, room->info.yTop, room->info.z); - Box box(min, min + vec3(room->xSectors * 1024, room->info.yBottom - room->info.yTop, room->zSectors * 1024)); - return box.intersect(vec3(-pos.x, -pos.y, pos.z) / SCALE); - } - */ - float tickTextureAnimation = 0.0f; - - void update() { - time += Core::deltaTime; - lara->update(); - camera.update(); - - if (tickTextureAnimation > 0.25f) { - tickTextureAnimation = 0.0f; - - if (level.animTexturesDataSize) { - uint16 *ptr = &level.animTexturesData[0]; - int count = *ptr++; - for (int i = 0; i < count; i++) { - auto animTex = (TR::AnimTexture*)ptr; - auto id = level.objectTextures[animTex->textures[0]]; - for (int j = 0; j < animTex->tCount; j++) // tCount = count of textures in animation group - 1 (!!!) - level.objectTextures[animTex->textures[j]] = level.objectTextures[animTex->textures[j + 1]]; - level.objectTextures[animTex->textures[animTex->tCount]] = id; - ptr += (sizeof(TR::AnimTexture) + sizeof(animTex->textures[0]) * (animTex->tCount + 1)) / sizeof(uint16); - } - } - } else - tickTextureAnimation += Core::deltaTime; - } - - void render() { - #ifndef FREE_CAMERA - camera.pos = vec3(-lara->pos.x, -lara->pos.y + 768, lara->pos.z); - #endif - camera.setup();; - - shader->bind(); - atlas->bind(0); - mesh->bind(); - - shader->setParam(uViewProj, Core::mViewProj); - shader->setParam(uModel, Core::mModel); - - Core::setCulling(cfFront); - glEnable(GL_DEPTH_TEST); - - Core::mModel.identity(); - - for (int i = 0; i < level.roomsCount; i++) - renderRoom(i); - - for (int i = 0; i < level.entitiesCount; i++) - renderEntity(level.entities[i]); - - #ifdef _DEBUG - // debugMeshes(); - - Debug::Draw::begin(); - debugRooms(); - // debugLights(); - debugPortals(); - // debugEntity(); - Debug::Draw::end(); - #endif - } + TR::Level level; + Shader *shader; + Texture *atlas; + Mesh *mesh; + + Controller *lara; + + float time; + + MeshRange *rangeRooms; + + Camera camera; + + + int mCount; + struct MeshInfo : MeshRange { + int offset; + TR::Vertex center; + int32 radius; + } *meshInfo; + + Level(Stream &stream) : level{stream}, time(0.0f) { + shader = new Shader(SHADER); + + initAtlas(); + initMesh(); + + int entity = 0; + for (int i = 0; i < level.entitiesCount; i++) + if (level.entities[i].id == ENTITY_LARA) { + entity = i; + break; + } + + lara = new Controller(&level, entity); + + camera.fov = 75.0f; + camera.znear = 0.1f * 2048.0f; + camera.zfar = 1000.0f * 2048.0f; + camera.offset = vec3(0, 0, 768); + camera.pos = vec3(0.0f); + camera.angle = vec3(0, PI, 0); + } + + ~Level() { + delete shader; + delete atlas; + delete mesh; + delete[] rangeRooms; + delete[] meshInfo; + + delete lara; + } + + void initAtlas() { + if (!level.tilesCount) { + atlas = NULL; + return; + } + + TR::RGBA *data = new TR::RGBA[1024 * 1024]; + for (int i = 0; i < level.tilesCount; i++) { + int tx = (i % 4) * 256; + int ty = (i / 4) * 256; + + TR::RGBA *ptr = &data[ty * 1024 + tx]; + for (int y = 0; y < 256; y++) { + for (int x = 0; x < 256; x++) { + int index = level.tiles[i].index[y * 256 + x]; + auto p = level.palette[index]; + ptr[x].r = p.r; + ptr[x].g = p.g; + ptr[x].b = p.b; + ptr[x].a = index == 0 ? 0 : 255; + } + ptr += 1024; + } + } + + for (int y = 1020; y < 1024; y++) + for (int x = 1020; x < 1024; x++) { + int i = y * 1024 + x; + data[i].r = data[i].g = data[i].b = data[i].a = 255; // white texel for colored triangles + } + + atlas = new Texture(1024, 1024, 0, data); + delete[] data; + } + + void initMesh() { + // TODO: sort by texture attribute (t.attribute == 2 ? bmAdd : bmAlpha) + + rangeRooms = new MeshRange[level.roomsCount]; + + int iCount = 0, vCount = 0; + + // get rooms mesh info + for (int i = 0; i < level.roomsCount; i++) { + rangeRooms[i].vStart = vCount; + rangeRooms[i].iStart = iCount; + TR::Room::Data &d = level.rooms[i].data; + iCount += d.rCount * 6 + d.tCount * 3; + vCount += d.rCount * 4 + d.tCount * 3; + rangeRooms[i].iCount = iCount - rangeRooms[i].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]; + + Index *indices = new Index[iCount]; + Vertex *vertices = new Vertex[vCount]; + iCount = vCount = 0; + + // rooms geometry + for (int i = 0; i < level.roomsCount; i++) { + TR::Room::Data &d = level.rooms[i].data; + + 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, 0x7FFF }; + 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, 0x7FFF }; + vertices[vCount].texCoord.x = ((tx + t.vertices[k].Xpixel) << 5) + 16; + vertices[vCount].texCoord.y = ((ty + t.vertices[k].Ypixel) << 5) + 16; + vCount++; + } + } + } + + // 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, 255 }; + 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, 255 }; + 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, 255 }; + 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, 255 }; + 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; + } + + mesh = new Mesh(indices, iCount, vertices, vCount); + delete[] indices; + delete[] vertices; + } + + TR::StaticMesh* getMeshByID(int id) { + for (int i = 0; i < level.staticMeshesCount; i++) + if (level.staticMeshes[i].id == id) + return &level.staticMeshes[i]; + return NULL; + } + + //#define SCALE (1.0f / 1024.0f / 2.0f) + + void renderRoom(int index) { + TR::Room &room = level.rooms[index]; + + mat4 m = Core::mModel; + Core::mModel.translate(vec3(room.info.x, 0.0f, room.info.z)); + Core::color = vec4(1.0f); + Core::ambient = vec3(1.0f); + Core::lightColor = vec4(0.0f, 0.0f, 0.0f, 1.0f); + + shader->setParam(uModel, Core::mModel); + shader->setParam(uColor, Core::color); + shader->setParam(uAmbient, Core::ambient); + shader->setParam(uLightColor, Core::lightColor); + + mesh->render(rangeRooms[index]); + Core::mModel = m; + + // meshes + for (int j = 0; j < room.meshesCount; j++) { + TR::Room::Mesh &rMesh = room.meshes[j]; + TR::StaticMesh *sMesh = getMeshByID(rMesh.meshID); + ASSERT(sMesh != NULL); + + mat4 m = Core::mModel; + Core::mModel.translate(vec3(rMesh.x, rMesh.y, rMesh.z)); + Core::mModel.rotateY(rMesh.rotation / 16384.0f * PI * 0.5f); + + getLight(vec3(rMesh.x, rMesh.y, rMesh.z), index); + + renderMesh(sMesh->mesh); + + Core::mModel = m; + } + + /* + // sprites + Core::setBlending(bmAlpha); + for (int j = 0; j < room.data.sCount; j++) + renderSprite(room, room.data.sprites[j]); + */ + } + + + void renderMesh(uint32 meshOffset) { + if (!level.meshOffsets[meshOffset] && meshOffset) + return; + + for (int i = 0; i < mCount; i++) + if (meshInfo[i].offset == level.meshOffsets[meshOffset]) { + shader->setParam(uModel, Core::mModel); + mesh->render(meshInfo[i]); + break; + } + } + + void renderSprite(const TR::SpriteTexture &sprite) { + float u0 = sprite.u / 256.0f; + float v0 = sprite.v / 255.0f; + float u1 = u0 + sprite.w / (256.0f * 256.0f); + float v1 = v0 + sprite.h / (256.0f * 256.0f); + + mat4 m = Core::mView.inverse(); + vec3 up = m.up.xyz * vec3(-1, -1, 1) * (-1); + vec3 right = m.right.xyz * vec3(-1, -1, 1); + + vec3 p[4]; + p[0] = right * sprite.r + up * sprite.b; + p[1] = right * sprite.l + up * sprite.b; + p[2] = right * sprite.l + up * sprite.t; + p[3] = right * sprite.r + up * sprite.t; + +// bindTexture(sprite.tile); + /* + glBegin(GL_QUADS); + glTexCoord2f(u0, v1); + glVertex3fv((GLfloat*)&p[0]); + glTexCoord2f(u1, v1); + glVertex3fv((GLfloat*)&p[1]); + glTexCoord2f(u1, v0); + glVertex3fv((GLfloat*)&p[2]); + glTexCoord2f(u0, v0); + glVertex3fv((GLfloat*)&p[3]); + glEnd(); + */ + } + + void renderSprite(const TR::Room &room, const TR::Room::Data::Sprite &sprite) { + auto &v = room.data.vertices[sprite.vertex]; + float a = 1.0f - v.lighting / (float)0x1FFF; + /* + glColor3f(a, a, a); + glPushMatrix(); + glTranslatef(v.vertex.x + room.info.x, v.vertex.y, v.vertex.z + room.info.z); + + renderSprite(level.spriteTextures[sprite.texture]); + + glPopMatrix(); + */ + } + + vec3 getAngle(TR::AnimFrame *frame, int index) { + #define ANGLE_SCALE (2.0f * PI / 1024.0f) + + uint16 b = frame->angles[index * 2 + 0]; + uint16 a = frame->angles[index * 2 + 1]; + + return vec3((a & 0x3FF0) >> 4, ( ((a & 0x000F) << 6) | ((b & 0xFC00) >> 10)), b & 0x03FF) * ANGLE_SCALE; + } + + float lerpAngle(float a, float b, float t) { + float d = b - a; + if (d >= PI) + a += PI * 2.0f; + else + if (d <= -PI) + a -= PI * 2.0f; + return a + (b - a) * t; + } + + quat lerpAngle(const vec3 &a, const vec3 &b, float t) { + // return vec3(lerpAngle(a.x, b.x, t), + // lerpAngle(a.y, b.y, t), + // lerpAngle(a.z, b.z, t)); + + mat4 ma, mb; + ma.identity(); + mb.identity(); + + ma.rotateY(a.y); + ma.rotateX(a.x); + ma.rotateZ(a.z); + + mb.rotateY(b.y); + mb.rotateX(b.x); + mb.rotateZ(b.z); + + return ma.getRot().slerp(mb.getRot(), t).normal(); + } + + void renderModel(const TR::Model &model) { + TR::Animation *anim = &level.anims[model.animation]; + + float fTime = time; + + if (model.id == ENTITY_LARA) { + anim = lara->anim; + fTime = lara->fTime; + } + + float k = fTime * 30.0f / anim->frameRate; + int fIndex = (int)k; + int fCount = (anim->frameEnd - anim->frameStart) / anim->frameRate + 1; + + int fSize = sizeof(TR::AnimFrame) + model.mCount * sizeof(uint16) * 2; + k = k - fIndex; + + + int fIndexA = fIndex % fCount, fIndexB = (fIndex + 1) % fCount; + TR::AnimFrame *frameA = (TR::AnimFrame*)&level.frameData[(anim->frameOffset + fIndexA * fSize) >> 1]; + + TR::Animation *nextAnim = NULL; + + if (fIndexB == 0) { + nextAnim = &level.anims[anim->nextAnimation]; + fIndexB = (anim->nextFrame - nextAnim->frameStart) / anim->frameRate; + } else + nextAnim = anim; + +// LOG("%d %f\n", fIndexA, fTime); + + + TR::AnimFrame *frameB = (TR::AnimFrame*)&level.frameData[(nextAnim->frameOffset + fIndexB * fSize) >> 1]; + + + +// ASSERT(fpSize == fSize); +// fSize = fpSize; + + // LOG("%d\n", fIndex % fCount); + //if (fCount > 1) LOG("%d %d\n", model->id, fCount); + // LOG("%d\n", fIndex % fCount); + + +// Debug::Draw::box(Box(vec3(frameA->minX, frameA->minY, frameA->minZ), vec3(frameA->maxX, frameA->maxY, frameA->maxZ))); + + TR::Node *node = (int)model.node < level.nodesDataSize ? (TR::Node*)&level.nodesData[model.node] : NULL; + + int sIndex = 0; + mat4 stack[20]; + + mat4 m; + m.identity(); + m.translate(vec3(frameA->x, frameA->y, frameA->z).lerp(vec3(frameB->x, frameB->y, frameB->z), k)); + + for (int i = 0; i < model.mCount; i++) { + + if (i > 0 && node) { + TR::Node &t = node[i - 1]; + + if (t.flags & 0x01) m = stack[--sIndex]; + if (t.flags & 0x02) stack[sIndex++] = m; + + ASSERT(sIndex >= 0); + ASSERT(sIndex < 20); + + m.translate(vec3(t.x, t.y, t.z)); + } + + quat q = lerpAngle(getAngle(frameA, i), getAngle(frameB, i), k); + m = m * mat4(q, vec3(0.0f)); + + + // vec3 angle = lerpAngle(getAngle(frameA, i), getAngle(frameB, i), k); + // m.rotateY(angle.y); + // m.rotateX(angle.x); + // m.rotateZ(angle.z); + + mat4 tmp = Core::mModel; + Core::mModel = Core::mModel * m; + renderMesh(model.mStart + i); + Core::mModel = tmp; + } + } + + int getLightIndex(const vec3 &pos, int &room) { + int idx = -1; + float dist; + // for (int j = 0; j < level.roomsCount; j++) + int j = room; + for (int i = 0; i < level.rooms[j].lightsCount; i++) { + TR::Room::Light &light = level.rooms[j].lights[i]; + float d = (pos - vec3(light.x, light.y, light.z)).length2(); + if (idx == -1 || d < dist) { + idx = i; + dist = d; + // room = j; + } + } + return idx; + } + + void getLight(const vec3 &pos, int roomIndex) { + int room = roomIndex; + int idx = getLightIndex(pos, room); + if (idx > -1) { + TR::Room::Light &light = level.rooms[room].lights[idx]; + float c = level.rooms[room].lights[idx].intensity / 8191.0f; + Core::lightPos = vec3(light.x, light.y, light.z); + Core::lightColor = vec4(c, c, c, light.attenuation * light.attenuation); + } else { + Core::lightPos = vec3(0.0f); + Core::lightColor = vec4(0.0f); + } + Core::ambient = vec3(1.0f - level.rooms[roomIndex].ambient / 8191.0f); + shader->setParam(uAmbient, Core::ambient); + shader->setParam(uLightPos, Core::lightPos); + shader->setParam(uLightColor, Core::lightColor); + } + + void renderEntity(const TR::Entity &entity) { + // if (!(entity.flags & ENTITY_FLAG_VISIBLE)) + // return; + + mat4 m = Core::mModel; + Core::mModel.translate(vec3(entity.x, entity.y, entity.z)); + + float c = (entity.intensity > -1) ? (1.0f - entity.intensity / (float)0x1FFF) : 1.0f; + float l = 1.0f; + + Core::color = vec4(c, c, c, 1.0); + shader->setParam(uColor, Core::color); + + getLight(vec3(entity.x, entity.y, entity.z), entity.room); + + for (int i = 0; i < level.modelsCount; i++) + if (entity.id == level.models[i].id) { + Core::mModel.rotateY(entity.rotation / 16384.0f * PI * 0.5f); + renderModel(level.models[i]); + break; + } + /* + for (int i = 0; i < level.spriteSequencesCount; i++) + if (entity.id == level.spriteSequences[i].id) { + renderSprite(level.spriteTextures[level.spriteSequences[i].sStart]); + break; + } + */ + Core::mModel = m; + } + +#ifdef _DEBUG + void debugPortals() { + Core::setBlending(bmAdd); + glColor3f(0, 0.25f, 0.25f); + glDepthMask(GL_FALSE); + + glBegin(GL_QUADS); + for (int i = 0; i < level.roomsCount; i++) { + TR::Room &r = level.rooms[i]; + for (int j = 0; j < r.portalsCount; j++) { + TR::Room::Portal &p = r.portals[j]; + for (int k = 0; k < 4; k++) { + TR::Vertex &v = p.vertices[k]; + glVertex3f(v.x + r.info.x, v.y, v.z + r.info.z); + } + } + } + glEnd(); + + glDepthMask(GL_TRUE); + Core::setBlending(bmAlpha); + } + + void debugFloor(const vec3 &f, const vec3 &c, int floorIndex, bool current) { + 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) }; + + uint16 cmd, *d = &level.floors[floorIndex]; + + if (floorIndex) + do { + cmd = *d++; + int func = cmd & 0x00FF; // function + int sub = (cmd & 0x7F00) >> 8; // sub function + + if (func == 0x01) { // portal + d++; + // d += 2; + + } + + if ((func == 0x02 || func == 0x03) && sub == 0x00) { // floor & ceiling corners + int sx = 256 * int((int8)(*d & 0x00FF)); + int sz = 256 * int((int8)((*d & 0xFF00) >> 8)); + + auto &p = func == 0x02 ? vf : vc; + + if (func == 0x02) { + + // if (current) + // LOG("%d\n", sx); + + if (sx > 0) { + p[0].y += sx; + p[3].y += sx; + } else { + p[1].y -= sx; + p[2].y -= sx; + } + + if (sz > 0) { + p[0].y += sz; + p[1].y += sz; + } else { + p[3].y -= sz; + p[2].y -= sz; + } + + } else { + + if (sx < 0) { + p[0].y += sx; + p[3].y += sx; + } else { + p[1].y -= sx; + p[2].y -= sx; + } + + if (sz > 0) { + p[0].y -= sz; + p[1].y -= sz; + } else { + p[3].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; + } + + } while (!(cmd & 0x8000)); + + if (current) + glColor3f(1, 1, 1); + else + glColor3f(0, 1, 0); + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < 5; i++) + glVertex3fv((GLfloat*)&vf[i % 4]); + glEnd(); + + glColor3f(1, 0, 0); + glBegin(GL_LINE_STRIP); + for (int i = 0; i < 5; i++) + glVertex3fv((GLfloat*)&vc[i % 4]); + glEnd(); + } + + void debugSectors(int index) { + TR::Room &room = level.rooms[index]; + + vec3 p = (lara->pos - vec3(room.info.x, 0, room.info.z)) / vec3(1024, 1, 1024); + + for (int z = 0; z < room.zSectors; z++) + for (int x = 0; x < room.xSectors; x++) { + auto &s = room.sectors[x * room.zSectors + z]; + vec3 f(x * 1024 + room.info.x, s.floor * 256, z * 1024 + room.info.z); + vec3 c(x * 1024 + room.info.x, s.ceiling * 256, z * 1024 + room.info.z); + + debugFloor(f, c, s.floorIndex, (int)p.x == x && (int)p.z == z); + } + } + + void debugRooms() { + Core::setBlending(bmAdd); + glDepthMask(GL_FALSE); + + for (int i = 0; i < level.roomsCount; i++) { + TR::Room &r = level.rooms[i]; + vec3 p = vec3(r.info.x, r.info.yTop, r.info.z); + + if (i == level.entities[lara->entity].room) { + //if (lara->insideRoom(Core::viewPos, i)) { + debugSectors(i); + glColor3f(0, 1, 0); + } else + glColor3f(1, 1, 1); + + Debug::Draw::box(p, p + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024)); + } + + glDepthMask(GL_TRUE); + Core::setBlending(bmAlpha); + } + + void debugMeshes() { + mat4 m = Core::mModel; + for (int i = 0; i < level.meshOffsetsCount; i++) { + renderMesh(i); + Core::mModel.translate(vec3(-128, 0, 0)); + } + Core::mModel = m; + } + + void debugLights() { + int roomIndex = level.entities[lara->entity].room; + int lightIndex = getLightIndex(lara->pos, roomIndex); + + glPointSize(8); + glBegin(GL_POINTS); + for (int i = 0; i < level.roomsCount; i++) + for (int j = 0; j < level.rooms[i].lightsCount; j++) { + TR::Room::Light &l = level.rooms[i].lights[j]; + float a = l.Intensity / 8191.0f; + vec3 p = vec3(l.x, l.y, l.z); + vec4 color = vec4(a, a, a, 1); + Debug::Draw::point(p, color); + if (i == roomIndex && j == lightIndex) + color = vec4(0, 1, 0, 1); + Debug::Draw::sphere(p, l.fade, color); + } + glEnd(); + } +#endif + + float tickTextureAnimation = 0.0f; + + void update() { + time += Core::deltaTime; + lara->update(); + camera.update(); + + /* + if (tickTextureAnimation > 0.25f) { + tickTextureAnimation = 0.0f; + + if (level.animTexturesDataSize) { + uint16 *ptr = &level.animTexturesData[0]; + int count = *ptr++; + for (int i = 0; i < count; i++) { + auto animTex = (TR::AnimTexture*)ptr; + auto id = level.objectTextures[animTex->textures[0]]; + for (int j = 0; j < animTex->tCount; j++) // tCount = count of textures in animation group - 1 (!!!) + level.objectTextures[animTex->textures[j]] = level.objectTextures[animTex->textures[j + 1]]; + level.objectTextures[animTex->textures[animTex->tCount]] = id; + ptr += (sizeof(TR::AnimTexture) + sizeof(animTex->textures[0]) * (animTex->tCount + 1)) / sizeof(uint16); + } + } + } else + tickTextureAnimation += Core::deltaTime; + */ + } + + void render() { + #ifndef FREE_CAMERA + camera.pos = vec3(-lara->pos.x, -lara->pos.y + 768, lara->pos.z); + #endif + camera.setup();; + + shader->bind(); + atlas->bind(0); + mesh->bind(); + + shader->setParam(uViewProj, Core::mViewProj); + shader->setParam(uModel, Core::mModel); + + glEnable(GL_DEPTH_TEST); + + Core::setCulling(cfFront); + + Core::mModel.identity(); + + for (int i = 0; i < level.roomsCount; i++) + renderRoom(i); + + for (int i = 0; i < level.entitiesCount; i++) + renderEntity(level.entities[i]); + + #ifdef _DEBUG + // debugMeshes(); + + Debug::Draw::begin(); + debugRooms(); + // debugLights(); + debugPortals(); + Debug::Draw::end(); + #endif + } }; #endif \ No newline at end of file diff --git a/src/mesh.h b/src/mesh.h index 53fd412..bf3c9f3 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -6,55 +6,55 @@ typedef unsigned short Index; struct Vertex { - short3 coord; - short2 texCoord; - short4 normal; - ubyte4 color; + short3 coord; + short2 texCoord; + short4 normal; + ubyte4 color; }; struct MeshRange { - int iStart; - int iCount; - int vStart; + int iStart; + int iCount; + int vStart; }; struct Mesh { - GLuint ID[2]; - int iCount; - int vCount; + GLuint ID[2]; + int iCount; + int vCount; - Mesh(Index *indices, int iCount, Vertex *vertices, int vCount) : iCount(iCount), vCount(vCount) { - glGenBuffers(2, ID); - bind(); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, iCount * sizeof(Index), indices, GL_STATIC_DRAW); - glBufferData(GL_ARRAY_BUFFER, vCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); - } + Mesh(Index *indices, int iCount, Vertex *vertices, int vCount) : iCount(iCount), vCount(vCount) { + glGenBuffers(2, ID); + bind(); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, iCount * sizeof(Index), indices, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, vCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); + } - virtual ~Mesh() { - glDeleteBuffers(2, ID); - } + virtual ~Mesh() { + glDeleteBuffers(2, ID); + } - void bind() { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ID[0]); - glBindBuffer(GL_ARRAY_BUFFER, ID[1]); + void bind() { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ID[0]); + glBindBuffer(GL_ARRAY_BUFFER, ID[1]); - glEnableVertexAttribArray(aCoord); - glEnableVertexAttribArray(aTexCoord); - glEnableVertexAttribArray(aNormal); - glEnableVertexAttribArray(aColor); - } + glEnableVertexAttribArray(aCoord); + glEnableVertexAttribArray(aTexCoord); + glEnableVertexAttribArray(aNormal); + glEnableVertexAttribArray(aColor); + } - void render(const MeshRange &range) { - Vertex *v = (Vertex*)(range.vStart * sizeof(Vertex)); - glVertexAttribPointer(aCoord, 3, GL_SHORT, false, sizeof(Vertex), &v->coord); - glVertexAttribPointer(aTexCoord, 2, GL_SHORT, true, sizeof(Vertex), &v->texCoord); - glVertexAttribPointer(aNormal, 4, GL_SHORT, true, sizeof(Vertex), &v->normal); - glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->color); - glDrawElements(GL_TRIANGLES, range.iCount, GL_UNSIGNED_SHORT, (GLvoid*)(range.iStart * sizeof(Index))); + void render(const MeshRange &range) { + Vertex *v = (Vertex*)(range.vStart * sizeof(Vertex)); + glVertexAttribPointer(aCoord, 3, GL_SHORT, false, sizeof(Vertex), &v->coord); + glVertexAttribPointer(aTexCoord, 2, GL_SHORT, true, sizeof(Vertex), &v->texCoord); + glVertexAttribPointer(aNormal, 4, GL_SHORT, true, sizeof(Vertex), &v->normal); + glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->color); + glDrawElements(GL_TRIANGLES, range.iCount, GL_UNSIGNED_SHORT, (GLvoid*)(range.iStart * sizeof(Index))); - Core::stats.dips++; - Core::stats.tris += range.iCount / 3; - } + Core::stats.dips++; + Core::stats.tris += range.iCount / 3; + } }; #endif \ No newline at end of file diff --git a/src/shader.glsl b/src/shader.glsl index 2cd9e98..351f0e4 100644 --- a/src/shader.glsl +++ b/src/shader.glsl @@ -34,12 +34,12 @@ varying vec4 vColor; discard; color *= vColor * uColor; // #ifdef LIGHTING - color.xyz = pow(color.xyz, vec3(2.2)); + color.xyz = pow(abs(color.xyz), vec3(2.2)); float lum = dot(normalize(vNormal.xyz), normalize(vLightVec)); float att = max(0.0, 1.0 - dot(vLightVec, vLightVec) / uLightColor.w); vec3 light = uLightColor.xyz * max(vNormal.w, lum * att) + uAmbient; color.xyz *= light; - color.xyz = pow(color.xyz, vec3(1.0/2.2)); + color.xyz = pow(abs(color.xyz), vec3(1.0/2.2)); // #endif gl_FragColor = color; } diff --git a/src/shader.h b/src/shader.h index 73954e8..9233dba 100644 --- a/src/shader.h +++ b/src/shader.h @@ -3,80 +3,84 @@ #include "core.h" -enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX }; -enum SamplerType { sDiffuse, sMAX }; -enum UniformType { uViewProj, uModel, uColor, uAmbient, uLightPos, uLightColor, uMAX }; +enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX }; +enum SamplerType { sDiffuse, sMAX }; +enum UniformType { uViewProj, uModel, uColor, uAmbient, uLightPos, uLightColor, uMAX }; -const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" }; -const char *SamplerName[sMAX] = { "sDiffuse" }; -const char *UniformName[uMAX] = { "uViewProj", "uModel", "uColor", "uAmbient", "uLightPos", "uLightColor" }; +const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" }; +const char *SamplerName[sMAX] = { "sDiffuse" }; +const char *UniformName[uMAX] = { "uViewProj", "uModel", "uColor", "uAmbient", "uLightPos", "uLightColor" }; struct Shader { - GLuint ID; - GLint uID[uMAX]; + GLuint ID; + GLint uID[uMAX]; - Shader(const char *text) { - #define GLSL_DEFINE "#version 110\n" + Shader(const char *text) { + #ifdef MOBILE + #define GLSL_DEFINE "precision highp float;\n" "#define MOBILE\n" + #else + #define GLSL_DEFINE "#version 120\n" + #endif - const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }; - const char *code[2][2] = { - { GLSL_DEFINE "#define VERTEX\n", text }, - { GLSL_DEFINE "#define FRAGMENT\n", text } - }; + const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }; + const char *code[2][2] = { + { GLSL_DEFINE "#define VERTEX\n", text }, + { GLSL_DEFINE "#define FRAGMENT\n", text } + }; - GLchar info[256]; + GLchar info[256]; - ID = glCreateProgram(); - for (int i = 0; i < 2; i++) { - GLuint obj = glCreateShader(type[i]); - glShaderSource(obj, 2, code[i], NULL); - glCompileShader(obj); - - glGetShaderInfoLog(obj, sizeof(info), NULL, info); - if (info[0]) LOG("! shader: %s\n", info); + ID = glCreateProgram(); + for (int i = 0; i < 2; i++) { + GLuint obj = glCreateShader(type[i]); + glShaderSource(obj, 2, code[i], NULL); + glCompileShader(obj); - glAttachShader(ID, obj); - glDeleteShader(obj); - } + glGetShaderInfoLog(obj, sizeof(info), NULL, info); + if (info[0]) LOG("! shader: %s\n", info); - for (int at = 0; at < aMAX; at++) - glBindAttribLocation(ID, at, AttribName[at]); + glAttachShader(ID, obj); + glDeleteShader(obj); + } - glLinkProgram(ID); + for (int at = 0; at < aMAX; at++) + glBindAttribLocation(ID, at, AttribName[at]); - glGetProgramInfoLog(ID, sizeof(info), NULL, info); - if (info[0]) LOG("! program: %s\n", info); + glLinkProgram(ID); - bind(); - for (int st = 0; st < sMAX; st++) - glUniform1iv(glGetUniformLocation(ID, (GLchar*)SamplerName[st]), 1, &st); - - for (int ut = 0; ut < uMAX; ut++) - uID[ut] = glGetUniformLocation(ID, (GLchar*)UniformName[ut]); - } - - virtual ~Shader() { - glDeleteProgram(ID); - } + glGetProgramInfoLog(ID, sizeof(info), NULL, info); + if (info[0]) LOG("! program: %s\n", info); - void bind() { - glUseProgram(ID); - } + bind(); + for (int st = 0; st < sMAX; st++) + glUniform1iv(glGetUniformLocation(ID, (GLchar*)SamplerName[st]), 1, &st); - void setParam(UniformType uType, const vec3 &value, int count = 1) { - if (uID[uType] != -1) - glUniform3fv(uID[uType], count, (GLfloat*)&value); - } + for (int ut = 0; ut < uMAX; ut++) + uID[ut] = glGetUniformLocation(ID, (GLchar*)UniformName[ut]); + } - void setParam(UniformType uType, const vec4 &value, int count = 1) { - if (uID[uType] != -1) - glUniform4fv(uID[uType], count, (GLfloat*)&value); - } + virtual ~Shader() { + glDeleteProgram(ID); + } - void setParam(UniformType uType, const mat4 &value, int count = 1) { - if (uID[uType] != -1) - glUniformMatrix4fv(uID[uType], count, false, (GLfloat*)&value); - } + void bind() { + glUseProgram(ID); + } + + void setParam(UniformType uType, const vec3 &value, int count = 1) { + if (uID[uType] != -1) + glUniform3fv(uID[uType], count, (GLfloat*)&value); + } + + void setParam(UniformType uType, const vec4 &value, int count = 1) { + if (uID[uType] != -1) + glUniform4fv(uID[uType], count, (GLfloat*)&value); + } + + void setParam(UniformType uType, const mat4 &value, int count = 1) { + if (uID[uType] != -1) + glUniformMatrix4fv(uID[uType], count, false, (GLfloat*)&value); + } }; #endif \ No newline at end of file diff --git a/src/texture.h b/src/texture.h index 04b2817..f17fefb 100644 --- a/src/texture.h +++ b/src/texture.h @@ -4,27 +4,27 @@ #include "core.h" struct Texture { - GLuint ID; - int width, height; + GLuint ID; + int width, height; - Texture(int width, int height, int format, void *data) : width(width), height(height) { - glGenTextures(1, &ID); - bind(0); + Texture(int width, int height, int format, void *data) : width(width), height(height) { + glGenTextures(1, &ID); + bind(0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + } - virtual ~Texture() { - glDeleteTextures(1, &ID); - } + virtual ~Texture() { + glDeleteTextures(1, &ID); + } - void bind(int sampler) { - glActiveTexture(GL_TEXTURE0 + sampler); - glBindTexture(GL_TEXTURE_2D, ID); - } + void bind(int sampler) { + glActiveTexture(GL_TEXTURE0 + sampler); + glBindTexture(GL_TEXTURE_2D, ID); + } }; #endif \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index bcceb14..eb58153 100644 --- a/src/utils.h +++ b/src/utils.h @@ -445,6 +445,7 @@ struct Stream { Stream(const char *name) : pos(0) { f = fopen(name, "rb"); + if (!f) LOG("error loading file\n"); fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); diff --git a/src/web/build.bat b/src/web/build.bat index 326d1d6..419cc0f 100644 --- a/src/web/build.bat +++ b/src/web/build.bat @@ -1,2 +1,2 @@ set SRC=main.cpp -em++ %SRC% -O2 --llvm-opts 2 --closure 1 -std=c++11 -o OpenLara.js --preload-file ./../../bin/data/LEVEL2_DEMO.PHD -I..\ \ No newline at end of file +em++ %SRC% -O2 --llvm-opts 2 --closure 1 -std=c++11 -o OpenLara.js --preload-file ./LEVEL2_DEMO.PHD -I..\ \ No newline at end of file diff --git a/src/web/main.cpp b/src/web/main.cpp index 12e8a16..b38cec3 100644 --- a/src/web/main.cpp +++ b/src/web/main.cpp @@ -27,6 +27,9 @@ void main_loop() { FPS = 0; } + int f; + emscripten_get_canvas_size(&Core::width, &Core::height, &f); + Game::update(); Game::render(); eglSwapBuffers(display, surface); diff --git a/src/win/main.cpp b/src/win/main.cpp index be20c90..9e59d4a 100644 --- a/src/win/main.cpp +++ b/src/win/main.cpp @@ -1,246 +1,246 @@ #ifdef _DEBUG - #include "crtdbg.h" + #include "crtdbg.h" #endif #include "game.h" DWORD getTime() { #ifdef DEBUG - LARGE_INTEGER Freq, Count; - QueryPerformanceFrequency(&Freq); - QueryPerformanceCounter(&Count); - return (DWORD)(Count.QuadPart * 1000L / Freq.QuadPart); + LARGE_INTEGER Freq, Count; + QueryPerformanceFrequency(&Freq); + QueryPerformanceCounter(&Count); + return (DWORD)(Count.QuadPart * 1000L / Freq.QuadPart); #else - timeBeginPeriod(0); - return timeGetTime(); + timeBeginPeriod(0); + return timeGetTime(); #endif } InputKey keyToInputKey(int code) { - int codes[] = { - VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_SPACE, VK_RETURN, VK_ESCAPE, VK_SHIFT, VK_CONTROL, VK_MENU, - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - }; + int codes[] = { + VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_SPACE, VK_RETURN, VK_ESCAPE, VK_SHIFT, VK_CONTROL, VK_MENU, + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + }; - for (int i = 0; i < sizeof(codes) / sizeof(codes[0]); i++) - if (codes[i] == code) - return (InputKey)(ikLeft + i); - return ikNone; + for (int i = 0; i < sizeof(codes) / sizeof(codes[0]); i++) + if (codes[i] == code) + return (InputKey)(ikLeft + i); + return ikNone; } InputKey mouseToInputKey(int msg) { - return (msg >= WM_LBUTTONDOWN || msg <= WM_LBUTTONDBLCLK) ? ikMouseL : - (msg >= WM_RBUTTONDOWN || msg <= WM_RBUTTONDBLCLK) ? ikMouseR : ikMouseM; + return (msg >= WM_LBUTTONDOWN || msg <= WM_LBUTTONDBLCLK) ? ikMouseL : + (msg >= WM_RBUTTONDOWN || msg <= WM_RBUTTONDBLCLK) ? ikMouseR : ikMouseM; } -#define JOY_DEAD_ZONE_STICK 0.3f -#define JOY_DEAD_ZONE_TRIGGER 0.01f +#define JOY_DEAD_ZONE_STICK 0.3f +#define JOY_DEAD_ZONE_TRIGGER 0.01f bool joyReady; void joyInit() { - JOYINFOEX info; - info.dwSize = sizeof(info); - info.dwFlags = JOY_RETURNALL; - joyReady = joyGetPosEx(0, &info) == JOYERR_NOERROR; + JOYINFOEX info; + info.dwSize = sizeof(info); + info.dwFlags = JOY_RETURNALL; + joyReady = joyGetPosEx(0, &info) == JOYERR_NOERROR; } void joyFree() { - joyReady = false; - memset(&Input::joy, 0, sizeof(Input::joy)); - for (int ik = ikJoyA; ik <= ikJoyDP; ik++) - Input::down[ik] = false; + joyReady = false; + memset(&Input::joy, 0, sizeof(Input::joy)); + for (int ik = ikJoyA; ik <= ikJoyDP; ik++) + Input::down[ik] = false; } float joyAxis(int x, int xMin, int xMax) { - return ((x - xMin) / (float)(xMax - xMin)) * 2.0f - 1.0f; + return ((x - xMin) / (float)(xMax - xMin)) * 2.0f - 1.0f; } vec2 joyDir(float ax, float ay) { - vec2 dir = vec2(ax, ay); - float dist = min(1.0f, dir.length()); - if (dist < JOY_DEAD_ZONE_STICK) dist = 0; + vec2 dir = vec2(ax, ay); + float dist = min(1.0f, dir.length()); + if (dist < JOY_DEAD_ZONE_STICK) dist = 0; - return dir.normal() * dist; + return dir.normal() * dist; } void joyUpdate() { - if (!joyReady) return; + if (!joyReady) return; - JOYINFOEX info; - info.dwSize = sizeof(info); - info.dwFlags = JOY_RETURNALL; + JOYINFOEX info; + info.dwSize = sizeof(info); + info.dwFlags = JOY_RETURNALL; - if (joyGetPosEx(0, &info) == JOYERR_NOERROR) { - JOYCAPS caps; - joyGetDevCaps(0, &caps, sizeof(caps)); + if (joyGetPosEx(0, &info) == JOYERR_NOERROR) { + JOYCAPS caps; + joyGetDevCaps(0, &caps, sizeof(caps)); - Input::setPos(ikJoyL, joyDir(joyAxis(info.dwXpos, caps.wXmin, caps.wXmax), - joyAxis(info.dwYpos, caps.wYmin, caps.wYmax))); + Input::setPos(ikJoyL, joyDir(joyAxis(info.dwXpos, caps.wXmin, caps.wXmax), + joyAxis(info.dwYpos, caps.wYmin, caps.wYmax))); - if ((caps.wCaps & JOYCAPS_HASR) && (caps.wCaps & JOYCAPS_HASU)) - Input::setPos(ikJoyR, joyDir(joyAxis(info.dwUpos, caps.wUmin, caps.wUmax), - joyAxis(info.dwRpos, caps.wRmin, caps.wRmax))); + if ((caps.wCaps & JOYCAPS_HASR) && (caps.wCaps & JOYCAPS_HASU)) + Input::setPos(ikJoyR, joyDir(joyAxis(info.dwUpos, caps.wUmin, caps.wUmax), + joyAxis(info.dwRpos, caps.wRmin, caps.wRmax))); - if (caps.wCaps & JOYCAPS_HASZ) { - float z = joyAxis(info.dwZpos, caps.wZmin, caps.wZmax); - if (fabsf(z) > JOY_DEAD_ZONE_TRIGGER) - Input::setPos(z > 0.0f ? ikJoyLT : ikJoyRT, vec2(fabsf(z), 0.0f)); - } - - if (caps.wCaps & JOYCAPS_HASPOV && info.dwPOV != JOY_POVCENTERED) - Input::setPos(ikJoyDP, vec2((float)(1 + info.dwPOV / 4500), 0)); + if (caps.wCaps & JOYCAPS_HASZ) { + float z = joyAxis(info.dwZpos, caps.wZmin, caps.wZmax); + if (fabsf(z) > JOY_DEAD_ZONE_TRIGGER) + Input::setPos(z > 0.0f ? ikJoyLT : ikJoyRT, vec2(fabsf(z), 0.0f)); + } - for (int i = 0; i < 10; i++) - Input::setDown((InputKey)(ikJoyA + i), (info.dwButtons & (1 << i)) > 0); - } else - joyFree(); + if (caps.wCaps & JOYCAPS_HASPOV && info.dwPOV != JOY_POVCENTERED) + Input::setPos(ikJoyDP, vec2((float)(1 + info.dwPOV / 4500), 0)); + + for (int i = 0; i < 10; i++) + Input::setDown((InputKey)(ikJoyA + i), (info.dwButtons & (1 << i)) > 0); + } else + joyFree(); } static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - switch (msg) { - case WM_ACTIVATE : - Input::reset(); - break; - // keyboard - case WM_KEYDOWN : - case WM_KEYUP : - case WM_SYSKEYDOWN : - case WM_SYSKEYUP : - Input::setDown(keyToInputKey(wParam), msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN); - break; - // mouse - case WM_LBUTTONDOWN : - case WM_LBUTTONUP : - case WM_LBUTTONDBLCLK : - case WM_RBUTTONDOWN : - case WM_RBUTTONUP : - case WM_RBUTTONDBLCLK : - case WM_MBUTTONDOWN : - case WM_MBUTTONUP : - case WM_MBUTTONDBLCLK : { - InputKey key = mouseToInputKey(msg); - Input::setPos(key, vec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam))); - bool down = msg != WM_LBUTTONUP && msg != WM_RBUTTONUP && msg != WM_MBUTTONUP; - Input::setDown(key, down); - if (down) - SetCapture(hWnd); - else - ReleaseCapture(); - break; - } - case WM_MOUSEMOVE : - Input::setPos(ikMouseL, vec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam))); - break; - // gamepad - case WM_DEVICECHANGE : - joyInit(); - return 1; - // touch - // ... - case WM_SIZE : - Core::width = LOWORD(lParam); - Core::height = HIWORD(lParam); - break; - case WM_DESTROY : - PostQuitMessage(0); - break; - default : - return DefWindowProc(hWnd, msg, wParam, lParam); - } - return 0; + switch (msg) { + case WM_ACTIVATE : + Input::reset(); + break; + // keyboard + case WM_KEYDOWN : + case WM_KEYUP : + case WM_SYSKEYDOWN : + case WM_SYSKEYUP : + Input::setDown(keyToInputKey(wParam), msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN); + break; + // mouse + case WM_LBUTTONDOWN : + case WM_LBUTTONUP : + case WM_LBUTTONDBLCLK : + case WM_RBUTTONDOWN : + case WM_RBUTTONUP : + case WM_RBUTTONDBLCLK : + case WM_MBUTTONDOWN : + case WM_MBUTTONUP : + case WM_MBUTTONDBLCLK : { + InputKey key = mouseToInputKey(msg); + Input::setPos(key, vec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam))); + bool down = msg != WM_LBUTTONUP && msg != WM_RBUTTONUP && msg != WM_MBUTTONUP; + Input::setDown(key, down); + if (down) + SetCapture(hWnd); + else + ReleaseCapture(); + break; + } + case WM_MOUSEMOVE : + Input::setPos(ikMouseL, vec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam))); + break; + // gamepad + case WM_DEVICECHANGE : + joyInit(); + return 1; + // touch + // ... + case WM_SIZE : + Core::width = LOWORD(lParam); + Core::height = HIWORD(lParam); + break; + case WM_DESTROY : + PostQuitMessage(0); + break; + default : + return DefWindowProc(hWnd, msg, wParam, lParam); + } + return 0; } HGLRC initGL(HDC hDC) { - PIXELFORMATDESCRIPTOR pfd; - memset(&pfd, 0, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.cColorBits = 32; - pfd.cDepthBits = 24; + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.cColorBits = 32; + pfd.cDepthBits = 24; - int format = ChoosePixelFormat(hDC, &pfd); - SetPixelFormat(hDC, format, &pfd); - HGLRC hRC = wglCreateContext(hDC); - wglMakeCurrent(hDC, hRC); - return hRC; + int format = ChoosePixelFormat(hDC, &pfd); + SetPixelFormat(hDC, format, &pfd); + HGLRC hRC = wglCreateContext(hDC); + wglMakeCurrent(hDC, hRC); + return hRC; } void freeGL(HGLRC hRC) { - wglMakeCurrent(0, 0); - wglDeleteContext(hRC); + wglMakeCurrent(0, 0); + wglDeleteContext(hRC); } int main() { #ifdef _DEBUG - _CrtMemState _ms; - _CrtMemCheckpoint(&_ms); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); + _CrtMemState _ms; + _CrtMemCheckpoint(&_ms); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); #endif - RECT r = { 0, 0, 1280, 720 }; - AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false); + RECT r = { 0, 0, 1280, 720 }; + AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false); - HWND hWnd = CreateWindow("static", "OpenLara", WS_OVERLAPPEDWINDOW, 0, 0, r.right - r.left, r.bottom - r.top, 0, 0, 0, 0); + HWND hWnd = CreateWindow("static", "OpenLara", WS_OVERLAPPEDWINDOW, 0, 0, r.right - r.left, r.bottom - r.top, 0, 0, 0, 0); - joyInit(); + joyInit(); - HDC hDC = GetDC(hWnd); - HGLRC hRC = initGL(hDC); - Game::init(); + HDC hDC = GetDC(hWnd); + HGLRC hRC = initGL(hDC); + Game::init(); - SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc); - ShowWindow(hWnd, SW_SHOWDEFAULT); + SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc); + ShowWindow(hWnd, SW_SHOWDEFAULT); - DWORD time, lastTime = getTime(); - - MSG msg; - msg.message = WM_PAINT; - - DWORD fps = 0, fpsTime = getTime() + 1000; + DWORD time, lastTime = getTime(); - while (msg.message != WM_QUIT) - if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } else { - time = getTime(); - if (time <= lastTime) - continue; - - Core::deltaTime = (time - lastTime) * 0.001f; - lastTime = time; + MSG msg; + msg.message = WM_PAINT; - joyUpdate(); + DWORD fps = 0, fpsTime = getTime() + 1000; - Core::stats.dips = 0; - Core::stats.tris = 0; + while (msg.message != WM_QUIT) + if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + time = getTime(); + if (time <= lastTime) + continue; - Game::update(); - Game::render(); + Core::deltaTime = (time - lastTime) * 0.001f; + lastTime = time; - SwapBuffers(hDC); + joyUpdate(); - if (fpsTime < getTime()) { - LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris); - fps = 0; - fpsTime = getTime() + 1000; - } else - fps++; - } - - Game::free(); - freeGL(hRC); - ReleaseDC(hWnd, hDC); + Core::stats.dips = 0; + Core::stats.tris = 0; - DestroyWindow(hWnd); + Game::update(); + Game::render(); + + SwapBuffers(hDC); + + if (fpsTime < getTime()) { + LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris); + fps = 0; + fpsTime = getTime() + 1000; + } else + fps++; + } + + Game::free(); + freeGL(hRC); + ReleaseDC(hWnd, hDC); + + DestroyWindow(hWnd); #ifdef _DEBUG - _CrtMemDumpAllObjectsSince(&_ms); - system("pause"); + _CrtMemDumpAllObjectsSince(&_ms); + system("pause"); #endif - return 0; + return 0; } \ No newline at end of file