diff --git a/src/controller.h b/src/controller.h index b4ce5ed..9b24449 100644 --- a/src/controller.h +++ b/src/controller.h @@ -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; } }; diff --git a/src/core.h b/src/core.h index 0c0b9ef..3308182 100644 --- a/src/core.h +++ b/src/core.h @@ -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" diff --git a/src/format.h b/src/format.h index 4a0b443..6fe2e5d 100644 --- a/src/format.h +++ b/src/format.h @@ -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; diff --git a/src/level.h b/src/level.h index 780e8d6..26474b8 100644 --- a/src/level.h +++ b/src/level.h @@ -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]); diff --git a/src/mesh.h b/src/mesh.h index 07db7d6..1fc5a89 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -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 (stream.read(iCount)); - Vertex *vertices = stream.readArray(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))); } }; diff --git a/src/shader.h b/src/shader.h index 9901496..73954e8 100644 --- a/src/shader.h +++ b/src/shader.h @@ -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) { diff --git a/src/utils.h b/src/utils.h index 1ca03ef..0283685 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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 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 T& read(T &x) { - read(&x, sizeof(x)); + raw(&x, sizeof(x)); return x; } template - 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; } }; diff --git a/src/win/main.cpp b/src/win/main.cpp index 002199d..6568f1e 100644 --- a/src/win/main.cpp +++ b/src/win/main.cpp @@ -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; } \ No newline at end of file