1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-10 15:14:28 +02:00

add VBO support

add shaders support
todo: animated textures, billboards
This commit is contained in:
XProger
2016-08-20 05:48:58 +03:00
parent 10b48368e7
commit 3d8c871ea7
8 changed files with 647 additions and 334 deletions

View File

@@ -4,8 +4,10 @@
#include "format.h"
struct Controller {
TR::Level *level;
TR::Animation *anim;
TR::Level *level;
int entity;
TR::Animation *anim;
float fTime;
vec3 pos;
@@ -14,9 +16,13 @@ struct Controller {
int state; // LaraState
int lastFrame;
Controller(TR::Level *level) : level(level), pos(0.0f), angle(0.0f), fTime(0.0f) {
Controller(TR::Level *level, int entity) : level(level), entity(entity), pos(0.0f), angle(0.0f), fTime(0.0f) {
anim = &level->anims[0];
lastFrame = 0;
TR::Entity &e = level->entities[entity];
pos = vec3(e.x, e.y, e.z);
angle = e.rotation / 16384.0f * PI * 0.5f;
}
void update() {
@@ -181,8 +187,43 @@ struct Controller {
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;
TR::Entity &e = level->entities[entity];
e.x = int(pos.x);
e.y = int(pos.y);
e.z = int(pos.z);
e.rotation = int(angle / (PI * 0.5f) * 16384.0f);
/*
TR::Room &room = level->rooms[level->entities[entity].room];
for (int i = 0; i < room.portalsCount; i++) {
if (insideRoom(pos, room.portals[i].roomIndex)) {
level->entities[entity].room = room.portals[i].roomIndex;
LOG("set room: %d\n", i);
break;
}
}
for (int i = 0; i < level->roomsCount; i++)
if (insideRoom(pos, i) && i != level->entities[entity].room) {
level->entities[entity].room = i;
LOG("set room: %d\n", i);
break;
}
*/
}
bool insideRoom(const vec3 &pos, int room) {
TR::Room &r = level->rooms[room];
vec3 min = vec3(r.info.x, r.info.yTop, r.info.z);
vec3 max = min + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024);
return pos.x >= min.x && pos.x <= max.x &&
pos.y >= min.y && pos.y <= max.y &&
pos.z >= min.z && pos.z <= max.z;
}
};

View File

@@ -50,6 +50,10 @@ namespace Core {
int width, height;
float deltaTime;
mat4 mView, mProj, mViewProj, mModel;
vec3 lightPos;
vec4 lightColor;
vec3 ambient;
vec4 color;
}
#include "texture.h"

View File

@@ -211,7 +211,7 @@ namespace TR {
int16 lightsCount;
struct Light {
int32 x, y, z; // Position of light, in world coordinates
uint16 Intensity1; // Light intensity
uint16 Intensity; // Light intensity
uint32 fade; // Falloff value
} *lights;
@@ -499,7 +499,7 @@ namespace TR {
// read version
stream.read(version);
// tiles
stream.readArray(tiles, stream.read(tilesCount));
stream.read(tiles, stream.read(tilesCount));
stream.read(unused);
// rooms
rooms = new Room[stream.read(roomsCount)];
@@ -511,69 +511,69 @@ namespace TR {
// room data
stream.read(d.size);
int pos = stream.pos;
stream.readArray(d.vertices, stream.read(d.vCount));
stream.readArray(d.rectangles, stream.read(d.rCount));
stream.readArray(d.triangles, stream.read(d.tCount));
stream.readArray(d.sprites, stream.read(d.sCount));
stream.read(d.vertices, stream.read(d.vCount));
stream.read(d.rectangles, stream.read(d.rCount));
stream.read(d.triangles, stream.read(d.tCount));
stream.read(d.sprites, stream.read(d.sCount));
stream.setPos(pos + d.size * 2);
// portals
stream.readArray(r.portals, stream.read(r.portalsCount));
stream.read(r.portals, stream.read(r.portalsCount));
// sectors
stream.read(r.zSectors);
stream.read(r.xSectors);
stream.readArray(r.sectors, r.zSectors * r.xSectors);
stream.read(r.sectors, r.zSectors * r.xSectors);
// ambient light luminance
stream.read(r.ambient);
// lights
stream.readArray(r.lights, stream.read(r.lightsCount));
stream.read(r.lights, stream.read(r.lightsCount));
// meshes
stream.readArray(r.meshes, stream.read(r.meshesCount));
stream.read(r.meshes, stream.read(r.meshesCount));
stream.read(r.alternateRoom);
stream.read(r.flags);
}
// floors
stream.readArray(floors, stream.read(floorsCount));
stream.read(floors, stream.read(floorsCount));
// meshes
stream.readArray(meshData, stream.read(meshDataSize));
stream.readArray(meshOffsets, stream.read(meshOffsetsCount));
stream.read(meshData, stream.read(meshDataSize));
stream.read(meshOffsets, stream.read(meshOffsetsCount));
// animations
stream.readArray(anims, stream.read(animsCount));
stream.readArray(states, stream.read(statesCount));
stream.readArray(ranges, stream.read(rangesCount));
stream.readArray(commands, stream.read(commandsCount));
stream.readArray(nodesData, stream.read(nodesDataSize));
stream.readArray(frameData, stream.read(frameDataSize));
stream.read(anims, stream.read(animsCount));
stream.read(states, stream.read(statesCount));
stream.read(ranges, stream.read(rangesCount));
stream.read(commands, stream.read(commandsCount));
stream.read(nodesData, stream.read(nodesDataSize));
stream.read(frameData, stream.read(frameDataSize));
// models
stream.readArray(models, stream.read(modelsCount));
stream.readArray(staticMeshes, stream.read(staticMeshesCount));
stream.read(models, stream.read(modelsCount));
stream.read(staticMeshes, stream.read(staticMeshesCount));
// textures & UV
stream.readArray(objectTextures, stream.read(objectTexturesCount));
stream.readArray(spriteTextures, stream.read(spriteTexturesCount));
stream.readArray(spriteSequences, stream.read(spriteSequencesCount));
stream.read(objectTextures, stream.read(objectTexturesCount));
stream.read(spriteTextures, stream.read(spriteTexturesCount));
stream.read(spriteSequences, stream.read(spriteSequencesCount));
// cameras
stream.readArray(camera, stream.read(camerasCount));
stream.read(camera, stream.read(camerasCount));
// sound sources
stream.readArray(soundSources, stream.read(soundSourcesCount));
stream.read(soundSources, stream.read(soundSourcesCount));
// AI
stream.readArray(boxes, stream.read(boxesCount));
stream.readArray(overlaps, stream.read(overlapsCount));
stream.readArray(zones, boxesCount);
stream.read(boxes, stream.read(boxesCount));
stream.read(overlaps, stream.read(overlapsCount));
stream.read(zones, boxesCount);
// animated textures
stream.readArray(animTexturesData, stream.read(animTexturesDataSize));
stream.read(animTexturesData, stream.read(animTexturesDataSize));
// entities (enemies, items, lara etc.)
stream.readArray(entities, stream.read(entitiesCount));
stream.read(entities, stream.read(entitiesCount));
// palette
stream.seek(32 * 256); // skip lightmap palette
stream.readArray(palette, 256);
stream.read(palette, 256);
// cinematic frames for cameras
stream.readArray(cameraFrames, stream.read(cameraFramesCount));
stream.read(cameraFrames, stream.read(cameraFramesCount));
// demo data
stream.readArray(demoData, stream.read(demoDataSize));
stream.read(demoData, stream.read(demoDataSize));
// sounds
stream.readArray(soundsMap, 256);
stream.readArray(soundsInfo, stream.read(soundsInfoCount));
stream.readArray(soundData, stream.read(soundDataSize));
stream.readArray(soundOffsets, stream.read(soundOffsetsCount));
stream.read(soundsMap, 256);
stream.read(soundsInfo, stream.read(soundsInfoCount));
stream.read(soundData, stream.read(soundDataSize));
stream.read(soundOffsets, stream.read(soundOffsetsCount));
// modify palette colors from 6-bit Amiga colorspace
int m = 0;

View File

@@ -6,19 +6,103 @@
#include "format.h"
#include "controller.h"
const char SHADER[] = \
"varying vec3 vLightVec;\n"\
"varying vec2 vTexCoord;\n"\
"varying vec4 vNormal;\n"\
"varying vec4 vColor;\n"\
\
"#ifdef VERTEX\n"\
" uniform mat4 uViewProj;\n"\
" uniform mat4 uModel;\n"\
" uniform vec3 uLightPos;\n"\
\
" attribute vec3 aCoord;\n"\
" attribute vec2 aTexCoord;\n"\
" attribute vec4 aNormal;\n"\
" attribute vec4 aColor;\n"\
\
" void main() {\n"\
" vec4 coord = uModel * vec4(aCoord, 1.0);\n"\
" vLightVec = uLightPos - coord.xyz;\n"\
" vTexCoord = aTexCoord + vec2(0.5/1024.0);\n"\
" vNormal = vec4(mat3(uModel[0].xyz, uModel[1].xyz, uModel[2].xyz) * (aNormal.xyz * 2.0 - 1.0), aNormal.w);\n"\
" vColor = aColor;\n"\
" gl_Position = uViewProj * coord;\n"\
" }\n"\
"#else\n"\
" uniform sampler2D sDiffuse;\n"\
" uniform vec4 uColor;\n"\
" uniform vec3 uAmbient;\n"\
" uniform vec4 uLightColor;\n"\
\
" void main() {\n"\
" vec4 color = texture2D(sDiffuse, vTexCoord) * vColor * uColor;\n"\
" color.xyz = pow(color.xyz, vec3(2.2));\n"\
" vec3 light = uLightColor.xyz * max(vNormal.w, dot(normalize(vNormal.xyz), normalize(vLightVec)));\n"\
" light += uAmbient;\n"\
" color.xyz *= light;\n"\
" color.xyz = pow(color.xyz, vec3(1.0/2.2));\n"\
" gl_FragColor = color;\n"\
" }\n"\
"#endif";
ubyte4 packNormal(const TR::Vertex &n) {
vec3 vn = (vec3(n.x, n.y, n.z).normal() * 0.5f + vec3(0.5f)) * 255.0f;
ubyte4 v;
// v.x = (int)n.x * 255 / (2 * 16300) + 127;
// v.y = (int)n.y * 255 / (2 * 16300) + 127;
// v.z = (int)n.z * 255 / (2 * 16300) + 127;
v.x = (int)vn.x;
v.y = (int)vn.y;
v.z = (int)vn.z;
v.w = 0;
return v;
}
struct Level {
TR::Level level;
Texture *atlas;
float time;
Controller *lara;
TR::Level level;
Shader *shader;
Texture *atlas;
Mesh *mesh;
Controller *lara;
float time;
MeshRange *rangeRooms;
int mCount;
struct MeshInfo : MeshRange {
int offset;
TR::Vertex center;
int32 radius;
} *meshInfo;
Level(const char *name) : level(Stream(name)), time(0.0f) {
shader = new Shader(SHADER);
initAtlas();
lara = new Controller(&level);
initMesh();
int entity = 0;
for (int i = 0; i < level.entitiesCount; i++)
if (level.entities[i].id == ENTITY_LARA) {
entity = i;
break;
}
lara = new Controller(&level, entity);
}
~Level() {
delete shader;
delete atlas;
delete mesh;
delete[] rangeRooms;
delete[] meshInfo;
delete lara;
}
void initAtlas() {
@@ -46,23 +130,315 @@ struct Level {
}
}
for (int y = 1020; y < 1024; y++)
for (int x = 1020; x < 1024; x++) {
int i = y * 1024 + x;
data[i].r = data[i].g = data[i].b = data[i].a = 255; // white texel for colored triangles
}
atlas = new Texture(1024, 1024, 0, data);
delete[] data;
}
void bindTexture(int tile) {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef((tile % 4) * 0.25f, (tile / 4) * 0.25f, 0.0f);
glScalef(0.25f, 0.25f, 1.0f);
glMatrixMode(GL_MODELVIEW);
}
void initMesh() {
// TODO: sort by texture attribute (t.attribute == 2 ? bmAdd : bmAlpha)
void setTexture(int objTexture) {
auto &t = level.objectTextures[objTexture];
Core::setBlending(t.attribute == 2 ? bmAdd : bmAlpha);
bindTexture(t.tileAndFlag & 0x7FFF);
rangeRooms = new MeshRange[level.roomsCount];
int iCount = 0, vCount = 0;
// get rooms mesh info
for (int i = 0; i < level.roomsCount; i++) {
rangeRooms[i].vStart = vCount;
rangeRooms[i].iStart = iCount;
TR::Room::Data &d = level.rooms[i].data;
iCount += d.rCount * 6 + d.tCount * 3;
vCount += d.rCount * 4 + d.tCount * 3;
rangeRooms[i].iCount = iCount - rangeRooms[i].iStart;
}
// get objects mesh info
#define OFFSET(bytes) (ptr = (TR::Mesh*)((char*)ptr + (bytes) - sizeof(char*)))
mCount = 0;
TR::Mesh *ptr = (TR::Mesh*)level.meshData;
while ( ((int)ptr - (int)level.meshData) < level.meshDataSize * 2 ) {
mCount++;
OFFSET(ptr->vCount * sizeof(TR::Vertex));
if (ptr->nCount > 0)
OFFSET(ptr->nCount * sizeof(TR::Vertex));
else
OFFSET(-ptr->nCount * sizeof(int16));
iCount += ptr->rCount * 6;
vCount += ptr->rCount * 4;
OFFSET(ptr->rCount * sizeof(TR::Rectangle));
iCount += ptr->tCount * 3;
vCount += ptr->tCount * 3;
OFFSET(ptr->tCount * sizeof(TR::Triangle));
iCount += ptr->crCount * 6;
vCount += ptr->crCount * 4;
OFFSET(ptr->crCount * sizeof(TR::Rectangle));
iCount += ptr->ctCount * 3;
vCount += ptr->ctCount * 3;
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
ptr = (TR::Mesh*)(((int)ptr + 3) & ~3);
}
meshInfo = new MeshInfo[mCount];
Index *indices = new Index[iCount];
Vertex *vertices = new Vertex[vCount];
iCount = vCount = 0;
// rooms geometry
for (int i = 0; i < level.roomsCount; i++) {
TR::Room::Data &d = level.rooms[i].data;
int vStart = vCount;
for (int j = 0; j < d.rCount; j++) {
auto &f = d.rectangles[j];
auto &t = level.objectTextures[f.texture];
int tile = t.tileAndFlag & 0x7FFF;
int tx = (tile % 4) * 256;
int ty = (tile / 4) * 256;
int vIndex = vCount - vStart;
indices[iCount + 0] = vIndex + 0;
indices[iCount + 1] = vIndex + 1;
indices[iCount + 2] = vIndex + 2;
indices[iCount + 3] = vIndex + 0;
indices[iCount + 4] = vIndex + 2;
indices[iCount + 5] = vIndex + 3;
iCount += 6;
for (int k = 0; k < 4; k++) {
auto &v = d.vertices[f.vertices[k]];
uint8 a = 255 - (v.lighting >> 5);
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z };
vertices[vCount].color = { a, a, a, 255 };
vertices[vCount].normal = { 0, 0, 0, 255 };
vertices[vCount].texCoord = { (tx + t.vertices[k].Xpixel) << 5, (ty + t.vertices[k].Ypixel) << 5 };
vCount++;
}
}
for (int j = 0; j < d.tCount; j++) {
auto &f = d.triangles[j];
auto &t = level.objectTextures[f.texture];
int tile = t.tileAndFlag & 0x7FFF;
int tx = (tile % 4) * 256;
int ty = (tile / 4) * 256;
int vIndex = vCount - vStart;
indices[iCount + 0] = vIndex + 0;
indices[iCount + 1] = vIndex + 1;
indices[iCount + 2] = vIndex + 2;
iCount += 3;
for (int k = 0; k < 3; k++) {
auto &v = d.vertices[f.vertices[k]];
uint8 a = 255 - (v.lighting >> 5);
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z };
vertices[vCount].color = { a, a, a, 255 };
vertices[vCount].normal = { 0, 0, 0, 255 };
vertices[vCount].texCoord = { (tx + t.vertices[k].Xpixel) << 5, (ty + t.vertices[k].Ypixel) << 5 };
vCount++;
}
}
}
// objects geometry
mCount = 0;
ptr = (TR::Mesh*)level.meshData;
while ( ((int)ptr - (int)level.meshData) < level.meshDataSize * sizeof(uint16) ) {
MeshInfo &info = meshInfo[mCount++];
info.offset = (int)ptr - (int)level.meshData;
info.vStart = vCount;
info.iStart = iCount;
info.center = ptr->center;
info.radius = ptr->radius;
TR::Vertex *mVertices = (TR::Vertex*)&ptr->vertices;
OFFSET(ptr->vCount * sizeof(TR::Vertex));
TR::Vertex *normals = NULL;
int16 *lights = NULL;
int nCount = ptr->nCount;
if (ptr->nCount > 0) {
normals = (TR::Vertex*)&ptr->normals;
OFFSET(ptr->nCount * sizeof(TR::Vertex));
} else {
lights = (int16*)&ptr->lights;
OFFSET(-ptr->nCount * sizeof(int16));
}
int vStart = vCount;
// rectangles
for (int j = 0; j < ptr->rCount; j++) {
auto &f = ((TR::Rectangle*)&ptr->rectangles)[j];
auto &t = level.objectTextures[f.texture];
int tile = t.tileAndFlag & 0x7FFF;
int tx = (tile % 4) * 256;
int ty = (tile / 4) * 256;
int vIndex = vCount - vStart;
indices[iCount + 0] = vIndex + 0;
indices[iCount + 1] = vIndex + 1;
indices[iCount + 2] = vIndex + 2;
indices[iCount + 3] = vIndex + 0;
indices[iCount + 4] = vIndex + 2;
indices[iCount + 5] = vIndex + 3;
iCount += 6;
for (int k = 0; k < 4; k++) {
auto &v = mVertices[f.vertices[k]];
vertices[vCount].coord = { v.x, v.y, v.z };
if (nCount > 0) {
vertices[vCount].normal = packNormal(normals[f.vertices[k]]);
vertices[vCount].color = { 255, 255, 255, 255 };
} else {
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
vertices[vCount].normal = { 0, 0, 0, 255 };
vertices[vCount].color = { a, a, a, 255 };
}
vertices[vCount].texCoord = { (tx + t.vertices[k].Xpixel) << 5, (ty + t.vertices[k].Ypixel) << 5 };
vCount++;
}
}
OFFSET(ptr->rCount * sizeof(TR::Rectangle));
// triangles
for (int j = 0; j < ptr->tCount; j++) {
auto &f = ((TR::Triangle*)&ptr->triangles)[j];
auto &t = level.objectTextures[f.texture];
int tile = t.tileAndFlag & 0x7FFF;
int tx = (tile % 4) * 256;
int ty = (tile / 4) * 256;
int vIndex = vCount - vStart;
indices[iCount + 0] = vIndex + 0;
indices[iCount + 1] = vIndex + 1;
indices[iCount + 2] = vIndex + 2;
iCount += 3;
for (int k = 0; k < 3; k++) {
auto &v = mVertices[f.vertices[k]];
vertices[vCount].coord = { v.x, v.y, v.z };
if (nCount > 0) {
vertices[vCount].normal = packNormal(normals[f.vertices[k]]);
vertices[vCount].color = { 255, 255, 255, 255 };
} else {
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
vertices[vCount].normal = { 0, 0, 0, 255 };
vertices[vCount].color = { a, a, a, 255 };
}
vertices[vCount].texCoord = { (tx + t.vertices[k].Xpixel) << 5, (ty + t.vertices[k].Ypixel) << 5 };
vCount++;
}
}
OFFSET(ptr->tCount * sizeof(TR::Triangle));
// color rectangles
for (int j = 0; j < ptr->crCount; j++) {
auto &f = ((TR::Rectangle*)&ptr->crectangles)[j];
auto &c = level.palette[f.texture & 0xFF];
int vIndex = vCount - vStart;
indices[iCount + 0] = vIndex + 0;
indices[iCount + 1] = vIndex + 1;
indices[iCount + 2] = vIndex + 2;
indices[iCount + 3] = vIndex + 0;
indices[iCount + 4] = vIndex + 2;
indices[iCount + 5] = vIndex + 3;
iCount += 6;
for (int k = 0; k < 4; k++) {
auto &v = mVertices[f.vertices[k]];
vertices[vCount].coord = { v.x, v.y, v.z };
if (nCount > 0) {
vertices[vCount].normal = packNormal(normals[f.vertices[k]]);
vertices[vCount].color = { c.r, c.g, c.b, 255 };
} else {
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
vertices[vCount].normal = { 0, 0, 0, 255 };
vertices[vCount].color = { a, a, a, 255 }; // TODO: apply color
}
vertices[vCount].texCoord = { 1022 << 5, 1022 << 5 };
vCount++;
}
}
OFFSET(ptr->crCount * sizeof(TR::Rectangle));
// color triangles
for (int j = 0; j < ptr->ctCount; j++) {
auto &f = ((TR::Triangle*)&ptr->ctriangles)[j];
auto &c = level.palette[f.texture & 0xFF];
int vIndex = vCount - vStart;
indices[iCount + 0] = vIndex + 0;
indices[iCount + 1] = vIndex + 1;
indices[iCount + 2] = vIndex + 2;
iCount += 3;
for (int k = 0; k < 3; k++) {
auto &v = mVertices[f.vertices[k]];
vertices[vCount].coord = { v.x, v.y, v.z };
if (nCount > 0) {
vertices[vCount].normal = packNormal(normals[f.vertices[k]]);
vertices[vCount].color = { c.r, c.g, c.b, 255 };
} else {
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
vertices[vCount].normal = { 0, 0, 0, 255 };
vertices[vCount].color = { a, a, a, 255 }; // TODO: apply color
}
vertices[vCount].texCoord = { 1022 << 5, 1022 << 5 };
vCount++;
}
}
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
ptr = (TR::Mesh*)(((int)ptr + 3) & ~3);
info.iCount = iCount - info.iStart;
}
mesh = new Mesh(indices, iCount, vertices, vCount);
delete[] indices;
delete[] vertices;
}
TR::StaticMesh* getMeshByID(int id) {
@@ -74,213 +450,56 @@ struct Level {
#define SCALE (1.0f / 1024.0f / 2.0f)
void renderRoom(const TR::Room &room) {
glPushMatrix();
glTranslatef(room.info.x, 0.0f, room.info.z);
void renderRoom(int index) {
TR::Room &room = level.rooms[index];
// 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);
glVertex3sv((GLshort*)&v.vertex);
}
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);
glVertex3sv((GLshort*)&v.vertex);
}
glEnd();
}
glPopMatrix();
mat4 m = Core::mModel;
Core::mModel.translate(vec3(room.info.x, 0.0f, room.info.z));
shader->setParam(uModel, Core::mModel);
mesh->render(rangeRooms[index]);
Core::mModel = m;
Core::color = vec4(1.0f);
shader->setParam(uColor, Core::color);
// 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();
glTranslatef(rMesh.x, rMesh.y, rMesh.z);
glRotatef((rMesh.rotation >> 14) * 90.0f, 0, 1, 0);
renderMesh(sMesh->mesh, vec3(a));
mat4 m = Core::mModel;
Core::mModel.translate(vec3(rMesh.x, rMesh.y, rMesh.z));
Core::mModel.rotateY((rMesh.rotation >> 14) * 90.0f * DEG2RAD);
glPopMatrix();
getLight(vec3(rMesh.x, rMesh.y, rMesh.z), index);
shader->setParam(uAmbient, Core::ambient);
shader->setParam(uLightPos, Core::lightPos);
shader->setParam(uLightColor, Core::lightColor);
renderMesh(sMesh->mesh);
Core::mModel = m;
}
/*
// sprites
Core::setBlending(bmAlpha);
for (int j = 0; j < room.data.sCount; j++)
renderSprite(room, room.data.sprites[j]);
*/
}
void renderMesh(uint32 meshOffset, const vec3 &color) {
// remap mesh
#define OFFSET(bytes) (ptr = (TR::Mesh*)((char*)ptr + bytes - sizeof(char*)))
void renderMesh(uint32 meshOffset) {
if (!level.meshOffsets[meshOffset] && meshOffset)
return;
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();
glNormal3sv((GLshort*)&vn);
} 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);
glVertex3sv((GLshort*)&v);
for (int i = 0; i < mCount; i++)
if (meshInfo[i].offset == level.meshOffsets[meshOffset]) {
shader->setParam(uModel, Core::mModel);
mesh->render(meshInfo[i]);
break;
}
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();
glNormal3sv((GLshort*)&vn);
} 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);
glVertex3sv((GLshort*)&v);
}
glEnd();
}
glDisable(GL_TEXTURE_2D);
// debug normals
// triangles (colored)
glBegin(GL_TRIANGLES);
for (int j = 0; j < mesh.ctCount; j++) {
auto &f = mesh.ctriangles[j];
auto &c = level.palette[f.texture & 0xFF];
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);
glNormal3sv((GLshort*)&vn);
} 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);
}
glVertex3sv((GLshort*)&v);
}
}
glEnd();
// rectangles (colored)
glBegin(GL_QUADS);
for (int j = 0; j < mesh.crCount; j++) {
auto &f = mesh.crectangles[j];
auto &c = level.palette[f.texture & 0xFF];
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);
glNormal3sv((GLshort*)&vn);
} 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);
}
glVertex3sv((GLshort*)&v);
}
}
glEnd();
glEnable(GL_TEXTURE_2D);
if (mesh.nCount > 0)
glDisable(GL_LIGHTING);
}
void renderSprite(const TR::SpriteTexture &sprite) {
@@ -299,7 +518,7 @@ struct Level {
p[2] = right * sprite.l + up * sprite.t;
p[3] = right * sprite.r + up * sprite.t;
bindTexture(sprite.tile);
// bindTexture(sprite.tile);
glBegin(GL_QUADS);
glTexCoord2f(u0, v1);
glVertex3fv((GLfloat*)&p[0]);
@@ -363,13 +582,8 @@ struct Level {
return ma.getRot().slerp(mb.getRot(), t).normal();
}
float debugTime = 0.0f;
void renderModel(const TR::Model &model) {
mat4 m;
m.identity();
void renderModel(const TR::Model &model) {
TR::Animation *anim = &level.anims[model.animation];
float fTime = time;
@@ -377,8 +591,6 @@ struct Level {
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;
@@ -422,6 +634,8 @@ struct Level {
int sIndex = 0;
mat4 stack[20];
mat4 m;
m.identity();
m.translate(vec3(frameA->x, frameA->y, frameA->z).lerp(vec3(frameB->x, frameB->y, frameB->z), k));
for (int i = 0; i < model.mCount; i++) {
@@ -447,39 +661,67 @@ struct Level {
// m.rotateX(angle.x);
// m.rotateZ(angle.z);
glPushMatrix();
glMultMatrixf((GLfloat*)&m);
renderMesh(model.mStart + i, vec3(1.0f));
glPopMatrix();
mat4 tmp = Core::mModel;
Core::mModel = Core::mModel * m;
renderMesh(model.mStart + i);
Core::mModel = tmp;
}
}
void getLight(const vec3 &pos, int room) {
int idx = -1;
float dist;
for (int i = 0; i < level.rooms[room].lightsCount; i++) {
TR::Room::Light &light = level.rooms[room].lights[i];
float d = (pos - vec3(light.x, light.y, light.z)).length();
if (idx == -1 || d < dist) {
idx = i;
dist = d;
}
}
if (idx > -1) {
TR::Room::Light &light = level.rooms[room].lights[idx];
float c = level.rooms[room].lights[idx].Intensity / 8191.0f;
Core::lightPos = vec3(-light.x, -light.y, light.z);
Core::lightColor = vec4(c, c, c, 0.0f);
} else {
Core::lightPos = vec3(0.0f);
Core::lightColor = vec4(0.0f);
}
Core::ambient = vec3(1.0f - level.rooms[room].ambient / 8191.0f);
}
void renderEntity(const TR::Entity &entity) {
glPushMatrix();
glTranslatef(entity.x, entity.y, entity.z);
mat4 m = Core::mModel;
Core::mModel.translate(vec3(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);
float c = (entity.intensity > -1) ? (1.0f - entity.intensity / (float)0x1FFF) : 1.0f;
float l = 1.0f;
Core::color = vec4(c, c, c, 1.0);
getLight(vec3(entity.x, entity.y, entity.z), entity.room);
shader->setParam(uColor, Core::color);
shader->setParam(uAmbient, Core::ambient);
shader->setParam(uLightPos, Core::lightPos);
shader->setParam(uLightColor, Core::lightColor);
for (int i = 0; i < level.modelsCount; i++)
if (entity.id == level.models[i].id) {
glRotatef((entity.rotation >> 14) * 90.0f, 0, 1, 0);
Core::mModel.rotateY(entity.rotation / 16384.0f * PI * 0.5f);
// Core::mModel.rotateY((entity.rotation >> 14) * 90.0f * DEG2RAD);
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();
*/
Core::mModel = m;
}
@@ -749,22 +991,33 @@ struct Level {
}
void render() {
shader->bind();
atlas->bind(0);
mesh->bind();
shader->setParam(uViewProj, Core::mViewProj);
shader->setParam(uModel, Core::mModel);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.9f);
glEnable(GL_TEXTURE_2D);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHT0);
//glEnable(GL_LIGHT0);
Core::setCulling(cfFront);
glColor3f(1, 1, 1);
glScalef(-SCALE, -SCALE, SCALE);
Core::mModel.identity();
Core::mModel.scale(vec3(-SCALE, -SCALE, SCALE));
Core::color = vec4(1.0f);
Core::ambient = vec3(0.0f);
shader->setParam(uColor, Core::color);
shader->setParam(uAmbient, Core::ambient);
for (int i = 0; i < level.roomsCount; i++)
renderRoom(level.rooms[i]);
renderRoom(i);
for (int i = 0; i < level.entitiesCount; i++)
renderEntity(level.entities[i]);

View File

@@ -6,30 +6,30 @@
typedef unsigned short Index;
struct Vertex {
vec3 coord;
vec3 normal;
vec2 texCoord;
short3 coord;
short2 texCoord;
ubyte4 normal;
ubyte4 color;
};
struct MeshRange {
int iStart;
int iCount;
int vStart;
};
struct Mesh {
GLuint ID[2];
int iCount;
int vCount;
/*
Mesh(const char *name) {
Stream stream(name);
Index *indices = stream.readArray<Index> (stream.read(iCount));
Vertex *vertices = stream.readArray<Vertex>(stream.read(vCount));
Mesh(Index *indices, int iCount, Vertex *vertices, int vCount) : iCount(iCount), vCount(vCount) {
glGenBuffers(2, ID);
bind();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iCount * sizeof(Index), indices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, vCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
delete[] indices;
delete[] vertices;
}
*/
virtual ~Mesh() {
glDeleteBuffers(2, ID);
}
@@ -37,25 +37,20 @@ struct Mesh {
void bind() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ID[0]);
glBindBuffer(GL_ARRAY_BUFFER, ID[1]);
}
void render() {
bind();
glEnableVertexAttribArray(aCoord);
glEnableVertexAttribArray(aNormal);
glEnableVertexAttribArray(aTexCoord);
glEnableVertexAttribArray(aNormal);
glEnableVertexAttribArray(aColor);
}
Vertex *v = NULL;
glVertexAttribPointer(aCoord, 3, GL_FLOAT, false, sizeof(Vertex), &v->coord);
glVertexAttribPointer(aNormal, 3, GL_FLOAT, false, sizeof(Vertex), &v->normal);
glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, false, sizeof(Vertex), &v->texCoord);
glDrawElements(GL_TRIANGLES, iCount, GL_UNSIGNED_SHORT, NULL);
glDisableVertexAttribArray(aCoord);
glDisableVertexAttribArray(aNormal);
glDisableVertexAttribArray(aTexCoord);
void render(const MeshRange &range) {
Vertex *v = (Vertex*)(range.vStart * sizeof(Vertex));
glVertexAttribPointer(aCoord, 3, GL_SHORT, false, sizeof(Vertex), &v->coord);
glVertexAttribPointer(aTexCoord, 2, GL_SHORT, true, sizeof(Vertex), &v->texCoord);
glVertexAttribPointer(aNormal, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->normal);
glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->color);
glDrawElements(GL_TRIANGLES, range.iCount, GL_UNSIGNED_SHORT, (GLvoid*)(range.iStart * sizeof(Index)));
}
};

View File

@@ -3,25 +3,19 @@
#include "core.h"
enum AttribType { aCoord, aTexCoord, aNormal, aMAX };
enum SamplerType { sTex0, sMAX };
enum UniformType { uViewProj, uModel, uLightVec, uMAX };
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
enum SamplerType { sDiffuse, sMAX };
enum UniformType { uViewProj, uModel, uColor, uAmbient, uLightPos, uLightColor, uMAX };
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal" };
const char *SamplerName[sMAX] = { "sTex0" };
const char *UniformName[uMAX] = { "uViewProj", "uModel", "uLightVec" };
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
const char *SamplerName[sMAX] = { "sDiffuse" };
const char *UniformName[uMAX] = { "uViewProj", "uModel", "uColor", "uAmbient", "uLightPos", "uLightColor" };
struct Shader {
GLuint ID;
GLint uID[uMAX];
Shader(const char *name, int param) {
Stream stream(name);
char *text = new char[stream.size + 1];
stream.read(text, stream.size);
text[stream.size] = '\0';
Shader(const char *text) {
#define GLSL_DEFINE "#version 110\n"
const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
@@ -44,7 +38,6 @@ struct Shader {
glAttachShader(ID, obj);
glDeleteShader(obj);
}
delete[] text;
for (int at = 0; at < aMAX; at++)
glBindAttribLocation(ID, at, AttribName[at]);
@@ -68,8 +61,6 @@ struct Shader {
void bind() {
glUseProgram(ID);
setParam(uViewProj, Core::mViewProj);
setParam(uModel, Core::mModel);
}
void setParam(UniformType uType, const vec3 &value, int count = 1) {

View File

@@ -31,6 +31,18 @@ typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
struct ubyte4 {
uint8 x, y, z, w;
};
struct short2 {
int16 x, y;
};
struct short3 {
int16 x, y, z;
};
template <typename T>
inline const T& min(const T &a, const T &b) {
return a < b ? a : b;
@@ -52,8 +64,9 @@ struct vec2 {
vec2 operator * (float s) const { return vec2(x*s, y*s); }
float dot(const vec2 &v) const { return x*v.x + y*v.y; }
float cross(const vec2 &v) const { return x*v.y - y*v.x; }
float length() const { return sqrtf(dot(*this)); }
vec2 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
float length2() const { return dot(*this); }
float length() const { return sqrtf(length2()); }
vec2 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
};
struct vec3 {
@@ -68,11 +81,11 @@ struct vec3 {
vec3 operator * (const vec3 &v) const { return vec3(x*v.x, y*v.y, z*v.z); }
vec3 operator * (float s) const { return vec3(x*s, y*s, z*s); }
float dot(const vec3 &v) const { return x*v.x + y*v.y + z*v.z; }
vec3 cross(const vec3 &v) const { return vec3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x); }
float length() const { return sqrtf(x*x + y*y + z*z); }
vec3 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
float length2() const { return dot(*this); }
float length() const { return sqrtf(length2()); }
vec3 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
vec3 lerp(const vec3 &v, const float t) const {
return *this + (v - *this) * t;
@@ -86,6 +99,7 @@ struct vec4 {
};
vec4() {}
vec4(float s) : x(s), y(s), z(s), w(s) {}
vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
};
@@ -437,23 +451,24 @@ struct Stream {
pos += offset;
}
int read(void *data, int size) {
int raw(void *data, int size) {
pos += size;
return fread(data, 1, size, f);
}
template <typename T>
T& read(T &x) {
read(&x, sizeof(x));
raw(&x, sizeof(x));
return x;
}
template <typename T>
T* readArray(T *&a, int count) {
if (!count)
return NULL;
a = new T[count];
read(a, count * sizeof(T));
T* read(T *&a, int count) {
if (count) {
a = new T[count];
raw(a, count * sizeof(T));
} else
a = NULL;
return a;
}
};

View File

@@ -1,3 +1,7 @@
#ifdef _DEBUG
#include "crtdbg.h"
#endif
#include "game.h"
DWORD getTime() {
@@ -171,6 +175,12 @@ void freeGL(HGLRC hRC) {
}
int main() {
#ifdef _DEBUG
_CrtMemState _ms;
_CrtMemCheckpoint(&_ms);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
#endif
RECT r = { 0, 0, 1280, 720 };
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
@@ -223,6 +233,10 @@ int main() {
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
#ifdef _DEBUG
_CrtMemDumpAllObjectsSince(&_ms);
system("pause");
#endif
return 0;
}