1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-09 06:36:59 +02:00

code refactoring

This commit is contained in:
XProger
2016-08-18 02:52:34 +03:00
parent 3382830f9a
commit 426ccebf95
8 changed files with 1625 additions and 1680 deletions

190
src/controller.h Normal file
View 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

View File

@@ -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
View 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

File diff suppressed because it is too large Load Diff

784
src/level.h Normal file
View 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

View File

@@ -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);

View File

@@ -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

View File

@@ -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" />