mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-16 01:54:38 +02:00
add glTF exporter (debug config, models + first animation)
This commit is contained in:
@@ -1005,9 +1005,9 @@ namespace Core {
|
|||||||
void setCullMode(CullMode mode) {
|
void setCullMode(CullMode mode) {
|
||||||
renderState &= ~RS_CULL;
|
renderState &= ~RS_CULL;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case cmNone : break;
|
|
||||||
case cmBack : renderState |= RS_CULL_BACK; break;
|
case cmBack : renderState |= RS_CULL_BACK; break;
|
||||||
case cmFront : renderState |= RS_CULL_FRONT; break;
|
case cmFront : renderState |= RS_CULL_FRONT; break;
|
||||||
|
default : ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
320
src/extension.h
Normal file
320
src/extension.h
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
#ifndef _H_EXTENSION
|
||||||
|
#define _H_EXTENSION
|
||||||
|
|
||||||
|
#include "mesh.h"
|
||||||
|
|
||||||
|
#if defined(_DEBUG) && defined(_OS_WIN) && defined(_GAPI_GL) && !defined(_GAPI_GLES)
|
||||||
|
#define GEOMETRY_EXPORT
|
||||||
|
|
||||||
|
#include "animation.h"
|
||||||
|
#include "gltf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Extension {
|
||||||
|
|
||||||
|
#ifdef GEOMETRY_EXPORT
|
||||||
|
void exportTexture(const char *name, Texture *tex) {
|
||||||
|
char *data32 = new char[tex->width * tex->height * 4];
|
||||||
|
|
||||||
|
tex->bind(sDiffuse);
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data32);
|
||||||
|
|
||||||
|
Texture::SaveBMP(name, data32, tex->width, tex->height);
|
||||||
|
|
||||||
|
delete[] data32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exportModel(IGame *game, TR::Model &model) {
|
||||||
|
TR::Level *level = game->getLevel();
|
||||||
|
MeshBuilder *mesh = game->getMesh();
|
||||||
|
|
||||||
|
struct ModelVertex {
|
||||||
|
vec3 coord;
|
||||||
|
vec3 normal;
|
||||||
|
vec2 texCoord;
|
||||||
|
ubyte4 joints;
|
||||||
|
ubyte4 weights;
|
||||||
|
};
|
||||||
|
|
||||||
|
char name[256];
|
||||||
|
sprintf(name, "models/dump/%d.glb", int(model.type));
|
||||||
|
|
||||||
|
FILE *file = fopen(name, "wb");
|
||||||
|
if (!file) {
|
||||||
|
LOG("dump: can't dump model to file \"%s\"!\n", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Index *indices = new Index[64 * 1024];
|
||||||
|
Vertex *vertices = new Vertex[64 * 1024];
|
||||||
|
|
||||||
|
int iCount = 0, vCount = 0;
|
||||||
|
|
||||||
|
int animRate = 1, animFrames = 0;
|
||||||
|
|
||||||
|
Animation *anim = NULL;
|
||||||
|
if (model.animation != 0xFFFF) {
|
||||||
|
anim = new Animation(level, &model, true);
|
||||||
|
anim->setAnim(0);
|
||||||
|
animRate = max((int)(anim->anims + anim->index)->frameRate, 1);
|
||||||
|
animFrames = anim->framesCount / animRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get model geometry
|
||||||
|
MeshBuilder::Geometry geom[3];
|
||||||
|
for (int transp = 0; transp < 3; transp++) {
|
||||||
|
int blendMask = mesh->getBlendMask(transp);
|
||||||
|
|
||||||
|
for (int j = 0; j < model.mCount; j++) {
|
||||||
|
bool forceOpaque = false;
|
||||||
|
TR::Entity::fixOpaque(model.type, forceOpaque);
|
||||||
|
|
||||||
|
int index = level->meshOffsets[model.mStart + j];
|
||||||
|
if (index || model.mStart + j <= 0) {
|
||||||
|
TR::Mesh &m = level->meshes[index];
|
||||||
|
mesh->buildMesh(geom[transp], blendMask, m, level, indices, vertices, iCount, vCount, 0, j, 0, 0, 0, 0, COLOR_WHITE, false, forceOpaque);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < iCount; i += 3) { // CCW -> CW
|
||||||
|
swap(indices[i], indices[i + 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int timelineOffset = 0;
|
||||||
|
int translationOffset = timelineOffset + animFrames * sizeof(float);
|
||||||
|
int rotationOffset = translationOffset + animFrames * sizeof(vec3);
|
||||||
|
int verticesOffset = rotationOffset + model.mCount * animFrames * sizeof(quat);
|
||||||
|
int indicesOffset = verticesOffset + vCount * sizeof(ModelVertex);
|
||||||
|
int bufferSize = indicesOffset + iCount * sizeof(Index);
|
||||||
|
|
||||||
|
char *bufferData = new char[bufferSize];
|
||||||
|
|
||||||
|
vec4 vMin(+INF), vMax(-INF);
|
||||||
|
|
||||||
|
mat4 flip = mat4(
|
||||||
|
-1, 0, 0, 0,
|
||||||
|
0, -1, 0, 0,
|
||||||
|
0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1
|
||||||
|
);
|
||||||
|
mat4 flipInv = flip.inverseOrtho();
|
||||||
|
|
||||||
|
ModelVertex *gVertices = (ModelVertex*)(bufferData + verticesOffset);
|
||||||
|
for (int i = 0; i < vCount; i++) {
|
||||||
|
Vertex &src = vertices[i];
|
||||||
|
ModelVertex &dst = gVertices[i];
|
||||||
|
|
||||||
|
dst.coord = src.coord;
|
||||||
|
dst.normal = src.normal;
|
||||||
|
dst.texCoord = src.texCoord;
|
||||||
|
dst.normal = dst.normal.normal();
|
||||||
|
|
||||||
|
dst.coord = flip * dst.coord;
|
||||||
|
dst.normal = flip * dst.normal;
|
||||||
|
|
||||||
|
dst.texCoord *= (1.0f / 32767.0f);
|
||||||
|
dst.joints = ubyte4(uint8(src.coord.w), 0, 0, 0);
|
||||||
|
dst.weights = ubyte4(255, 0, 0, 0);
|
||||||
|
|
||||||
|
vMin.x = min(vMin.x, dst.coord.x);
|
||||||
|
vMin.y = min(vMin.y, dst.coord.y);
|
||||||
|
vMin.z = min(vMin.z, dst.coord.z);
|
||||||
|
|
||||||
|
vMax.x = max(vMax.x, dst.coord.x);
|
||||||
|
vMax.y = max(vMax.y, dst.coord.y);
|
||||||
|
vMax.z = max(vMax.z, dst.coord.z);
|
||||||
|
}
|
||||||
|
memcpy(bufferData + indicesOffset, indices, sizeof(Index) * iCount);
|
||||||
|
|
||||||
|
GLTF *gltf = new GLTF();
|
||||||
|
|
||||||
|
gltf->addSampler(GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT);
|
||||||
|
gltf->addImage("objects.bmp");
|
||||||
|
gltf->addTexture("texture", 0, 0);
|
||||||
|
gltf->addMaterial("material", 0, 0, 1.0f, 0.0f);
|
||||||
|
|
||||||
|
delete[] vertices;
|
||||||
|
delete[] indices;
|
||||||
|
|
||||||
|
gltf->addAccessor(0, 0, iCount, GLTF::SCALAR, GL_UNSIGNED_SHORT); // 0
|
||||||
|
gltf->addAccessor(1, (int)OFFSETOF(ModelVertex, coord), vCount, GLTF::VEC3, GL_FLOAT, false, vMin, vMax); // 1
|
||||||
|
gltf->addAccessor(1, (int)OFFSETOF(ModelVertex, normal), vCount, GLTF::VEC3, GL_FLOAT); // 2
|
||||||
|
gltf->addAccessor(1, (int)OFFSETOF(ModelVertex, texCoord), vCount, GLTF::VEC2, GL_FLOAT); // 3
|
||||||
|
gltf->addAccessor(1, (int)OFFSETOF(ModelVertex, joints), vCount, GLTF::VEC4, GL_UNSIGNED_BYTE); // 4
|
||||||
|
gltf->addAccessor(1, (int)OFFSETOF(ModelVertex, weights), vCount, GLTF::VEC4, GL_UNSIGNED_BYTE, true); // 5
|
||||||
|
|
||||||
|
gltf->addBufferView(0, 0, indicesOffset, sizeof(Index) * iCount); // 0
|
||||||
|
gltf->addBufferView(0, sizeof(ModelVertex), verticesOffset, sizeof(ModelVertex) * vCount); // 1
|
||||||
|
|
||||||
|
sprintf(name, "%d_mesh", int(model.type));
|
||||||
|
gltf->addMesh(name, 0, 0, 1, 2, 3, -1, 4, 5);
|
||||||
|
|
||||||
|
JSON *nodes;
|
||||||
|
gltf->addScene("Scene", &nodes);
|
||||||
|
|
||||||
|
sprintf(name, "%d", int(model.type));
|
||||||
|
gltf->addNode(name, 0, 0, vec3(0, 0, 0), quat(0, 0, 0, 1));
|
||||||
|
nodes->add(NULL, 0); // mesh
|
||||||
|
nodes->add(NULL, 1); // skeleton
|
||||||
|
|
||||||
|
int joints[64];
|
||||||
|
bool links[32][32];
|
||||||
|
memset(links, 0, sizeof(links));
|
||||||
|
|
||||||
|
if (anim) {
|
||||||
|
JSON *samplers;
|
||||||
|
JSON *channels;
|
||||||
|
gltf->addAnimation("0_anim", &samplers, &channels);
|
||||||
|
|
||||||
|
{ // timeline (input)
|
||||||
|
float *timeline = (float*)(bufferData + timelineOffset);
|
||||||
|
for (int i = 0; i < animFrames; i++) {
|
||||||
|
timeline[i] = i * animRate / 30.0f;
|
||||||
|
}
|
||||||
|
gltf->addBufferView(0, 0, timelineOffset, animFrames * sizeof(float)); // 2
|
||||||
|
gltf->addAccessor(2, 0, animFrames, GLTF::SCALAR, GL_FLOAT, false, vec4(timeline[0], 0, 0, 0), vec4(timeline[animFrames - 1], 0, 0, 1)); // 6
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // root translation (output)
|
||||||
|
vec3 *translation = (vec3*)(bufferData + translationOffset);
|
||||||
|
gltf->addBufferView(0, 0, translationOffset, animFrames * sizeof(vec3)); // 3
|
||||||
|
gltf->addAccessor(3, 0, animFrames, GLTF::VEC3, GL_FLOAT); // 7+
|
||||||
|
|
||||||
|
JSON *sampler = samplers->add(JSON::OBJECT); // 0
|
||||||
|
sampler->add("input", 6); // timeline
|
||||||
|
sampler->add("output", 7); // translations for this node
|
||||||
|
|
||||||
|
JSON *channel = channels->add(JSON::OBJECT);
|
||||||
|
channel->add("sampler", 0);
|
||||||
|
JSON *target = channel->add(JSON::OBJECT, "target");
|
||||||
|
target->add("node", 1); // 0 - mesh, 1+ - skeleton (1 = root)
|
||||||
|
target->add("path", "translation");
|
||||||
|
|
||||||
|
for (int j = 0; j < animFrames; j++) {
|
||||||
|
TR::AnimFrame *frame = anim->getFrame(anim->anims + anim->index, j);
|
||||||
|
|
||||||
|
translation[j] = frame->pos;
|
||||||
|
translation[j] = flip * translation[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // rotations (output)
|
||||||
|
gltf->addBufferView(0, 0, rotationOffset, model.mCount * animFrames * sizeof(quat)); // 4
|
||||||
|
|
||||||
|
quat *rotation = (quat*)(bufferData + rotationOffset);
|
||||||
|
quat *ptr = rotation;
|
||||||
|
for (int i = 0; i < model.mCount; i++) {
|
||||||
|
for (int j = 0; j < animFrames; j++) {
|
||||||
|
TR::AnimFrame *frame = anim->getFrame(anim->anims + anim->index, j);
|
||||||
|
|
||||||
|
vec3 angles = frame->getAngle(level->version, i);
|
||||||
|
|
||||||
|
mat4 matrix;
|
||||||
|
matrix.identity();
|
||||||
|
matrix.rotateYXZ(angles);
|
||||||
|
matrix = flip * matrix * flipInv;
|
||||||
|
|
||||||
|
*ptr = matrix.getRot();
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
gltf->addAccessor(4, i * animFrames * sizeof(quat), animFrames, GLTF::VEC4, GL_FLOAT); // 8+
|
||||||
|
|
||||||
|
JSON *sampler = samplers->add(JSON::OBJECT); // 1+
|
||||||
|
sampler->add("input", 6); // timeline
|
||||||
|
sampler->add("output", 8 + i); // rotations for this node
|
||||||
|
|
||||||
|
JSON *channel = channels->add(JSON::OBJECT);
|
||||||
|
channel->add("sampler", 1 + i); // 0 - translation, 1+ - rotation samplers
|
||||||
|
JSON *target = channel->add(JSON::OBJECT, "target");
|
||||||
|
target->add("node", 1 + i); // 0 - mesh, 1+ - skeleton
|
||||||
|
target->add("path", "rotation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gltf->addBuffer(bufferData, bufferSize); // 0
|
||||||
|
|
||||||
|
delete[] bufferData;
|
||||||
|
|
||||||
|
{
|
||||||
|
int nIndex = 0;
|
||||||
|
int sIndex = 0;
|
||||||
|
int stack[16];
|
||||||
|
|
||||||
|
TR::Node *node = (TR::Node*)&level->nodesData[model.node];
|
||||||
|
|
||||||
|
for (int i = 0; i < model.mCount; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
links[nIndex][i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nIndex = i;
|
||||||
|
if (node[i].flags & 0x01) nIndex = stack[--sIndex];
|
||||||
|
if (node[i].flags & 0x02) stack[sIndex++] = nIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete anim;
|
||||||
|
|
||||||
|
vec3 jointPos = vec3(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < model.mCount; i++) {
|
||||||
|
sprintf(name, "joint_%d", i + 1);
|
||||||
|
|
||||||
|
JSON* node = gltf->addNode(name, -1, -1, jointPos, quat(0, 0, 0, 1));
|
||||||
|
JSON* children = new JSON(JSON::ARRAY, "children");
|
||||||
|
|
||||||
|
for (int j = 0; j < model.mCount; j++) {
|
||||||
|
if (links[i][j]) {
|
||||||
|
children->add(NULL, j + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children->nodes) {
|
||||||
|
node->add(children);
|
||||||
|
} else {
|
||||||
|
delete children;
|
||||||
|
}
|
||||||
|
|
||||||
|
joints[i] = i + 1;
|
||||||
|
TR::Node &t = *((TR::Node*)&level->nodesData[model.node] + i);
|
||||||
|
jointPos = flip * vec3((float)t.x, (float)t.y, (float)t.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
gltf->addSkin("skin", -1, 1, joints, model.mCount);
|
||||||
|
|
||||||
|
|
||||||
|
char *buffer = new char[gltf->getBufferSize()];
|
||||||
|
int size = gltf->save(buffer);
|
||||||
|
delete gltf;
|
||||||
|
|
||||||
|
fwrite(buffer, 1, size, file);
|
||||||
|
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
LOG("export model: %s\n", name);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exportGeometry(IGame *game, Texture *atlasRooms, Texture *atlasObjects, Texture *atlasSprites) {
|
||||||
|
CreateDirectory("models", NULL);
|
||||||
|
CreateDirectory("models/dump/", NULL);
|
||||||
|
|
||||||
|
exportTexture("models/dump/rooms", atlasRooms);
|
||||||
|
exportTexture("models/dump/objects", atlasObjects);
|
||||||
|
exportTexture("models/dump/sprites", atlasSprites);
|
||||||
|
|
||||||
|
TR::Level *level = game->getLevel();
|
||||||
|
MeshBuilder *mesh = game->getMesh();
|
||||||
|
|
||||||
|
for (int i = 0; i < level->modelsCount; i++) {
|
||||||
|
exportModel(game, level->models[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@@ -5011,7 +5011,7 @@ namespace TR {
|
|||||||
n = mesh.vertices[face.vertices[fn]].normal;\
|
n = mesh.vertices[face.vertices[fn]].normal;\
|
||||||
continue;\
|
continue;\
|
||||||
}\
|
}\
|
||||||
vec3 o(mesh.vertices[face.vertices[0]].coord);\
|
vec3 o = mesh.vertices[face.vertices[0]].coord;\
|
||||||
vec3 a = o - mesh.vertices[face.vertices[1]].coord;\
|
vec3 a = o - mesh.vertices[face.vertices[1]].coord;\
|
||||||
vec3 b = o - mesh.vertices[face.vertices[2]].coord;\
|
vec3 b = o - mesh.vertices[face.vertices[2]].coord;\
|
||||||
o = b.cross(a).normal() * 16300.0f;\
|
o = b.cross(a).normal() * 16300.0f;\
|
||||||
|
328
src/gltf.h
Normal file
328
src/gltf.h
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
#ifndef _H_GLTF
|
||||||
|
#define _H_GLTF
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
#define ACCESSOR_TYPES(E) \
|
||||||
|
E( SCALAR ) \
|
||||||
|
E( VEC2 ) \
|
||||||
|
E( VEC3 ) \
|
||||||
|
E( VEC4 ) \
|
||||||
|
E( MAT2 ) \
|
||||||
|
E( MAT3 ) \
|
||||||
|
E( MAT4 )
|
||||||
|
|
||||||
|
struct GLTF {
|
||||||
|
enum AccessorType { ACCESSOR_TYPES(DECL_ENUM) ACCESSOR_TYPE_MAX };
|
||||||
|
|
||||||
|
JSON *root;
|
||||||
|
JSON *asset;
|
||||||
|
JSON *buffers;
|
||||||
|
JSON *bufferViews;
|
||||||
|
JSON *accessors;
|
||||||
|
JSON *meshes;
|
||||||
|
JSON *images;
|
||||||
|
JSON *samplers;
|
||||||
|
JSON *textures;
|
||||||
|
JSON *materials;
|
||||||
|
JSON *nodes;
|
||||||
|
JSON *skins;
|
||||||
|
JSON *animations;
|
||||||
|
JSON *scenes;
|
||||||
|
|
||||||
|
char *binaryData;
|
||||||
|
int binarySize;
|
||||||
|
|
||||||
|
GLTF() : binaryData(NULL), binarySize(0) {
|
||||||
|
root = new JSON(JSON::OBJECT);
|
||||||
|
|
||||||
|
asset = root->add(JSON::OBJECT, "asset");
|
||||||
|
images = root->add(JSON::ARRAY, "images");
|
||||||
|
samplers = root->add(JSON::ARRAY, "samplers");
|
||||||
|
textures = root->add(JSON::ARRAY, "textures");
|
||||||
|
materials = root->add(JSON::ARRAY, "materials");
|
||||||
|
buffers = root->add(JSON::ARRAY, "buffers");
|
||||||
|
bufferViews = root->add(JSON::ARRAY, "bufferViews");
|
||||||
|
accessors = root->add(JSON::ARRAY, "accessors");
|
||||||
|
meshes = root->add(JSON::ARRAY, "meshes");
|
||||||
|
nodes = root->add(JSON::ARRAY, "nodes");
|
||||||
|
skins = root->add(JSON::ARRAY, "skins");
|
||||||
|
animations = root->add(JSON::ARRAY, "animations");
|
||||||
|
scenes = root->add(JSON::ARRAY, "scenes");
|
||||||
|
|
||||||
|
asset->add("generator", "OpenLara");
|
||||||
|
asset->add("version", "2.0");
|
||||||
|
|
||||||
|
root->add("scene", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
~GLTF() {
|
||||||
|
delete[] binaryData;
|
||||||
|
delete root;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getBufferSize() {
|
||||||
|
return 8 * 1024 * 1024 + binarySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int save(char *buffer) {
|
||||||
|
struct Header {
|
||||||
|
uint32 magic;
|
||||||
|
uint32 version;
|
||||||
|
uint32 length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Chunk {
|
||||||
|
uint32 length;
|
||||||
|
uint32 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
char *start = buffer;
|
||||||
|
|
||||||
|
Header *header = (Header*)buffer;
|
||||||
|
buffer += sizeof(Header);
|
||||||
|
|
||||||
|
Chunk *chunk = (Chunk*)buffer;
|
||||||
|
buffer += sizeof(Chunk);
|
||||||
|
|
||||||
|
root->save(buffer);
|
||||||
|
|
||||||
|
chunk->length = strlen(buffer);
|
||||||
|
chunk->type = FOURCC("JSON");
|
||||||
|
|
||||||
|
buffer += chunk->length;
|
||||||
|
|
||||||
|
while (( int(buffer - start) % 4) != 0) {
|
||||||
|
*buffer++ = ' ';
|
||||||
|
chunk->length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binaryData) {
|
||||||
|
Chunk *chunk = (Chunk*)buffer;
|
||||||
|
buffer += sizeof(Chunk);
|
||||||
|
chunk->length = binarySize;
|
||||||
|
chunk->type = FOURCC("BIN\0");
|
||||||
|
|
||||||
|
memcpy(buffer, binaryData, binarySize);
|
||||||
|
|
||||||
|
buffer += binarySize;
|
||||||
|
|
||||||
|
while (( (buffer - start) % 4) != 0) {
|
||||||
|
*buffer++ = 0;
|
||||||
|
chunk->length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header->magic = FOURCC("glTF");
|
||||||
|
header->version = 2;
|
||||||
|
header->length = buffer - start;
|
||||||
|
|
||||||
|
return header->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addAccessor(int bufferView, int byteOffset, int count, AccessorType type, int format, bool normalized = false, const vec4 &vMin = vec4(0.0f), const vec4 &vMax = vec4(0.0f)) {
|
||||||
|
static const char *AccessorTypeName[ACCESSOR_TYPE_MAX] = { ACCESSOR_TYPES(DECL_STR) };
|
||||||
|
|
||||||
|
JSON *item = accessors->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
item->add("bufferView", bufferView);
|
||||||
|
|
||||||
|
if (byteOffset) {
|
||||||
|
item->add("byteOffset", byteOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
item->add("count", count);
|
||||||
|
item->add("type", AccessorTypeName[type]);
|
||||||
|
item->add("componentType", format);
|
||||||
|
|
||||||
|
if (normalized) {
|
||||||
|
item->add("normalized", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vMin != vMax || vMin != vec4(0.0f)) {
|
||||||
|
JSON *itemMin = item->add(JSON::ARRAY, "min");
|
||||||
|
JSON *itemMax = item->add(JSON::ARRAY, "max");
|
||||||
|
|
||||||
|
int k;
|
||||||
|
switch (type) {
|
||||||
|
case SCALAR : k = 1; break;
|
||||||
|
case VEC2 : k = 2; break;
|
||||||
|
case VEC3 : k = 3; break;
|
||||||
|
case VEC4 : k = 4; break;
|
||||||
|
default : k = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < k; i++) {
|
||||||
|
itemMin->add(NULL, vMin[i]);
|
||||||
|
itemMax->add(NULL, vMax[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addBuffer(void *data, int size) {
|
||||||
|
JSON *item = buffers->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
item->add("byteLength", size);
|
||||||
|
|
||||||
|
binarySize = size;
|
||||||
|
binaryData = new char[size];
|
||||||
|
memcpy(binaryData, data, size);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addBufferView(int buffer, int byteStride, int byteOffset, int byteLength) {
|
||||||
|
JSON *item = bufferViews->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
item->add("buffer", buffer);
|
||||||
|
if (byteStride) {
|
||||||
|
item->add("byteStride", byteStride);
|
||||||
|
}
|
||||||
|
if (byteOffset) {
|
||||||
|
item->add("byteOffset", byteOffset);
|
||||||
|
}
|
||||||
|
item->add("byteLength", byteLength);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addMesh(const char *name, int material, int INDICES, int POSITION = -1, int NORMAL = -1, int TEXCOORD = -1, int COLOR = -1, int JOINTS = -1, int WEIGHTS = -1) {
|
||||||
|
JSON *item = meshes->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
if (name) item->add("name", name);
|
||||||
|
JSON *primitives = item->add(JSON::ARRAY, "primitives");
|
||||||
|
JSON *part = primitives->add(JSON::OBJECT);
|
||||||
|
JSON *attributes = part->add(JSON::OBJECT, "attributes");
|
||||||
|
if (POSITION >= 0) attributes->add("POSITION", POSITION);
|
||||||
|
if (NORMAL >= 0) attributes->add("NORMAL", NORMAL);
|
||||||
|
if (TEXCOORD >= 0) attributes->add("TEXCOORD_0", TEXCOORD);
|
||||||
|
if (COLOR >= 0) attributes->add("COLOR_0", COLOR);
|
||||||
|
if (JOINTS >= 0) attributes->add("JOINTS_0", JOINTS);
|
||||||
|
if (WEIGHTS >= 0) attributes->add("WEIGHTS_0", WEIGHTS);
|
||||||
|
part->add("indices", INDICES);
|
||||||
|
part->add("material", material);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addImage(const char *uri) {
|
||||||
|
JSON *item = images->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
item->add("uri", uri);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addSampler(int magFilter, int minFilter, int wrapS, int wrapT) {
|
||||||
|
JSON *item = samplers->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
item->add("magFilter", magFilter);
|
||||||
|
item->add("minFilter", minFilter);
|
||||||
|
item->add("wrapS", wrapS);
|
||||||
|
item->add("wrapT", wrapT);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addTexture(const char *name, int sampler, int source) {
|
||||||
|
JSON *item = textures->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
if (name) item->add("name", name);
|
||||||
|
item->add("sampler", sampler);
|
||||||
|
item->add("source", source);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addMaterial(const char *name, int baseColorTextureIndex, int baseColorTextureTexCoord, float roughnessFactor, float metallicFactor) {
|
||||||
|
JSON *item = materials->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
if (name) item->add("name", name);
|
||||||
|
|
||||||
|
item->add("alphaMode", "MASK");
|
||||||
|
|
||||||
|
JSON *pbr = item->add(JSON::OBJECT, "pbrMetallicRoughness");
|
||||||
|
pbr->add("roughnessFactor", roughnessFactor);
|
||||||
|
pbr->add("metallicFactor", metallicFactor);
|
||||||
|
|
||||||
|
JSON *baseTex = pbr->add(JSON::OBJECT, "baseColorTexture");
|
||||||
|
baseTex->add("index", baseColorTextureIndex);
|
||||||
|
baseTex->add("texCoord", baseColorTextureTexCoord);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addNode(const char *name, int mesh, int skin, const vec3 &translation, const quat &rotation) {
|
||||||
|
JSON *item = nodes->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
if (name) item->add("name", name);
|
||||||
|
if (mesh >= 0) item->add("mesh", mesh);
|
||||||
|
if (skin >= 0) item->add("skin", skin);
|
||||||
|
|
||||||
|
if (translation != vec3(0.0f)) {
|
||||||
|
JSON *v = item->add(JSON::ARRAY, "translation");
|
||||||
|
v->add(NULL, translation.x);
|
||||||
|
v->add(NULL, translation.y);
|
||||||
|
v->add(NULL, translation.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rotation != quat(0.0f, 0.0f, 0.0f, 1.0f)) {
|
||||||
|
JSON *v = item->add(JSON::ARRAY, "rotation");
|
||||||
|
v->add(NULL, rotation.x);
|
||||||
|
v->add(NULL, rotation.y);
|
||||||
|
v->add(NULL, rotation.z);
|
||||||
|
v->add(NULL, rotation.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON *addSkin(const char *name, int inverseBindMatrices, int skeleton, int *joints, int jointsCount) {
|
||||||
|
JSON *item = skins->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
item->add("name", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inverseBindMatrices >= 0) {
|
||||||
|
item->add("inverseBindMatrices", inverseBindMatrices);
|
||||||
|
}
|
||||||
|
|
||||||
|
item->add("skeleton", skeleton);
|
||||||
|
|
||||||
|
JSON *v = item->add(JSON::ARRAY, "joints");
|
||||||
|
for (int i = 0; i < jointsCount; i++) {
|
||||||
|
v->add(NULL, joints[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* addAnimation(const char *name, JSON **samplers, JSON **channels) {
|
||||||
|
JSON *item = animations->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
if (name) item->add("name", name);
|
||||||
|
if (samplers) *samplers = item->add(JSON::ARRAY, "samplers");
|
||||||
|
if (channels) *channels = item->add(JSON::ARRAY, "channels");
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSON* addScene(const char *name, JSON **nodes) {
|
||||||
|
JSON *item = scenes->add(JSON::OBJECT);
|
||||||
|
|
||||||
|
item->add("name", name);
|
||||||
|
if (nodes) {
|
||||||
|
*nodes = item->add(JSON::ARRAY, "nodes");
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef ACCESSOR_TYPES
|
||||||
|
|
||||||
|
#endif
|
135
src/json.h
Normal file
135
src/json.h
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
#ifndef _H_JSON
|
||||||
|
#define _H_JSON
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
struct JSON {
|
||||||
|
|
||||||
|
enum Type { EMPTY, OBJECT, ARRAY, STRING, NUMBER, FLOAT, BOOL };
|
||||||
|
|
||||||
|
JSON *prev;
|
||||||
|
JSON *next;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
union {
|
||||||
|
JSON *nodes;
|
||||||
|
char *sValue;
|
||||||
|
int iValue;
|
||||||
|
float fValue;
|
||||||
|
bool bValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
JSON(Type type, const char *name = NULL) : nodes(NULL), prev(NULL), next(NULL), type(type) {
|
||||||
|
this->name = String::copy(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
~JSON() {
|
||||||
|
switch (type) {
|
||||||
|
case OBJECT :
|
||||||
|
case ARRAY : {
|
||||||
|
JSON *node = nodes;
|
||||||
|
while (node) {
|
||||||
|
JSON *next = node->next;
|
||||||
|
delete node;
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STRING : {
|
||||||
|
delete[] sValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default : ;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] name;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* add(Type type, const char *name = NULL) {
|
||||||
|
ASSERT(this->type != ARRAY || (name == NULL && (!nodes || nodes->type == type)));
|
||||||
|
return add(new JSON(type, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON* add(JSON *node) {
|
||||||
|
node->prev = NULL;
|
||||||
|
node->next = nodes;
|
||||||
|
if (nodes) {
|
||||||
|
nodes->prev = node;
|
||||||
|
}
|
||||||
|
nodes = node;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void add(const char *name, const char *value) {
|
||||||
|
add(STRING, name)->sValue = String::copy(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const char *name, int value) {
|
||||||
|
add(NUMBER, name)->iValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const char *name, float value) {
|
||||||
|
add(FLOAT, name)->fValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const char *name, bool value) {
|
||||||
|
add(BOOL, name)->bValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void save(char *buffer) {
|
||||||
|
*buffer = 0;
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
strcat(buffer, "\"");
|
||||||
|
strcat(buffer, name);
|
||||||
|
strcat(buffer, "\":");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == EMPTY) {
|
||||||
|
strcat(buffer, "null");
|
||||||
|
} else if (type == OBJECT || type == ARRAY) {
|
||||||
|
bool isObject = (type == OBJECT);
|
||||||
|
strcat(buffer, isObject ? "{" : "[");
|
||||||
|
|
||||||
|
JSON *node = nodes;
|
||||||
|
while (node && node->next) {
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
while (node) {
|
||||||
|
node->save(buffer + strlen(buffer));
|
||||||
|
node = node->prev;
|
||||||
|
if (node) {
|
||||||
|
strcat(buffer, ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strcat(buffer, isObject ? "}" : "]");
|
||||||
|
} else if (type == STRING) {
|
||||||
|
strcat(buffer, "\"");
|
||||||
|
if (sValue) {
|
||||||
|
strcat(buffer, sValue);
|
||||||
|
}
|
||||||
|
strcat(buffer, "\"");
|
||||||
|
} else if (type == NUMBER) {
|
||||||
|
char buf[64];
|
||||||
|
_itoa(iValue, buf, 10);
|
||||||
|
strcat(buffer, buf);
|
||||||
|
} else if (type == FLOAT) {
|
||||||
|
char buf[64];
|
||||||
|
sprintf(buf, "%.9g", fValue);
|
||||||
|
strcat(buffer, buf);
|
||||||
|
|
||||||
|
//_gcvt(fValue, 8, buf);
|
||||||
|
//strcat(buffer, buf);
|
||||||
|
//strcat(buffer, "0");
|
||||||
|
} else if (type == BOOL) {
|
||||||
|
strcat(buffer, bValue ? "true" : "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -12,6 +12,7 @@
|
|||||||
#include "inventory.h"
|
#include "inventory.h"
|
||||||
#include "savegame.h"
|
#include "savegame.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "extension.h"
|
||||||
|
|
||||||
#if defined(_DEBUG) && defined(_GAPI_GL) && !defined(_GAPI_GLES)
|
#if defined(_DEBUG) && defined(_GAPI_GL) && !defined(_GAPI_GLES)
|
||||||
#define DEBUG_RENDER
|
#define DEBUG_RENDER
|
||||||
@@ -2135,6 +2136,13 @@ struct Level : IGame {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef GEOMETRY_EXPORT
|
||||||
|
if (Input::down[ikF1]) {
|
||||||
|
Extension::exportGeometry(this, atlasRooms, atlasObjects, atlasSprites);
|
||||||
|
Input::down[ikF1] = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateEffect() {
|
void updateEffect() {
|
||||||
|
@@ -988,6 +988,9 @@ struct MeshBuilder {
|
|||||||
for (int j = 0; j < mesh.fCount; j++) {
|
for (int j = 0; j < mesh.fCount; j++) {
|
||||||
TR::Face &f = mesh.faces[j];
|
TR::Face &f = mesh.faces[j];
|
||||||
ASSERT(f.colored || f.flags.texture < level->objectTexturesCount);
|
ASSERT(f.colored || f.flags.texture < level->objectTexturesCount);
|
||||||
|
if (level->version & TR::VER_PSX) {
|
||||||
|
f.colored = false; // PSX version has colored textures
|
||||||
|
}
|
||||||
TR::TextureInfo &t = f.colored ? (useRoomTex ? whiteRoom : whiteObject) : level->objectTextures[f.flags.texture];
|
TR::TextureInfo &t = f.colored ? (useRoomTex ? whiteRoom : whiteObject) : level->objectTextures[f.flags.texture];
|
||||||
|
|
||||||
int texAttrib = forceOpaque ? 0 : t.attribute;
|
int texAttrib = forceOpaque ? 0 : t.attribute;
|
||||||
|
@@ -199,6 +199,7 @@
|
|||||||
<ClInclude Include="..\..\collision.h" />
|
<ClInclude Include="..\..\collision.h" />
|
||||||
<ClInclude Include="..\..\controller.h" />
|
<ClInclude Include="..\..\controller.h" />
|
||||||
<ClInclude Include="..\..\core.h" />
|
<ClInclude Include="..\..\core.h" />
|
||||||
|
<ClInclude Include="..\..\extension.h" />
|
||||||
<ClInclude Include="..\..\format.h" />
|
<ClInclude Include="..\..\format.h" />
|
||||||
<ClInclude Include="..\..\debug.h" />
|
<ClInclude Include="..\..\debug.h" />
|
||||||
<ClInclude Include="..\..\enemy.h" />
|
<ClInclude Include="..\..\enemy.h" />
|
||||||
@@ -212,6 +213,8 @@
|
|||||||
<ClInclude Include="..\..\gapi\gu.h" />
|
<ClInclude Include="..\..\gapi\gu.h" />
|
||||||
<ClInclude Include="..\..\gapi\gxm.h" />
|
<ClInclude Include="..\..\gapi\gxm.h" />
|
||||||
<ClInclude Include="..\..\gapi\vk.h" />
|
<ClInclude Include="..\..\gapi\vk.h" />
|
||||||
|
<ClInclude Include="..\..\gltf.h" />
|
||||||
|
<ClInclude Include="..\..\json.h" />
|
||||||
<ClInclude Include="..\..\lang.h" />
|
<ClInclude Include="..\..\lang.h" />
|
||||||
<ClInclude Include="..\..\lang\de.h" />
|
<ClInclude Include="..\..\lang\de.h" />
|
||||||
<ClInclude Include="..\..\lang\en.h" />
|
<ClInclude Include="..\..\lang\en.h" />
|
||||||
|
@@ -116,6 +116,9 @@
|
|||||||
<ClInclude Include="..\..\lang\fi.h">
|
<ClInclude Include="..\..\lang\fi.h">
|
||||||
<Filter>lang</Filter>
|
<Filter>lang</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\extension.h" />
|
||||||
|
<ClInclude Include="..\..\gltf.h" />
|
||||||
|
<ClInclude Include="..\..\json.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\shaders\filter.glsl">
|
<None Include="..\..\shaders\filter.glsl">
|
||||||
|
60
src/utils.h
60
src/utils.h
@@ -483,6 +483,8 @@ struct vec4 {
|
|||||||
vec4(const vec3 &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
|
vec4(const vec3 &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
|
||||||
vec4(const vec2 &xy, const vec2 &zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y) {}
|
vec4(const vec2 &xy, const vec2 &zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y) {}
|
||||||
|
|
||||||
|
inline float& operator [] (int index) const { ASSERT(index >= 0 && index <= 3); return ((float*)this)[index]; }
|
||||||
|
|
||||||
inline bool operator == (const vec4 &v) const { return x == v.x && y == v.y && z == v.z && w == v.w; }
|
inline bool operator == (const vec4 &v) const { return x == v.x && y == v.y && z == v.z && w == v.w; }
|
||||||
inline bool operator != (const vec4 &v) const { return !(*this == v); }
|
inline bool operator != (const vec4 &v) const { return !(*this == v); }
|
||||||
|
|
||||||
@@ -515,6 +517,9 @@ struct quat {
|
|||||||
w = c;
|
w = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool operator == (const quat &q) const { return x == q.x && y == q.y && z == q.z && w == q.w; }
|
||||||
|
inline bool operator != (const quat &v) const { return !(*this == v); }
|
||||||
|
|
||||||
quat operator - () const {
|
quat operator - () const {
|
||||||
return quat(-x, -y, -z, -w);
|
return quat(-x, -y, -z, -w);
|
||||||
}
|
}
|
||||||
@@ -1065,7 +1070,11 @@ struct short4 {
|
|||||||
short4() {}
|
short4() {}
|
||||||
short4(int16 x, int16 y, int16 z, int16 w) : x(x), y(y), z(z), w(w) {}
|
short4(int16 x, int16 y, int16 z, int16 w) : x(x), y(y), z(z), w(w) {}
|
||||||
|
|
||||||
|
operator vec2() const { return vec2((float)x, (float)y); };
|
||||||
operator vec3() const { return vec3((float)x, (float)y, (float)z); };
|
operator vec3() const { return vec3((float)x, (float)y, (float)z); };
|
||||||
|
operator vec4() const { return vec4((float)x, (float)y, (float)z, (float)w); };
|
||||||
|
|
||||||
|
operator short2() const { return *((short2*)this); }
|
||||||
operator short3() const { return *((short3*)this); }
|
operator short3() const { return *((short3*)this); }
|
||||||
|
|
||||||
inline bool operator == (const short4 &v) const { return x == v.x && y == v.y && z == v.z && w == v.w; }
|
inline bool operator == (const short4 &v) const { return x == v.x && y == v.y && z == v.z && w == v.w; }
|
||||||
@@ -1386,6 +1395,28 @@ union Color16 { // RGBA5551
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace String {
|
||||||
|
|
||||||
|
void toLower(char *str) {
|
||||||
|
if (!str) return;
|
||||||
|
|
||||||
|
while (char &c = *str++) {
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
c -= 'Z' - 'z';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* copy(const char *str) {
|
||||||
|
if (str == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
char *res = new char[strlen(str) + 1];
|
||||||
|
strcpy(res, str);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Stream;
|
struct Stream;
|
||||||
|
|
||||||
extern void osCacheWrite (Stream *stream);
|
extern void osCacheWrite (Stream *stream);
|
||||||
@@ -1418,10 +1449,7 @@ struct Stream {
|
|||||||
int bufferIndex;
|
int bufferIndex;
|
||||||
|
|
||||||
Stream(const char *name, const void *data, int size, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), f(NULL), data((char*)data), name(NULL), size(size), pos(0), buffer(NULL) {
|
Stream(const char *name, const void *data, int size, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), f(NULL), data((char*)data), name(NULL), size(size), pos(0), buffer(NULL) {
|
||||||
if (name) {
|
this->name = String::copy(name);
|
||||||
this->name = new char[strlen(name) + 1];
|
|
||||||
strcpy(this->name, name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream(const char *name, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), f(NULL), data(NULL), name(NULL), size(-1), pos(0), buffer(NULL) {
|
Stream(const char *name, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), f(NULL), data(NULL), name(NULL), size(-1), pos(0), buffer(NULL) {
|
||||||
@@ -1446,10 +1474,7 @@ struct Stream {
|
|||||||
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
#ifdef _OS_WEB
|
#ifdef _OS_WEB
|
||||||
if (name) {
|
this->name = String::copy(name);
|
||||||
this->name = new char[strlen(name) + 1];
|
|
||||||
strcpy(this->name, name);
|
|
||||||
}
|
|
||||||
osDownload(this);
|
osDownload(this);
|
||||||
#else
|
#else
|
||||||
LOG("error loading file \"%s\"\n", name);
|
LOG("error loading file \"%s\"\n", name);
|
||||||
@@ -1468,10 +1493,7 @@ struct Stream {
|
|||||||
|
|
||||||
bufferIndex = -1;
|
bufferIndex = -1;
|
||||||
|
|
||||||
if (name) {
|
this->name = String::copy(name);
|
||||||
this->name = new char[strlen(name) + 1];
|
|
||||||
strcpy(this->name, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback)
|
if (callback)
|
||||||
callback(this, userData);
|
callback(this, userData);
|
||||||
@@ -1907,20 +1929,6 @@ struct BitStream {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace String {
|
|
||||||
|
|
||||||
void toLower(char *str) {
|
|
||||||
if (!str) return;
|
|
||||||
|
|
||||||
while (char &c = *str++) {
|
|
||||||
if (c >= 'A' && c <= 'Z')
|
|
||||||
c -= 'Z' - 'z';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
struct FixedStr {
|
struct FixedStr {
|
||||||
char data[N];
|
char data[N];
|
||||||
|
Reference in New Issue
Block a user