mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-09 06:36:59 +02:00
code refactoring
This commit is contained in:
190
src/controller.h
Normal file
190
src/controller.h
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#ifndef H_CONTROLLER
|
||||||
|
#define H_CONTROLLER
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
struct Controller {
|
||||||
|
TR::Level *level;
|
||||||
|
TR::Animation *anim;
|
||||||
|
float fTime;
|
||||||
|
|
||||||
|
vec3 pos;
|
||||||
|
float angle;
|
||||||
|
|
||||||
|
int state; // LaraState
|
||||||
|
int lastFrame;
|
||||||
|
|
||||||
|
Controller(TR::Level *level) : level(level), pos(0.0f), angle(0.0f), fTime(0.0f) {
|
||||||
|
anim = &level->anims[0];
|
||||||
|
lastFrame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
float rot = 0.0f;
|
||||||
|
state = TR::STATE_STOP;
|
||||||
|
if (Input::down[ikShift]) {
|
||||||
|
if (Input::down[ikUp]) { state = TR::STATE_WALK; };
|
||||||
|
if (Input::down[ikDown]) { state = TR::STATE_BACK; };
|
||||||
|
if (Input::down[ikLeft]) { if (!Input::down[ikUp] && !Input::down[ikDown]) { state = TR::STATE_STEP_LEFT; } else rot = -Core::deltaTime * PI; };
|
||||||
|
if (Input::down[ikRight]) { if (!Input::down[ikUp] && !Input::down[ikDown]) { state = TR::STATE_STEP_RIGHT; } else rot = Core::deltaTime * PI; };
|
||||||
|
} else
|
||||||
|
if (Input::down[ikSpace]) {
|
||||||
|
if (anim->state == TR::STATE_RUN)
|
||||||
|
state = TR::STATE_FORWARD_JUMP;
|
||||||
|
else
|
||||||
|
if (Input::down[ikUp])
|
||||||
|
state = anim->state != TR::STATE_COMPRESS ? TR::STATE_COMPRESS : TR::STATE_FORWARD_JUMP;
|
||||||
|
else
|
||||||
|
if (Input::down[ikDown])
|
||||||
|
state = anim->state != TR::STATE_COMPRESS ? TR::STATE_COMPRESS : TR::STATE_BACK_JUMP;
|
||||||
|
else
|
||||||
|
if (Input::down[ikLeft])
|
||||||
|
state = anim->state != TR::STATE_COMPRESS ? TR::STATE_COMPRESS : TR::STATE_LEFT_JUMP;
|
||||||
|
else
|
||||||
|
if (Input::down[ikRight])
|
||||||
|
state = anim->state != TR::STATE_COMPRESS ? TR::STATE_COMPRESS : TR::STATE_RIGHT_JUMP;
|
||||||
|
else
|
||||||
|
state = TR::STATE_UP_JUMP;
|
||||||
|
} else {
|
||||||
|
if (Input::down[ikUp]) { state = TR::STATE_RUN; };
|
||||||
|
if (Input::down[ikDown]) { state = TR::STATE_FAST_BACK; };
|
||||||
|
if (Input::down[ikLeft]) { if (!Input::down[ikUp] && !Input::down[ikDown]) state = TR::STATE_TURN_LEFT; rot = -Core::deltaTime * PI; };
|
||||||
|
if (Input::down[ikRight]) { if (!Input::down[ikUp] && !Input::down[ikDown]) state = TR::STATE_TURN_RIGHT; rot = Core::deltaTime * PI; };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input::down[ikEnter])
|
||||||
|
state = TR::STATE_COMPRESS;
|
||||||
|
|
||||||
|
|
||||||
|
fTime += Core::deltaTime;
|
||||||
|
int fCount = anim->frameEnd - anim->frameStart + 1;
|
||||||
|
int fIndex = int(fTime * 30.0f);
|
||||||
|
|
||||||
|
// LOG("%d / %d\n", fIndex, fCount);
|
||||||
|
|
||||||
|
// fIndex = anim->frameStart + (fIndex % fCount);
|
||||||
|
//LOG("%d\n", fIndex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (anim->state == state) {
|
||||||
|
for (int i = 0; i < anim->scCount; i++) {
|
||||||
|
auto &sc = level->stateChanges[anim->scOffset + i];
|
||||||
|
LOG("%d ", sc.state);
|
||||||
|
}
|
||||||
|
LOG("\n");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (anim->state != state) {
|
||||||
|
for (int i = 0; i < anim->scCount; i++) {
|
||||||
|
auto &sc = level->states[anim->scOffset + i];
|
||||||
|
if (sc.state == state) {
|
||||||
|
for (int j = 0; j < sc.rCount; j++) {
|
||||||
|
auto &range = level->ranges[sc.rangeOffset + j];
|
||||||
|
if ( anim->frameStart + fIndex >= range.low && anim->frameStart + fIndex <= range.high) {
|
||||||
|
int st = anim->state;
|
||||||
|
anim = &level->anims[range.nextAnimation];
|
||||||
|
fTime = 0.0f;//(ad.nextFrame - anim->frameStart) / (30.0f / anim->frameRate);
|
||||||
|
fIndex = range.nextFrame - anim->frameStart;
|
||||||
|
fCount = anim->frameEnd - anim->frameStart + 1;
|
||||||
|
// LOG("set anim %d %f %f %d -> %d -> %d\n", range.nextAnimation, anim->accel.toFloat(), anim->speed.toFloat(), st, state, anim->state);
|
||||||
|
|
||||||
|
//LOG("from %f to %f\n", s, s + a * c);
|
||||||
|
// LOG("frame: %d\n", fIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fIndex >= fCount) {
|
||||||
|
fIndex = anim->nextFrame;
|
||||||
|
int id = anim->nextAnimation;
|
||||||
|
anim = &level->anims[anim->nextAnimation];
|
||||||
|
// LOG("nxt anim %d %f %f %d %d\n", id, anim->accel.toFloat(), anim->speed.toFloat(), anim->frameRate, anim->frameEnd - anim->frameStart + 1);
|
||||||
|
|
||||||
|
// LOG("from %f to %f\n", s, s + a * c / 30.0f);
|
||||||
|
|
||||||
|
fIndex -= anim->frameStart;
|
||||||
|
// LOG("frame: %d\n", fIndex);
|
||||||
|
fTime = (fIndex) / 30.0f;
|
||||||
|
//fCount = anim->frameEnd - anim->frameStart + 1;
|
||||||
|
//LOG("reset\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anim->state == state) {
|
||||||
|
angle += rot;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 sx = *ptr++;
|
||||||
|
int16 sz = *ptr++;
|
||||||
|
LOG("jump: %d %d\n", (int)sx, (int)sz);
|
||||||
|
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];
|
||||||
|
|
||||||
|
PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x06 :
|
||||||
|
ptr += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 speed = anim->speed.toFloat() + anim->accel.toFloat() * (fTime * 30.0f);
|
||||||
|
pos = pos + vec3(sinf(d), 0, cosf(d)) * (speed * Core::deltaTime * 30.0f);
|
||||||
|
|
||||||
|
|
||||||
|
lastFrame = fIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
// Texture
|
// Texture
|
||||||
PFNGLACTIVETEXTUREPROC glActiveTexture;
|
PFNGLACTIVETEXTUREPROC glActiveTexture;
|
||||||
PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
|
|
||||||
// Shader
|
// Shader
|
||||||
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
||||||
PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
||||||
@@ -64,7 +63,6 @@ namespace Core {
|
|||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
GetProcOGL(glActiveTexture);
|
GetProcOGL(glActiveTexture);
|
||||||
GetProcOGL(glCompressedTexImage2D);
|
|
||||||
|
|
||||||
GetProcOGL(glCreateProgram);
|
GetProcOGL(glCreateProgram);
|
||||||
GetProcOGL(glDeleteProgram);
|
GetProcOGL(glDeleteProgram);
|
||||||
|
637
src/format.h
Normal file
637
src/format.h
Normal file
@@ -0,0 +1,637 @@
|
|||||||
|
#ifndef H_FORMAT
|
||||||
|
#define H_FORMAT
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace TR {
|
||||||
|
#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_23,
|
||||||
|
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_NULL_54,
|
||||||
|
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 };
|
||||||
|
|
||||||
|
#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 Intensity1; // 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 rCount; // number of ranges
|
||||||
|
uint16 rangeOffset; // 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
|
||||||
|
tiles = stream.readArray<Tile8>(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;
|
||||||
|
d.vertices = stream.readArray<Room::Data::Vertex>(stream.read(d.vCount));
|
||||||
|
d.rectangles = stream.readArray<Rectangle>(stream.read(d.rCount));
|
||||||
|
d.triangles = stream.readArray<Triangle>(stream.read(d.tCount));
|
||||||
|
d.sprites = stream.readArray<Room::Data::Sprite>(stream.read(d.sCount));
|
||||||
|
stream.setPos(pos + d.size * 2);
|
||||||
|
// portals
|
||||||
|
r.portals = stream.readArray<Room::Portal>(stream.read(r.portalsCount));
|
||||||
|
// sectors
|
||||||
|
stream.read(r.zSectors);
|
||||||
|
stream.read(r.xSectors);
|
||||||
|
r.sectors = stream.readArray<Room::Sector>(r.zSectors * r.xSectors);
|
||||||
|
// ambient light luminance
|
||||||
|
stream.read(r.ambient);
|
||||||
|
// lights
|
||||||
|
r.lights = stream.readArray<Room::Light>(stream.read(r.lightsCount));
|
||||||
|
// meshes
|
||||||
|
r.meshes = stream.readArray<Room::Mesh>(stream.read(r.meshesCount));
|
||||||
|
|
||||||
|
stream.read(r.alternateRoom);
|
||||||
|
stream.read(r.flags);
|
||||||
|
}
|
||||||
|
// floors
|
||||||
|
floors = stream.readArray<uint16>(stream.read(floorsCount));
|
||||||
|
// meshes
|
||||||
|
meshData = stream.readArray<uint16>(stream.read(meshDataSize));
|
||||||
|
meshOffsets = stream.readArray<uint32>(stream.read(meshOffsetsCount));
|
||||||
|
// animations
|
||||||
|
anims = stream.readArray<Animation>(stream.read(animsCount));
|
||||||
|
states = stream.readArray<AnimState>(stream.read(statesCount));
|
||||||
|
ranges = stream.readArray<AnimRange>(stream.read(rangesCount));
|
||||||
|
commands = stream.readArray<int16>(stream.read(commandsCount));
|
||||||
|
nodesData = stream.readArray<uint32>(stream.read(nodesDataSize));
|
||||||
|
frameData = stream.readArray<uint16>(stream.read(frameDataSize));
|
||||||
|
// models
|
||||||
|
models = stream.readArray<Model>(stream.read(modelsCount));
|
||||||
|
staticMeshes = stream.readArray<StaticMesh>(stream.read(staticMeshesCount));
|
||||||
|
// textures & UV
|
||||||
|
objectTextures = stream.readArray<ObjectTexture>(stream.read(objectTexturesCount));
|
||||||
|
spriteTextures = stream.readArray<SpriteTexture>(stream.read(spriteTexturesCount));
|
||||||
|
spriteSequences = stream.readArray<SpriteSequence>(stream.read(spriteSequencesCount));
|
||||||
|
// cameras
|
||||||
|
camera = stream.readArray<Camera>(stream.read(camerasCount));
|
||||||
|
// sound sources
|
||||||
|
soundSources = stream.readArray<SoundSource>(stream.read(soundSourcesCount));
|
||||||
|
// AI
|
||||||
|
boxes = stream.readArray<Box>(stream.read(boxesCount));
|
||||||
|
overlaps = stream.readArray<uint16>(stream.read(overlapsCount));
|
||||||
|
zones = stream.readArray<Zone>(boxesCount);
|
||||||
|
// animated textures
|
||||||
|
animTexturesData = stream.readArray<uint16>(stream.read(animTexturesDataSize));
|
||||||
|
// entities (enemies, items, lara etc.)
|
||||||
|
entities = stream.readArray<Entity>(stream.read(entitiesCount));
|
||||||
|
// palette
|
||||||
|
stream.seek(32 * 256); // skip lightmap palette
|
||||||
|
palette = stream.readArray<RGB>(256);
|
||||||
|
// cinematic frames for cameras
|
||||||
|
cameraFrames = stream.readArray<CameraFrame>(stream.read(cameraFramesCount));
|
||||||
|
// demo data
|
||||||
|
demoData = stream.readArray<uint8>(stream.read(demoDataSize));
|
||||||
|
// sounds
|
||||||
|
soundsMap = stream.readArray<int16>(256);
|
||||||
|
soundsInfo = stream.readArray<SoundInfo>(stream.read(soundsInfoCount));
|
||||||
|
soundData = stream.readArray<uint8>(stream.read(soundDataSize));
|
||||||
|
soundOffsets = stream.readArray<uint32>(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1523
src/game.h
1523
src/game.h
File diff suppressed because it is too large
Load Diff
784
src/level.h
Normal file
784
src/level.h
Normal file
@@ -0,0 +1,784 @@
|
|||||||
|
#ifndef H_LEVEL
|
||||||
|
#define H_LEVEL
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "format.h"
|
||||||
|
#include "controller.h"
|
||||||
|
|
||||||
|
struct Level {
|
||||||
|
TR::Level level;
|
||||||
|
Texture **textures;
|
||||||
|
float time;
|
||||||
|
Controller *lara;
|
||||||
|
|
||||||
|
Level(const char *name) : level(Stream(name)), time(0.0f) {
|
||||||
|
if (level.tilesCount) {
|
||||||
|
textures = new Texture*[level.tilesCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < level.tilesCount; i++) {
|
||||||
|
// sprintf(buf, "LEVEL1_%d.PVR", i);
|
||||||
|
// textures[i] = Core::load<Texture>(buf);
|
||||||
|
textures[i] = getTexture(i);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
textures = NULL;
|
||||||
|
|
||||||
|
lara = new Controller(&level);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Level() {
|
||||||
|
for (int i = 0; i < level.tilesCount; i++)
|
||||||
|
delete textures[i];
|
||||||
|
delete[] textures;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture *getTexture(int tile) {
|
||||||
|
TR::RGBA data[256 * 256];
|
||||||
|
for (int i = 0; i < 256 * 256; i++) {
|
||||||
|
int index = level.tiles[tile].index[i];
|
||||||
|
auto p = level.palette[index];
|
||||||
|
data[i].r = p.r;
|
||||||
|
data[i].g = p.g;
|
||||||
|
data[i].b = p.b;
|
||||||
|
data[i].a = index == 0 ? 0 : 255;
|
||||||
|
}
|
||||||
|
return new Texture(256, 256, 0, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTexture(int objTexture) {
|
||||||
|
auto &t = level.objectTextures[objTexture];
|
||||||
|
Core::setBlending(t.attribute == 2 ? bmAdd : bmAlpha);
|
||||||
|
textures[t.tileAndFlag & 0x7FFF]->bind(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
float time;
|
||||||
|
vec3 laraPos(0.0f);
|
||||||
|
|
||||||
|
|
||||||
|
meshes = Array<tr_mesh>();
|
||||||
|
meshes.count = meshPointers.count;
|
||||||
|
meshes.items = new tr_mesh*[meshes.count];
|
||||||
|
|
||||||
|
for (int i = 0; i < meshPointers.count; i++) {
|
||||||
|
stream->setPos(meshesData + meshPointers[i]);
|
||||||
|
meshes.items[i] = new tr_mesh(stream);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SCALE (1.0f / 1024.0f / 2.0f)
|
||||||
|
|
||||||
|
void renderRoom(const TR::Room &room) {
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(-SCALE, -SCALE, SCALE);
|
||||||
|
glTranslatef(room.info.x, 0.0f, room.info.z);
|
||||||
|
|
||||||
|
// rectangles
|
||||||
|
for (int j = 0; j < room.data.rCount; j++) {
|
||||||
|
auto &f = room.data.rectangles[j];
|
||||||
|
auto &t = level.objectTextures[f.texture];
|
||||||
|
setTexture(f.texture);
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
auto &v = room.data.vertices[f.vertices[k]];
|
||||||
|
float a = 1.0f - v.lighting / 8191.0f;
|
||||||
|
glColor3f(a, a, a);
|
||||||
|
glTexCoord2f(t.vertices[k].Xpixel / 256.0f, t.vertices[k].Ypixel / 256.0f);
|
||||||
|
glVertex3f(v.vertex.x, v.vertex.y, v.vertex.z);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// triangles
|
||||||
|
for (int j = 0; j < room.data.tCount; j++) {
|
||||||
|
auto &f = room.data.triangles[j];
|
||||||
|
auto &t = level.objectTextures[f.texture];
|
||||||
|
setTexture(f.texture);
|
||||||
|
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
auto &v = room.data.vertices[f.vertices[k]];
|
||||||
|
float a = 1.0f - v.lighting / 8191.0f;
|
||||||
|
glColor3f(a, a, a);
|
||||||
|
glTexCoord2f(t.vertices[k].Xpixel / 256.0f, t.vertices[k].Ypixel / 256.0f);
|
||||||
|
glVertex3f(v.vertex.x, v.vertex.y, v.vertex.z);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
// meshes
|
||||||
|
float a = 1.0f - room.ambient / 8191.0f;
|
||||||
|
|
||||||
|
for (int j = 0; j < room.meshesCount; j++) {
|
||||||
|
auto rMesh = room.meshes[j];
|
||||||
|
auto sMesh = getMeshByID(rMesh.meshID);
|
||||||
|
ASSERT(sMesh != NULL);
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(-SCALE, -SCALE, SCALE);
|
||||||
|
glTranslatef(rMesh.x, rMesh.y, rMesh.z);
|
||||||
|
glRotatef((rMesh.rotation >> 14) * 90.0f, 0, 1, 0);
|
||||||
|
|
||||||
|
renderMesh(sMesh->mesh, vec3(a));
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
// sprites
|
||||||
|
Core::setBlending(bmAlpha);
|
||||||
|
for (int j = 0; j < room.data.sCount; j++)
|
||||||
|
renderSprite(room, room.data.sprites[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void renderMesh(uint32 meshOffset, const vec3 &color) {
|
||||||
|
// remap mesh
|
||||||
|
#define OFFSET(bytes) (ptr = (TR::Mesh*)((char*)ptr + bytes - sizeof(char*)))
|
||||||
|
|
||||||
|
TR::Mesh *ptr = (TR::Mesh*)((char*)level.meshData + level.meshOffsets[meshOffset]);
|
||||||
|
TR::Mesh mesh;
|
||||||
|
mesh.center = ptr->center;
|
||||||
|
mesh.radius = ptr->radius;
|
||||||
|
mesh.vCount = ptr->vCount;
|
||||||
|
mesh.vertices = (TR::Vertex*)&ptr->vertices;
|
||||||
|
OFFSET(mesh.vCount * sizeof(TR::Vertex));
|
||||||
|
mesh.nCount = ptr->nCount;
|
||||||
|
mesh.normals = (TR::Vertex*)&ptr->normals;
|
||||||
|
if (mesh.nCount > 0)
|
||||||
|
OFFSET(mesh.nCount * sizeof(TR::Vertex));
|
||||||
|
else
|
||||||
|
OFFSET(-mesh.nCount * sizeof(int16));
|
||||||
|
|
||||||
|
mesh.rCount = ptr->rCount;
|
||||||
|
mesh.rectangles = (TR::Rectangle*)&ptr->rectangles;
|
||||||
|
OFFSET(mesh.rCount * sizeof(TR::Rectangle));
|
||||||
|
|
||||||
|
mesh.tCount = ptr->tCount;
|
||||||
|
mesh.triangles = (TR::Triangle*)&ptr->triangles;
|
||||||
|
OFFSET(mesh.tCount * sizeof(TR::Triangle));
|
||||||
|
|
||||||
|
mesh.crCount = ptr->crCount;
|
||||||
|
mesh.crectangles = (TR::Rectangle*)&ptr->crectangles;
|
||||||
|
OFFSET(mesh.crCount * sizeof(TR::Rectangle));
|
||||||
|
|
||||||
|
mesh.ctCount = ptr->ctCount;
|
||||||
|
mesh.ctriangles = (TR::Triangle*)&ptr->ctriangles;
|
||||||
|
OFFSET(mesh.ctCount * sizeof(TR::Triangle));
|
||||||
|
|
||||||
|
if (mesh.nCount > 0)
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glColor3f(color.x, color.y, color.z);
|
||||||
|
|
||||||
|
// triangles
|
||||||
|
for (int j = 0; j < mesh.tCount; j++) {
|
||||||
|
auto &f = mesh.triangles[j];
|
||||||
|
auto &t = level.objectTextures[f.texture];
|
||||||
|
setTexture(f.texture);
|
||||||
|
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
auto &v = mesh.vertices[f.vertices[k]];
|
||||||
|
|
||||||
|
if (mesh.nCount > 0) {
|
||||||
|
auto vn = mesh.normals[f.vertices[k]];
|
||||||
|
vec3 n = vec3(vn.x, vn.y, vn.z).normal();
|
||||||
|
glNormal3f(n.x, n.y, n.z);
|
||||||
|
} else {
|
||||||
|
auto l = mesh.lights[f.vertices[k]];
|
||||||
|
float a = 1.0f - l / 8191.0f;
|
||||||
|
glColor3f(a, a, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
glTexCoord2f(t.vertices[k].Xpixel / 256.0f, t.vertices[k].Ypixel / 256.0f);
|
||||||
|
glVertex3f(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// rectangles
|
||||||
|
for (int j = 0; j < mesh.rCount; j++) {
|
||||||
|
auto &f = mesh.rectangles[j];
|
||||||
|
auto &t = level.objectTextures[f.texture];
|
||||||
|
setTexture(f.texture);
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
auto &v = mesh.vertices[f.vertices[k]];
|
||||||
|
|
||||||
|
if (mesh.nCount > 0) {
|
||||||
|
auto vn = mesh.normals[f.vertices[k]];
|
||||||
|
vec3 n = vec3(vn.x, vn.y, vn.z).normal();
|
||||||
|
glNormal3f(n.x, n.y, n.z);
|
||||||
|
} else {
|
||||||
|
auto l = mesh.lights[f.vertices[k]];
|
||||||
|
float a = 1.0f - l / 8191.0f;
|
||||||
|
glColor3f(a, a, a);
|
||||||
|
}
|
||||||
|
glTexCoord2f(t.vertices[k].Xpixel / 256.0f, t.vertices[k].Ypixel / 256.0f);
|
||||||
|
glVertex3f(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
// debug normals
|
||||||
|
|
||||||
|
// triangles (colored)
|
||||||
|
for (int j = 0; j < mesh.ctCount; j++) {
|
||||||
|
auto &f = mesh.ctriangles[j];
|
||||||
|
auto &c = level.palette[f.texture & 0xFF];
|
||||||
|
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
auto &v = mesh.vertices[f.vertices[k]];
|
||||||
|
|
||||||
|
if (mesh.nCount > 0) {
|
||||||
|
auto vn = mesh.normals[f.vertices[k]];
|
||||||
|
vec3 n = vec3(vn.x, vn.y, vn.z).normal();
|
||||||
|
glColor3f(c.r / 255.0f * color.x, c.g / 255.0f * color.y, c.b / 255.0f * color.z);
|
||||||
|
glNormal3f(n.x, n.y, n.z);
|
||||||
|
} else {
|
||||||
|
auto l = mesh.lights[f.vertices[k]];
|
||||||
|
float a = (1.0f - l / 8191.0f) / 255.0f;
|
||||||
|
glColor3f(c.r * a, c.g * a, c.b * a);
|
||||||
|
}
|
||||||
|
glVertex3f(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
// rectangles (colored)
|
||||||
|
for (int j = 0; j < mesh.crCount; j++) {
|
||||||
|
auto &f = mesh.crectangles[j];
|
||||||
|
auto &c = level.palette[f.texture & 0xFF];
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
auto &v = mesh.vertices[f.vertices[k]];
|
||||||
|
|
||||||
|
if (mesh.nCount > 0) {
|
||||||
|
auto vn = mesh.normals[f.vertices[k]];
|
||||||
|
vec3 n = vec3(vn.x, vn.y, vn.z).normal();
|
||||||
|
glColor3f(c.r / 255.0f * color.x, c.g / 255.0f * color.y, c.b / 255.0f * color.z);
|
||||||
|
glNormal3f(n.x, n.y, n.z);
|
||||||
|
} else {
|
||||||
|
auto l = mesh.lights[f.vertices[k]];
|
||||||
|
float a = (1.0f - l / 8191.0f) / 255.0f;
|
||||||
|
glColor3f(c.r * a, c.g * a, c.b * a);
|
||||||
|
}
|
||||||
|
glVertex3f(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
if (mesh.nCount > 0)
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
textures[sprite.tile]->bind(0);
|
||||||
|
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();
|
||||||
|
glScalef(-SCALE, -SCALE, SCALE);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
float debugTime = 0.0f;
|
||||||
|
|
||||||
|
void renderModel(const TR::Model &model) {
|
||||||
|
mat4 m;
|
||||||
|
m.identity();
|
||||||
|
|
||||||
|
TR::Animation *anim = &level.anims[model.animation];
|
||||||
|
|
||||||
|
float fTime = time;
|
||||||
|
|
||||||
|
if (model.id == ENTITY_LARA) {
|
||||||
|
anim = lara->anim;
|
||||||
|
fTime = lara->fTime;
|
||||||
|
m.translate(lara->pos);
|
||||||
|
m.rotateY(lara->angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glMultMatrixf((GLfloat*)&m);
|
||||||
|
renderMesh(model.mStart + i, vec3(1.0f));
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderEntity(const TR::Entity &entity) {
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(-SCALE, -SCALE, SCALE);
|
||||||
|
glTranslatef(entity.x, entity.y, entity.z);
|
||||||
|
|
||||||
|
if (entity.intensity > -1) {
|
||||||
|
float a = 1.0f - entity.intensity / (float)0x1FFF;
|
||||||
|
glColor3f(a, a, a);
|
||||||
|
} else
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < level.modelsCount; i++)
|
||||||
|
if (entity.id == level.models[i].id) {
|
||||||
|
glRotatef((entity.rotation >> 14) * 90.0f, 0, 1, 0);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
void debugPortals() {
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
Core::setBlending(bmAdd);
|
||||||
|
glColor3f(0, 0.25f, 0);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(-SCALE, -SCALE, SCALE);
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (int i = 0; i < rooms.count; i++) {
|
||||||
|
int x = rooms[i]->info.x;
|
||||||
|
int z = rooms[i]->info.z;
|
||||||
|
for (int j = 0; j < rooms[i]->portals.count; j++) {
|
||||||
|
auto &p = rooms[i]->portals[j];
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
auto &v = p.vertices[k];
|
||||||
|
glVertex3f(v.x + x, v.y, v.z + z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
Core::setBlending(bmAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugFloor(const vec3 &f, const vec3 &c, int floorIndex) {
|
||||||
|
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) };
|
||||||
|
|
||||||
|
auto *d = &floors[floorIndex];
|
||||||
|
auto cmd = *d;
|
||||||
|
|
||||||
|
do {
|
||||||
|
cmd = *d;
|
||||||
|
int func = cmd & 0x001F; // function
|
||||||
|
int sub = (cmd & 0x7F00) >> 8; // sub function
|
||||||
|
d++;
|
||||||
|
|
||||||
|
|
||||||
|
if (func == 0x00) { // portal
|
||||||
|
// d++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
d++;
|
||||||
|
|
||||||
|
|
||||||
|
// LOG("%d %d\n", func, sub);
|
||||||
|
} while ((cmd & 0x8000) == 0); // end
|
||||||
|
|
||||||
|
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(tr_room *room) {
|
||||||
|
vec3 p = (Core::viewPos / SCALE - vec3(-room->info.x, 0, room->info.z)) / vec3(1024, 1, 1024);
|
||||||
|
int px = (int)-p.x;
|
||||||
|
int pz = (int)p.z;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugRooms() {
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
Core::setBlending(bmAdd);
|
||||||
|
glColor3f(0, 0.25f, 0);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(-SCALE, -SCALE, SCALE);
|
||||||
|
|
||||||
|
for (int i = 0; i < rooms.count; i++) {
|
||||||
|
auto &r = *rooms[i];
|
||||||
|
vec3 p = vec3(r.info.x, r.info.yTop, r.info.z);
|
||||||
|
if (isInsideRoom(Core::viewPos, rooms[i])) {
|
||||||
|
debugSectors(rooms[i]);
|
||||||
|
glColor3f(0, 1, 0);
|
||||||
|
} else
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
|
||||||
|
Debug::Draw::box(Box(p, p + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024)));
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
Core::setBlending(bmAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugMeshes() {
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(-SCALE, -SCALE, SCALE);
|
||||||
|
for (int i = 0; i < meshes.count; i++) {
|
||||||
|
renderMesh(meshes[i], vec3(1.0f));
|
||||||
|
glTranslatef(-128, 0, 0);
|
||||||
|
}
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugLights() {
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
glPointSize(8);
|
||||||
|
glBegin(GL_POINTS);
|
||||||
|
for (int i = 0; i < rooms.count; i++)
|
||||||
|
for (int j = 0; j < rooms[i]->lights.count; j++) {
|
||||||
|
auto &l = rooms[i]->lights[j];
|
||||||
|
float a = l.Intensity1 / 8191.0f;
|
||||||
|
glColor3f(a, a, a);
|
||||||
|
glVertex3f(-l.x * SCALE, -l.y * SCALE, l.z * SCALE);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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() {
|
||||||
|
glEnable(GL_ALPHA_TEST);
|
||||||
|
glAlphaFunc(GL_GREATER, 0.9f);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glEnable(GL_NORMALIZE);
|
||||||
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
|
glEnable(GL_LIGHT0);
|
||||||
|
|
||||||
|
|
||||||
|
Core::setCulling(cfFront);
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < level.roomsCount; i++)
|
||||||
|
renderRoom(level.rooms[i]);
|
||||||
|
|
||||||
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
|
renderEntity(level.entities[i]);
|
||||||
|
|
||||||
|
// debugRooms();
|
||||||
|
// debugMeshes();
|
||||||
|
// debugLights();
|
||||||
|
// debugPortals();
|
||||||
|
// debugEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -3,83 +3,10 @@
|
|||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
|
||||||
#define PVR_RGBA8 0x61626772
|
|
||||||
#define PVR_ALPHA 0x00000061
|
|
||||||
#define PVR_PVRTC4 0x00000002 // iOS
|
|
||||||
#define PVR_ETC1 0x00000006 // Android
|
|
||||||
#define PVR_BC1 0x00000007 // Desktop
|
|
||||||
|
|
||||||
#define GL_COMPRESSED_RGB_S3TC_DXT1 0x83F0
|
|
||||||
#define GL_ETC1_RGB8_OES 0x8D64
|
|
||||||
#define GL_COMPRESSED_RGB_PVRTC_4BPPV1 0x8C00
|
|
||||||
|
|
||||||
struct Texture {
|
struct Texture {
|
||||||
GLuint ID;
|
GLuint ID;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
Texture(const char *name) {
|
|
||||||
Stream stream(name);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int version;
|
|
||||||
int flags;
|
|
||||||
long format;
|
|
||||||
long ext;
|
|
||||||
int color;
|
|
||||||
int channel;
|
|
||||||
int height;
|
|
||||||
int width;
|
|
||||||
int depth;
|
|
||||||
int surfaces;
|
|
||||||
int faces;
|
|
||||||
int mipCount;
|
|
||||||
int metaSize;
|
|
||||||
} header;
|
|
||||||
|
|
||||||
stream.read(header);
|
|
||||||
stream.seek(header.metaSize);
|
|
||||||
|
|
||||||
GLenum fmt;
|
|
||||||
int minSize;
|
|
||||||
switch (header.format) {
|
|
||||||
case PVR_ALPHA : minSize = 1; fmt = GL_ALPHA; break;
|
|
||||||
case PVR_RGBA8 : minSize = 1; fmt = GL_RGBA; break;
|
|
||||||
case PVR_BC1 : minSize = 4; fmt = GL_COMPRESSED_RGB_S3TC_DXT1; break;
|
|
||||||
case PVR_ETC1 : minSize = 4; fmt = GL_ETC1_RGB8_OES; break;
|
|
||||||
case PVR_PVRTC4 : minSize = 8; fmt = GL_COMPRESSED_RGB_PVRTC_4BPPV1; break;
|
|
||||||
default :
|
|
||||||
LOG("! unsupported texture format\n");
|
|
||||||
ID = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glGenTextures(1, &ID);
|
|
||||||
bind(0);
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, header.mipCount == 1 ? GL_LINEAR : GL_LINEAR_MIPMAP_LINEAR);
|
|
||||||
|
|
||||||
int sizeX = width = header.width;
|
|
||||||
int sizeY = height = header.height;
|
|
||||||
|
|
||||||
char *data = new char[width * height * 4];
|
|
||||||
for (int i = 0; i < header.mipCount; i++) {
|
|
||||||
if (minSize == 1) {
|
|
||||||
int size = sizeX * sizeY * (header.format == PVR_RGBA8 ? 4 : 1);
|
|
||||||
stream.read(data, size);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, i, fmt, sizeX, sizeY, 0, fmt, GL_UNSIGNED_BYTE, data);
|
|
||||||
} else {
|
|
||||||
int size = (max(sizeX, minSize) * max(sizeY, minSize) * 4 + 7) / 8;
|
|
||||||
stream.read(data, size);
|
|
||||||
glCompressedTexImage2D(GL_TEXTURE_2D, i, fmt, sizeX, sizeY, 0, size, data);
|
|
||||||
}
|
|
||||||
sizeX /= 2;
|
|
||||||
sizeY /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
Texture(int width, int height, int format, void *data) : width(width), height(height) {
|
Texture(int width, int height, int format, void *data) : width(width), height(height) {
|
||||||
glGenTextures(1, &ID);
|
glGenTextures(1, &ID);
|
||||||
bind(0);
|
bind(0);
|
||||||
|
93
src/utils.h
93
src/utils.h
@@ -24,6 +24,13 @@
|
|||||||
#define RAD2DEG (180.0f / PI)
|
#define RAD2DEG (180.0f / PI)
|
||||||
#define EPS FLT_EPSILON
|
#define EPS FLT_EPSILON
|
||||||
|
|
||||||
|
typedef char int8;
|
||||||
|
typedef short int16;
|
||||||
|
typedef int int32;
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline const T& min(const T &a, const T &b) {
|
inline const T& min(const T &a, const T &b) {
|
||||||
return a < b ? a : b;
|
return a < b ? a : b;
|
||||||
@@ -449,92 +456,6 @@ struct Stream {
|
|||||||
read(a, count * sizeof(T));
|
read(a, count * sizeof(T));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *readStr(char *buffer) {
|
|
||||||
unsigned char len;
|
|
||||||
read(&len, sizeof(len));
|
|
||||||
if (!len)
|
|
||||||
return NULL;
|
|
||||||
read(buffer, len);
|
|
||||||
buffer[len] = 0;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T, typename C = int>
|
|
||||||
struct Array {
|
|
||||||
T **items;
|
|
||||||
C count;
|
|
||||||
|
|
||||||
Array() : items(NULL), count(0) {}
|
|
||||||
|
|
||||||
Array(int count) : count(count) {
|
|
||||||
if (count == 0) {
|
|
||||||
items = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
items = new T*[count];
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
items[i] = new T();
|
|
||||||
}
|
|
||||||
|
|
||||||
Array(Stream *stream) {
|
|
||||||
stream->read(count);
|
|
||||||
if (count == 0) {
|
|
||||||
items = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
items = new T*[count];
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
items[i] = new T(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Array() {
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
delete items[i];
|
|
||||||
delete[] items;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* operator[] (int index) const {
|
|
||||||
return items[index];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename C = int>
|
|
||||||
struct Vector {
|
|
||||||
T *items;
|
|
||||||
C count;
|
|
||||||
|
|
||||||
Vector(Stream *stream) {
|
|
||||||
stream->read(count);
|
|
||||||
if (count <= 0) {
|
|
||||||
items = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
items = (T*)malloc((int)count * sizeof(T));
|
|
||||||
stream->read(items, (int)count * sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector(Stream *stream, int count) : count(count) {
|
|
||||||
if (count <= 0) {
|
|
||||||
items = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
items = (T*)malloc((int)count * sizeof(T));
|
|
||||||
stream->read(items, (int)count * sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
~Vector() {
|
|
||||||
if (items) free(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
T& operator[] (int index) const {
|
|
||||||
ASSERT(index >= 0);
|
|
||||||
ASSERT(index < count);
|
|
||||||
return items[index];
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@@ -94,12 +94,15 @@
|
|||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\controller.h" />
|
||||||
<ClInclude Include="..\core.h" />
|
<ClInclude Include="..\core.h" />
|
||||||
<ClInclude Include="..\game.h" />
|
<ClInclude Include="..\game.h" />
|
||||||
<ClInclude Include="..\input.h" />
|
<ClInclude Include="..\input.h" />
|
||||||
|
<ClInclude Include="..\level.h" />
|
||||||
<ClInclude Include="..\mesh.h" />
|
<ClInclude Include="..\mesh.h" />
|
||||||
<ClInclude Include="..\shader.h" />
|
<ClInclude Include="..\shader.h" />
|
||||||
<ClInclude Include="..\texture.h" />
|
<ClInclude Include="..\texture.h" />
|
||||||
|
<ClInclude Include="..\format.h" />
|
||||||
<ClInclude Include="..\utils.h" />
|
<ClInclude Include="..\utils.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
Reference in New Issue
Block a user