mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-12 08:04:09 +02:00
add VBO support
add shaders support todo: animated textures, billboards
This commit is contained in:
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
struct Controller {
|
struct Controller {
|
||||||
TR::Level *level;
|
TR::Level *level;
|
||||||
|
int entity;
|
||||||
|
|
||||||
TR::Animation *anim;
|
TR::Animation *anim;
|
||||||
float fTime;
|
float fTime;
|
||||||
|
|
||||||
@@ -14,9 +16,13 @@ struct Controller {
|
|||||||
int state; // LaraState
|
int state; // LaraState
|
||||||
int lastFrame;
|
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];
|
anim = &level->anims[0];
|
||||||
lastFrame = 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() {
|
void update() {
|
||||||
@@ -181,8 +187,43 @@ struct Controller {
|
|||||||
float speed = anim->speed.toFloat() + anim->accel.toFloat() * (fTime * 30.0f);
|
float speed = anim->speed.toFloat() + anim->accel.toFloat() * (fTime * 30.0f);
|
||||||
pos = pos + vec3(sinf(d), 0, cosf(d)) * (speed * Core::deltaTime * 30.0f);
|
pos = pos + vec3(sinf(d), 0, cosf(d)) * (speed * Core::deltaTime * 30.0f);
|
||||||
|
|
||||||
|
|
||||||
lastFrame = fIndex;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -50,6 +50,10 @@ namespace Core {
|
|||||||
int width, height;
|
int width, height;
|
||||||
float deltaTime;
|
float deltaTime;
|
||||||
mat4 mView, mProj, mViewProj, mModel;
|
mat4 mView, mProj, mViewProj, mModel;
|
||||||
|
vec3 lightPos;
|
||||||
|
vec4 lightColor;
|
||||||
|
vec3 ambient;
|
||||||
|
vec4 color;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
76
src/format.h
76
src/format.h
@@ -211,7 +211,7 @@ namespace TR {
|
|||||||
int16 lightsCount;
|
int16 lightsCount;
|
||||||
struct Light {
|
struct Light {
|
||||||
int32 x, y, z; // Position of light, in world coordinates
|
int32 x, y, z; // Position of light, in world coordinates
|
||||||
uint16 Intensity1; // Light intensity
|
uint16 Intensity; // Light intensity
|
||||||
uint32 fade; // Falloff value
|
uint32 fade; // Falloff value
|
||||||
} *lights;
|
} *lights;
|
||||||
|
|
||||||
@@ -499,7 +499,7 @@ namespace TR {
|
|||||||
// read version
|
// read version
|
||||||
stream.read(version);
|
stream.read(version);
|
||||||
// tiles
|
// tiles
|
||||||
stream.readArray(tiles, stream.read(tilesCount));
|
stream.read(tiles, stream.read(tilesCount));
|
||||||
stream.read(unused);
|
stream.read(unused);
|
||||||
// rooms
|
// rooms
|
||||||
rooms = new Room[stream.read(roomsCount)];
|
rooms = new Room[stream.read(roomsCount)];
|
||||||
@@ -511,69 +511,69 @@ namespace TR {
|
|||||||
// room data
|
// room data
|
||||||
stream.read(d.size);
|
stream.read(d.size);
|
||||||
int pos = stream.pos;
|
int pos = stream.pos;
|
||||||
stream.readArray(d.vertices, stream.read(d.vCount));
|
stream.read(d.vertices, stream.read(d.vCount));
|
||||||
stream.readArray(d.rectangles, stream.read(d.rCount));
|
stream.read(d.rectangles, stream.read(d.rCount));
|
||||||
stream.readArray(d.triangles, stream.read(d.tCount));
|
stream.read(d.triangles, stream.read(d.tCount));
|
||||||
stream.readArray(d.sprites, stream.read(d.sCount));
|
stream.read(d.sprites, stream.read(d.sCount));
|
||||||
stream.setPos(pos + d.size * 2);
|
stream.setPos(pos + d.size * 2);
|
||||||
// portals
|
// portals
|
||||||
stream.readArray(r.portals, stream.read(r.portalsCount));
|
stream.read(r.portals, stream.read(r.portalsCount));
|
||||||
// sectors
|
// sectors
|
||||||
stream.read(r.zSectors);
|
stream.read(r.zSectors);
|
||||||
stream.read(r.xSectors);
|
stream.read(r.xSectors);
|
||||||
stream.readArray(r.sectors, r.zSectors * r.xSectors);
|
stream.read(r.sectors, r.zSectors * r.xSectors);
|
||||||
// ambient light luminance
|
// ambient light luminance
|
||||||
stream.read(r.ambient);
|
stream.read(r.ambient);
|
||||||
// lights
|
// lights
|
||||||
stream.readArray(r.lights, stream.read(r.lightsCount));
|
stream.read(r.lights, stream.read(r.lightsCount));
|
||||||
// meshes
|
// meshes
|
||||||
stream.readArray(r.meshes, stream.read(r.meshesCount));
|
stream.read(r.meshes, stream.read(r.meshesCount));
|
||||||
stream.read(r.alternateRoom);
|
stream.read(r.alternateRoom);
|
||||||
stream.read(r.flags);
|
stream.read(r.flags);
|
||||||
}
|
}
|
||||||
// floors
|
// floors
|
||||||
stream.readArray(floors, stream.read(floorsCount));
|
stream.read(floors, stream.read(floorsCount));
|
||||||
// meshes
|
// meshes
|
||||||
stream.readArray(meshData, stream.read(meshDataSize));
|
stream.read(meshData, stream.read(meshDataSize));
|
||||||
stream.readArray(meshOffsets, stream.read(meshOffsetsCount));
|
stream.read(meshOffsets, stream.read(meshOffsetsCount));
|
||||||
// animations
|
// animations
|
||||||
stream.readArray(anims, stream.read(animsCount));
|
stream.read(anims, stream.read(animsCount));
|
||||||
stream.readArray(states, stream.read(statesCount));
|
stream.read(states, stream.read(statesCount));
|
||||||
stream.readArray(ranges, stream.read(rangesCount));
|
stream.read(ranges, stream.read(rangesCount));
|
||||||
stream.readArray(commands, stream.read(commandsCount));
|
stream.read(commands, stream.read(commandsCount));
|
||||||
stream.readArray(nodesData, stream.read(nodesDataSize));
|
stream.read(nodesData, stream.read(nodesDataSize));
|
||||||
stream.readArray(frameData, stream.read(frameDataSize));
|
stream.read(frameData, stream.read(frameDataSize));
|
||||||
// models
|
// models
|
||||||
stream.readArray(models, stream.read(modelsCount));
|
stream.read(models, stream.read(modelsCount));
|
||||||
stream.readArray(staticMeshes, stream.read(staticMeshesCount));
|
stream.read(staticMeshes, stream.read(staticMeshesCount));
|
||||||
// textures & UV
|
// textures & UV
|
||||||
stream.readArray(objectTextures, stream.read(objectTexturesCount));
|
stream.read(objectTextures, stream.read(objectTexturesCount));
|
||||||
stream.readArray(spriteTextures, stream.read(spriteTexturesCount));
|
stream.read(spriteTextures, stream.read(spriteTexturesCount));
|
||||||
stream.readArray(spriteSequences, stream.read(spriteSequencesCount));
|
stream.read(spriteSequences, stream.read(spriteSequencesCount));
|
||||||
// cameras
|
// cameras
|
||||||
stream.readArray(camera, stream.read(camerasCount));
|
stream.read(camera, stream.read(camerasCount));
|
||||||
// sound sources
|
// sound sources
|
||||||
stream.readArray(soundSources, stream.read(soundSourcesCount));
|
stream.read(soundSources, stream.read(soundSourcesCount));
|
||||||
// AI
|
// AI
|
||||||
stream.readArray(boxes, stream.read(boxesCount));
|
stream.read(boxes, stream.read(boxesCount));
|
||||||
stream.readArray(overlaps, stream.read(overlapsCount));
|
stream.read(overlaps, stream.read(overlapsCount));
|
||||||
stream.readArray(zones, boxesCount);
|
stream.read(zones, boxesCount);
|
||||||
// animated textures
|
// animated textures
|
||||||
stream.readArray(animTexturesData, stream.read(animTexturesDataSize));
|
stream.read(animTexturesData, stream.read(animTexturesDataSize));
|
||||||
// entities (enemies, items, lara etc.)
|
// entities (enemies, items, lara etc.)
|
||||||
stream.readArray(entities, stream.read(entitiesCount));
|
stream.read(entities, stream.read(entitiesCount));
|
||||||
// palette
|
// palette
|
||||||
stream.seek(32 * 256); // skip lightmap palette
|
stream.seek(32 * 256); // skip lightmap palette
|
||||||
stream.readArray(palette, 256);
|
stream.read(palette, 256);
|
||||||
// cinematic frames for cameras
|
// cinematic frames for cameras
|
||||||
stream.readArray(cameraFrames, stream.read(cameraFramesCount));
|
stream.read(cameraFrames, stream.read(cameraFramesCount));
|
||||||
// demo data
|
// demo data
|
||||||
stream.readArray(demoData, stream.read(demoDataSize));
|
stream.read(demoData, stream.read(demoDataSize));
|
||||||
// sounds
|
// sounds
|
||||||
stream.readArray(soundsMap, 256);
|
stream.read(soundsMap, 256);
|
||||||
stream.readArray(soundsInfo, stream.read(soundsInfoCount));
|
stream.read(soundsInfo, stream.read(soundsInfoCount));
|
||||||
stream.readArray(soundData, stream.read(soundDataSize));
|
stream.read(soundData, stream.read(soundDataSize));
|
||||||
stream.readArray(soundOffsets, stream.read(soundOffsetsCount));
|
stream.read(soundOffsets, stream.read(soundOffsetsCount));
|
||||||
|
|
||||||
// modify palette colors from 6-bit Amiga colorspace
|
// modify palette colors from 6-bit Amiga colorspace
|
||||||
int m = 0;
|
int m = 0;
|
||||||
|
705
src/level.h
705
src/level.h
@@ -6,19 +6,103 @@
|
|||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "controller.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 {
|
struct Level {
|
||||||
TR::Level level;
|
TR::Level level;
|
||||||
|
Shader *shader;
|
||||||
Texture *atlas;
|
Texture *atlas;
|
||||||
float time;
|
Mesh *mesh;
|
||||||
|
|
||||||
Controller *lara;
|
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) {
|
Level(const char *name) : level(Stream(name)), time(0.0f) {
|
||||||
|
shader = new Shader(SHADER);
|
||||||
initAtlas();
|
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() {
|
~Level() {
|
||||||
|
delete shader;
|
||||||
delete atlas;
|
delete atlas;
|
||||||
|
delete mesh;
|
||||||
|
delete[] rangeRooms;
|
||||||
|
delete[] meshInfo;
|
||||||
|
|
||||||
|
delete lara;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAtlas() {
|
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);
|
atlas = new Texture(1024, 1024, 0, data);
|
||||||
delete[] data;
|
delete[] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bindTexture(int tile) {
|
void initMesh() {
|
||||||
|
// TODO: sort by texture attribute (t.attribute == 2 ? bmAdd : bmAlpha)
|
||||||
|
|
||||||
glMatrixMode(GL_TEXTURE);
|
rangeRooms = new MeshRange[level.roomsCount];
|
||||||
glLoadIdentity();
|
|
||||||
glTranslatef((tile % 4) * 0.25f, (tile / 4) * 0.25f, 0.0f);
|
int iCount = 0, vCount = 0;
|
||||||
glScalef(0.25f, 0.25f, 1.0f);
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
// 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++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTexture(int objTexture) {
|
for (int j = 0; j < d.tCount; j++) {
|
||||||
auto &t = level.objectTextures[objTexture];
|
auto &f = d.triangles[j];
|
||||||
Core::setBlending(t.attribute == 2 ? bmAdd : bmAlpha);
|
auto &t = level.objectTextures[f.texture];
|
||||||
bindTexture(t.tileAndFlag & 0x7FFF);
|
|
||||||
|
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) {
|
TR::StaticMesh* getMeshByID(int id) {
|
||||||
@@ -74,213 +450,56 @@ struct Level {
|
|||||||
|
|
||||||
#define SCALE (1.0f / 1024.0f / 2.0f)
|
#define SCALE (1.0f / 1024.0f / 2.0f)
|
||||||
|
|
||||||
void renderRoom(const TR::Room &room) {
|
void renderRoom(int index) {
|
||||||
glPushMatrix();
|
TR::Room &room = level.rooms[index];
|
||||||
glTranslatef(room.info.x, 0.0f, room.info.z);
|
|
||||||
|
|
||||||
// rectangles
|
mat4 m = Core::mModel;
|
||||||
for (int j = 0; j < room.data.rCount; j++) {
|
Core::mModel.translate(vec3(room.info.x, 0.0f, room.info.z));
|
||||||
auto &f = room.data.rectangles[j];
|
shader->setParam(uModel, Core::mModel);
|
||||||
auto &t = level.objectTextures[f.texture];
|
mesh->render(rangeRooms[index]);
|
||||||
setTexture(f.texture);
|
Core::mModel = m;
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
Core::color = vec4(1.0f);
|
||||||
for (int k = 0; k < 4; k++) {
|
shader->setParam(uColor, Core::color);
|
||||||
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();
|
|
||||||
|
|
||||||
// meshes
|
// meshes
|
||||||
float a = 1.0f - room.ambient / 8191.0f;
|
|
||||||
|
|
||||||
for (int j = 0; j < room.meshesCount; j++) {
|
for (int j = 0; j < room.meshesCount; j++) {
|
||||||
auto rMesh = room.meshes[j];
|
auto rMesh = room.meshes[j];
|
||||||
auto sMesh = getMeshByID(rMesh.meshID);
|
auto sMesh = getMeshByID(rMesh.meshID);
|
||||||
ASSERT(sMesh != NULL);
|
ASSERT(sMesh != NULL);
|
||||||
|
|
||||||
glPushMatrix();
|
mat4 m = Core::mModel;
|
||||||
glTranslatef(rMesh.x, rMesh.y, rMesh.z);
|
Core::mModel.translate(vec3(rMesh.x, rMesh.y, rMesh.z));
|
||||||
glRotatef((rMesh.rotation >> 14) * 90.0f, 0, 1, 0);
|
Core::mModel.rotateY((rMesh.rotation >> 14) * 90.0f * DEG2RAD);
|
||||||
|
|
||||||
renderMesh(sMesh->mesh, vec3(a));
|
getLight(vec3(rMesh.x, rMesh.y, rMesh.z), index);
|
||||||
|
shader->setParam(uAmbient, Core::ambient);
|
||||||
|
shader->setParam(uLightPos, Core::lightPos);
|
||||||
|
shader->setParam(uLightColor, Core::lightColor);
|
||||||
|
|
||||||
glPopMatrix();
|
renderMesh(sMesh->mesh);
|
||||||
|
|
||||||
|
Core::mModel = m;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
// sprites
|
// sprites
|
||||||
Core::setBlending(bmAlpha);
|
Core::setBlending(bmAlpha);
|
||||||
for (int j = 0; j < room.data.sCount; j++)
|
for (int j = 0; j < room.data.sCount; j++)
|
||||||
renderSprite(room, room.data.sprites[j]);
|
renderSprite(room, room.data.sprites[j]);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void renderMesh(uint32 meshOffset, const vec3 &color) {
|
void renderMesh(uint32 meshOffset) {
|
||||||
// remap mesh
|
if (!level.meshOffsets[meshOffset] && meshOffset)
|
||||||
#define OFFSET(bytes) (ptr = (TR::Mesh*)((char*)ptr + bytes - sizeof(char*)))
|
return;
|
||||||
|
|
||||||
TR::Mesh *ptr = (TR::Mesh*)((char*)level.meshData + level.meshOffsets[meshOffset]);
|
for (int i = 0; i < mCount; i++)
|
||||||
TR::Mesh mesh;
|
if (meshInfo[i].offset == level.meshOffsets[meshOffset]) {
|
||||||
mesh.center = ptr->center;
|
shader->setParam(uModel, Core::mModel);
|
||||||
mesh.radius = ptr->radius;
|
mesh->render(meshInfo[i]);
|
||||||
mesh.vCount = ptr->vCount;
|
break;
|
||||||
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);
|
|
||||||
}
|
|
||||||
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) {
|
void renderSprite(const TR::SpriteTexture &sprite) {
|
||||||
@@ -299,7 +518,7 @@ struct Level {
|
|||||||
p[2] = right * sprite.l + up * sprite.t;
|
p[2] = right * sprite.l + up * sprite.t;
|
||||||
p[3] = right * sprite.r + up * sprite.t;
|
p[3] = right * sprite.r + up * sprite.t;
|
||||||
|
|
||||||
bindTexture(sprite.tile);
|
// bindTexture(sprite.tile);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glTexCoord2f(u0, v1);
|
glTexCoord2f(u0, v1);
|
||||||
glVertex3fv((GLfloat*)&p[0]);
|
glVertex3fv((GLfloat*)&p[0]);
|
||||||
@@ -364,12 +583,7 @@ struct Level {
|
|||||||
return ma.getRot().slerp(mb.getRot(), t).normal();
|
return ma.getRot().slerp(mb.getRot(), t).normal();
|
||||||
}
|
}
|
||||||
|
|
||||||
float debugTime = 0.0f;
|
|
||||||
|
|
||||||
void renderModel(const TR::Model &model) {
|
void renderModel(const TR::Model &model) {
|
||||||
mat4 m;
|
|
||||||
m.identity();
|
|
||||||
|
|
||||||
TR::Animation *anim = &level.anims[model.animation];
|
TR::Animation *anim = &level.anims[model.animation];
|
||||||
|
|
||||||
float fTime = time;
|
float fTime = time;
|
||||||
@@ -377,8 +591,6 @@ struct Level {
|
|||||||
if (model.id == ENTITY_LARA) {
|
if (model.id == ENTITY_LARA) {
|
||||||
anim = lara->anim;
|
anim = lara->anim;
|
||||||
fTime = lara->fTime;
|
fTime = lara->fTime;
|
||||||
m.translate(lara->pos);
|
|
||||||
m.rotateY(lara->angle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float k = fTime * 30.0f / anim->frameRate;
|
float k = fTime * 30.0f / anim->frameRate;
|
||||||
@@ -422,6 +634,8 @@ struct Level {
|
|||||||
int sIndex = 0;
|
int sIndex = 0;
|
||||||
mat4 stack[20];
|
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));
|
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++) {
|
for (int i = 0; i < model.mCount; i++) {
|
||||||
@@ -447,39 +661,67 @@ struct Level {
|
|||||||
// m.rotateX(angle.x);
|
// m.rotateX(angle.x);
|
||||||
// m.rotateZ(angle.z);
|
// m.rotateZ(angle.z);
|
||||||
|
|
||||||
|
mat4 tmp = Core::mModel;
|
||||||
glPushMatrix();
|
Core::mModel = Core::mModel * m;
|
||||||
glMultMatrixf((GLfloat*)&m);
|
renderMesh(model.mStart + i);
|
||||||
renderMesh(model.mStart + i, vec3(1.0f));
|
Core::mModel = tmp;
|
||||||
glPopMatrix();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
void renderEntity(const TR::Entity &entity) {
|
||||||
glPushMatrix();
|
mat4 m = Core::mModel;
|
||||||
glTranslatef(entity.x, entity.y, entity.z);
|
Core::mModel.translate(vec3(entity.x, entity.y, entity.z));
|
||||||
|
|
||||||
if (entity.intensity > -1) {
|
float c = (entity.intensity > -1) ? (1.0f - entity.intensity / (float)0x1FFF) : 1.0f;
|
||||||
float a = 1.0f - entity.intensity / (float)0x1FFF;
|
float l = 1.0f;
|
||||||
glColor3f(a, a, a);
|
|
||||||
} else
|
|
||||||
glColor3f(1, 1, 1);
|
|
||||||
|
|
||||||
|
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++)
|
for (int i = 0; i < level.modelsCount; i++)
|
||||||
if (entity.id == level.models[i].id) {
|
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]);
|
renderModel(level.models[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++)
|
for (int i = 0; i < level.spriteSequencesCount; i++)
|
||||||
if (entity.id == level.spriteSequences[i].id) {
|
if (entity.id == level.spriteSequences[i].id) {
|
||||||
renderSprite(level.spriteTextures[level.spriteSequences[i].sStart]);
|
renderSprite(level.spriteTextures[level.spriteSequences[i].sStart]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
glPopMatrix();
|
Core::mModel = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -749,22 +991,33 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void render() {
|
void render() {
|
||||||
|
shader->bind();
|
||||||
atlas->bind(0);
|
atlas->bind(0);
|
||||||
|
mesh->bind();
|
||||||
|
|
||||||
|
shader->setParam(uViewProj, Core::mViewProj);
|
||||||
|
shader->setParam(uModel, Core::mModel);
|
||||||
|
|
||||||
glEnable(GL_ALPHA_TEST);
|
glEnable(GL_ALPHA_TEST);
|
||||||
glAlphaFunc(GL_GREATER, 0.9f);
|
glAlphaFunc(GL_GREATER, 0.9f);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glEnable(GL_NORMALIZE);
|
glEnable(GL_NORMALIZE);
|
||||||
glEnable(GL_COLOR_MATERIAL);
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
glEnable(GL_LIGHT0);
|
//glEnable(GL_LIGHT0);
|
||||||
|
|
||||||
Core::setCulling(cfFront);
|
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++)
|
for (int i = 0; i < level.roomsCount; i++)
|
||||||
renderRoom(level.rooms[i]);
|
renderRoom(i);
|
||||||
|
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
renderEntity(level.entities[i]);
|
renderEntity(level.entities[i]);
|
||||||
|
49
src/mesh.h
49
src/mesh.h
@@ -6,30 +6,30 @@
|
|||||||
typedef unsigned short Index;
|
typedef unsigned short Index;
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
vec3 coord;
|
short3 coord;
|
||||||
vec3 normal;
|
short2 texCoord;
|
||||||
vec2 texCoord;
|
ubyte4 normal;
|
||||||
|
ubyte4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshRange {
|
||||||
|
int iStart;
|
||||||
|
int iCount;
|
||||||
|
int vStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mesh {
|
struct Mesh {
|
||||||
GLuint ID[2];
|
GLuint ID[2];
|
||||||
int iCount;
|
int iCount;
|
||||||
int vCount;
|
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);
|
glGenBuffers(2, ID);
|
||||||
bind();
|
bind();
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iCount * sizeof(Index), indices, GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iCount * sizeof(Index), indices, GL_STATIC_DRAW);
|
||||||
glBufferData(GL_ARRAY_BUFFER, vCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, vCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
delete[] indices;
|
|
||||||
delete[] vertices;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
virtual ~Mesh() {
|
virtual ~Mesh() {
|
||||||
glDeleteBuffers(2, ID);
|
glDeleteBuffers(2, ID);
|
||||||
}
|
}
|
||||||
@@ -37,25 +37,20 @@ struct Mesh {
|
|||||||
void bind() {
|
void bind() {
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ID[0]);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ID[0]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, ID[1]);
|
glBindBuffer(GL_ARRAY_BUFFER, ID[1]);
|
||||||
}
|
|
||||||
|
|
||||||
void render() {
|
|
||||||
bind();
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(aCoord);
|
glEnableVertexAttribArray(aCoord);
|
||||||
glEnableVertexAttribArray(aNormal);
|
|
||||||
glEnableVertexAttribArray(aTexCoord);
|
glEnableVertexAttribArray(aTexCoord);
|
||||||
|
glEnableVertexAttribArray(aNormal);
|
||||||
|
glEnableVertexAttribArray(aColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(const MeshRange &range) {
|
||||||
Vertex *v = NULL;
|
Vertex *v = (Vertex*)(range.vStart * sizeof(Vertex));
|
||||||
glVertexAttribPointer(aCoord, 3, GL_FLOAT, false, sizeof(Vertex), &v->coord);
|
glVertexAttribPointer(aCoord, 3, GL_SHORT, false, sizeof(Vertex), &v->coord);
|
||||||
glVertexAttribPointer(aNormal, 3, GL_FLOAT, false, sizeof(Vertex), &v->normal);
|
glVertexAttribPointer(aTexCoord, 2, GL_SHORT, true, sizeof(Vertex), &v->texCoord);
|
||||||
glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, false, sizeof(Vertex), &v->texCoord);
|
glVertexAttribPointer(aNormal, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->normal);
|
||||||
glDrawElements(GL_TRIANGLES, iCount, GL_UNSIGNED_SHORT, NULL);
|
glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->color);
|
||||||
|
glDrawElements(GL_TRIANGLES, range.iCount, GL_UNSIGNED_SHORT, (GLvoid*)(range.iStart * sizeof(Index)));
|
||||||
glDisableVertexAttribArray(aCoord);
|
|
||||||
glDisableVertexAttribArray(aNormal);
|
|
||||||
glDisableVertexAttribArray(aTexCoord);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
23
src/shader.h
23
src/shader.h
@@ -3,25 +3,19 @@
|
|||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
|
||||||
enum AttribType { aCoord, aTexCoord, aNormal, aMAX };
|
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
||||||
enum SamplerType { sTex0, sMAX };
|
enum SamplerType { sDiffuse, sMAX };
|
||||||
enum UniformType { uViewProj, uModel, uLightVec, uMAX };
|
enum UniformType { uViewProj, uModel, uColor, uAmbient, uLightPos, uLightColor, uMAX };
|
||||||
|
|
||||||
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal" };
|
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
|
||||||
const char *SamplerName[sMAX] = { "sTex0" };
|
const char *SamplerName[sMAX] = { "sDiffuse" };
|
||||||
const char *UniformName[uMAX] = { "uViewProj", "uModel", "uLightVec" };
|
const char *UniformName[uMAX] = { "uViewProj", "uModel", "uColor", "uAmbient", "uLightPos", "uLightColor" };
|
||||||
|
|
||||||
struct Shader {
|
struct Shader {
|
||||||
GLuint ID;
|
GLuint ID;
|
||||||
GLint uID[uMAX];
|
GLint uID[uMAX];
|
||||||
|
|
||||||
Shader(const char *name, int param) {
|
Shader(const char *text) {
|
||||||
Stream stream(name);
|
|
||||||
|
|
||||||
char *text = new char[stream.size + 1];
|
|
||||||
stream.read(text, stream.size);
|
|
||||||
text[stream.size] = '\0';
|
|
||||||
|
|
||||||
#define GLSL_DEFINE "#version 110\n"
|
#define GLSL_DEFINE "#version 110\n"
|
||||||
|
|
||||||
const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
|
const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
|
||||||
@@ -44,7 +38,6 @@ struct Shader {
|
|||||||
glAttachShader(ID, obj);
|
glAttachShader(ID, obj);
|
||||||
glDeleteShader(obj);
|
glDeleteShader(obj);
|
||||||
}
|
}
|
||||||
delete[] text;
|
|
||||||
|
|
||||||
for (int at = 0; at < aMAX; at++)
|
for (int at = 0; at < aMAX; at++)
|
||||||
glBindAttribLocation(ID, at, AttribName[at]);
|
glBindAttribLocation(ID, at, AttribName[at]);
|
||||||
@@ -68,8 +61,6 @@ struct Shader {
|
|||||||
|
|
||||||
void bind() {
|
void bind() {
|
||||||
glUseProgram(ID);
|
glUseProgram(ID);
|
||||||
setParam(uViewProj, Core::mViewProj);
|
|
||||||
setParam(uModel, Core::mModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setParam(UniformType uType, const vec3 &value, int count = 1) {
|
void setParam(UniformType uType, const vec3 &value, int count = 1) {
|
||||||
|
33
src/utils.h
33
src/utils.h
@@ -31,6 +31,18 @@ typedef unsigned char uint8;
|
|||||||
typedef unsigned short uint16;
|
typedef unsigned short uint16;
|
||||||
typedef unsigned int uint32;
|
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>
|
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;
|
||||||
@@ -52,7 +64,8 @@ struct vec2 {
|
|||||||
vec2 operator * (float s) const { return vec2(x*s, y*s); }
|
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 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 cross(const vec2 &v) const { return x*v.y - y*v.x; }
|
||||||
float length() const { return sqrtf(dot(*this)); }
|
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); }
|
vec2 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,10 +81,10 @@ struct vec3 {
|
|||||||
vec3 operator * (const vec3 &v) const { return vec3(x*v.x, y*v.y, z*v.z); }
|
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); }
|
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; }
|
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); }
|
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); }
|
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 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
|
||||||
|
|
||||||
vec3 lerp(const vec3 &v, const float t) const {
|
vec3 lerp(const vec3 &v, const float t) const {
|
||||||
@@ -86,6 +99,7 @@ struct vec4 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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) {}
|
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;
|
pos += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read(void *data, int size) {
|
int raw(void *data, int size) {
|
||||||
pos += size;
|
pos += size;
|
||||||
return fread(data, 1, size, f);
|
return fread(data, 1, size, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T& read(T &x) {
|
T& read(T &x) {
|
||||||
read(&x, sizeof(x));
|
raw(&x, sizeof(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* readArray(T *&a, int count) {
|
T* read(T *&a, int count) {
|
||||||
if (!count)
|
if (count) {
|
||||||
return NULL;
|
|
||||||
a = new T[count];
|
a = new T[count];
|
||||||
read(a, count * sizeof(T));
|
raw(a, count * sizeof(T));
|
||||||
|
} else
|
||||||
|
a = NULL;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -1,3 +1,7 @@
|
|||||||
|
#ifdef _DEBUG
|
||||||
|
#include "crtdbg.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
DWORD getTime() {
|
DWORD getTime() {
|
||||||
@@ -171,6 +175,12 @@ void freeGL(HGLRC hRC) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
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 };
|
RECT r = { 0, 0, 1280, 720 };
|
||||||
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
|
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
|
||||||
|
|
||||||
@@ -223,6 +233,10 @@ int main() {
|
|||||||
ReleaseDC(hWnd, hDC);
|
ReleaseDC(hWnd, hDC);
|
||||||
|
|
||||||
DestroyWindow(hWnd);
|
DestroyWindow(hWnd);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
_CrtMemDumpAllObjectsSince(&_ms);
|
||||||
|
system("pause");
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Reference in New Issue
Block a user