From 6ce16b083716705307c80490c19fa1b496f81e33 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 18 Aug 2024 17:37:57 +0300 Subject: [PATCH 01/19] deleting XML document after use --- xmlModelReader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xmlModelReader.cpp b/xmlModelReader.cpp index 011c6ca..234c27f 100644 --- a/xmlModelReader.cpp +++ b/xmlModelReader.cpp @@ -42,6 +42,8 @@ namespace vb01{ assetRootNode->getDescendants(descendants); setupDrivers(descendants); + delete doc; + return asset; } From 19990e48f4f790a90091bf902a01dde6597a4453 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Mon, 19 Aug 2024 18:23:09 +0300 Subject: [PATCH 02/19] using only the neeeded number of vertex positions --- box.cpp | 8 ++--- mesh.cpp | 22 +++++++------ meshData.cpp | 38 ++++++++++++---------- meshData.h | 36 ++++++++++++++++++--- model.cpp | 6 ++-- quad.cpp | 25 ++++++++------- rayCaster.cpp | 4 +-- xmlModelReader.cpp | 78 ++++++++++++++++++++++++++++++++-------------- 8 files changed, 145 insertions(+), 72 deletions(-) diff --git a/box.cpp b/box.cpp index f69613a..118cf2f 100755 --- a/box.cpp +++ b/box.cpp @@ -63,14 +63,14 @@ namespace vb01{ MeshData::Vertex *vertices = new MeshData::Vertex[3 * numTris]; for(int i = 0; i < 3 * numTris; i++){ - MeshData::Vertex v; - v.pos = pos[data[3 * i]]; - v.norm = norm[data[3 * i + 1]]; + MeshData::Vertex v; + v.pos = &pos[data[3 * i]]; + v.norm = &norm[data[3 * i + 1]]; v.uv = tex[data[3 * i + 2]]; vertices[i] = v; indices[i] = i; } - meshBase = MeshData(vertices, indices, numTris); + meshBase = MeshData((Vector3*)pos, nullptr, nullptr, nullptr, 8, (Vector3*)norm, vertices, indices, numTris); } } diff --git a/mesh.cpp b/mesh.cpp index c8c8a25..1ac93b4 100755 --- a/mesh.cpp +++ b/mesh.cpp @@ -44,31 +44,35 @@ namespace vb01{ glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); - u32 size = sizeof(MeshData::Vertex); + u32 size = sizeof(MeshData::OldVertex); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, 3 * meshBase.numTris * size, meshBase.vertices, GL_DYNAMIC_DRAW); + + MeshData::OldVertex *glVertData = meshBase.toGlVerts(); + glBufferData(GL_ARRAY_BUFFER, 3 * meshBase.numTris * size, glVertData, GL_DYNAMIC_DRAW); + delete glVertData; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * meshBase.numTris * sizeof(u32), meshBase.indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, size, (void*)0); glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, norm))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, norm))); glEnableVertexAttribArray(1); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, uv))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, uv))); glEnableVertexAttribArray(2); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, tan))); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, tan))); glEnableVertexAttribArray(3); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, biTan))); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, biTan))); glEnableVertexAttribArray(4); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, weights))); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, weights))); glEnableVertexAttribArray(5); - glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, boneIndices))); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, boneIndices))); glEnableVertexAttribArray(6); for(int i = 0; i < meshBase.numShapeKeys; i++){ - glVertexAttribPointer(7 + i, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, shapeKeyOffsets) + 3 * i * sizeof(float))); + glVertexAttribPointer(7 + i, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, shapeKeyOffsets) + 3 * i * sizeof(float))); glEnableVertexAttribArray(7 + i); } } diff --git a/meshData.cpp b/meshData.cpp index b5223c9..7ae627d 100644 --- a/meshData.cpp +++ b/meshData.cpp @@ -17,22 +17,28 @@ namespace vb01{ } } - MeshData::ShapeKey::ShapeKey(string name, float value, float minValue, float maxValue) : Animatable(Animatable::SHAPE_KEY, name){ - this->name = name; - this->value = value; - this->minValue = minValue; - this->maxValue = maxValue; - } + MeshData::OldVertex* MeshData::toGlVerts(){ + int numVertices = 3 * numTris; + OldVertex *vertData = new OldVertex[numVertices]; - MeshData::MeshData(Vertex *vertices, u32 *indices, int numTris, string attachableName, string *vertexGroups, int numVertexGroups, string fullSkeletonName, ShapeKey *shapeKeys, int numShapeKeys){ - this->vertices = vertices; - this->indices = indices; - this->numTris = numTris; - this->attachableName = attachableName; - this->vertexGroups = vertexGroups; - this->numVertexGroups = numVertexGroups; - this->fullSkeletonName = fullSkeletonName; - this->shapeKeys = shapeKeys; - this->numShapeKeys = numShapeKeys; + for(int i = 0; i < numVertices; i++){ + vertData[i].pos = *vertices[i].pos; + vertData[i].norm = *vertices[i].norm; + vertData[i].tan = vertices[i].tan; + vertData[i].biTan = vertices[i].biTan; + vertData[i].uv = vertices[i].uv; + + if(weights){ + for(int j = 0; j < 4; j++){ + vertData[i].weights[j] = vertices[i].weights[j]; + vertData[i].boneIndices[j] = vertices[i].boneIndices[j]; + } + + } + + //if(shapeKeyOffsets) for(int j = 0; j < 100; j++) vertData[i].shapeKeyOffsets[j] = vertices[i].shapeKeyOffsets[j]; + } + + return vertData; } } diff --git a/meshData.h b/meshData.h index 783f60d..a8738d8 100644 --- a/meshData.h +++ b/meshData.h @@ -14,12 +14,12 @@ namespace vb01{ std::string name; float minValue, value, maxValue; - ShapeKey(std::string, float, float, float); + ShapeKey(std::string n, float v, float mnv, float mxv) : name(n), value(v), minValue(mnv), maxValue(mxv), Animatable(Animatable::SHAPE_KEY, name){} ShapeKey() : Animatable(Animatable::SHAPE_KEY){} void animate(float, KeyframeChannel); }; - struct Vertex{ + struct OldVertex{ Vector3 pos, norm, tan, biTan; Vector2 uv; float weights[4]{0, 0, 0, 0}; @@ -27,15 +27,43 @@ namespace vb01{ Vector3 shapeKeyOffsets[100]; }; + struct Vertex{ + Vector3 *pos = nullptr, *norm = nullptr, tan, biTan; + Vector2 uv; + float *weights = nullptr; + int *boneIndices = nullptr; + Vector3 *shapeKeyOffsets = nullptr; + }; + + OldVertex* toGlVerts(); + + Vector3 *positions = nullptr, *normals = nullptr, **shapeKeyOffsets = nullptr; + float **weights = nullptr; + int **boneIndices = nullptr; Vertex *vertices; std::string *vertexGroups = nullptr; ShapeKey *shapeKeys = nullptr; u32 *indices, VAO, VBO, EBO; - int numTris, numVertexGroups = 0, numShapeKeys = 0; + int numPos, numTris, numVertexGroups = 0, numShapeKeys = 0; std::string attachableName = "", fullSkeletonName = ""; MeshData(){} - MeshData(Vertex*, u32*, int, std::string = "", std::string *vg = nullptr, int = 0, std::string = "", ShapeKey *sk = nullptr, int = 0); + MeshData(Vector3 *pos, float **w, int **bi, Vector3 **sko, int np, Vector3 *norm, Vertex *vert, u32 *ind, int nt, std::string an = "", std::string *vg = nullptr, int nvg = 0, std::string fsn = "", ShapeKey *sk = nullptr, int nsk = 0) : + positions(pos), + weights(w), + boneIndices(bi), + shapeKeyOffsets(sko), + numPos(np), + normals(norm), + vertices(vert), + indices(ind), + numTris(nt), + vertexGroups(vg), + numVertexGroups(nvg), + fullSkeletonName(fsn), + shapeKeys(sk), + numShapeKeys(nsk) + {} }; } diff --git a/model.cpp b/model.cpp index a98cf93..bb5dbd0 100755 --- a/model.cpp +++ b/model.cpp @@ -28,14 +28,14 @@ namespace vb01{ } Model::~Model(){ - delete children[0]->getMesh(0)->getMaterial(); - vector descendants; getDescendants(descendants); for(Node *node : descendants) - for(Mesh *mesh : node->getMeshes()) + for(Mesh *mesh : node->getMeshes()){ + delete mesh->getMaterial(); mesh->setMaterial(nullptr); + } while(!children.empty()){ Node *c = children[children.size() - 1]; diff --git a/quad.cpp b/quad.cpp index 3181479..96adad6 100755 --- a/quad.cpp +++ b/quad.cpp @@ -18,19 +18,22 @@ namespace vb01{ Vector2 subQuadSize = Vector2(size.x / numHorQuads, size.y / numVertQuads); MeshData::Vertex *vertices = new MeshData::Vertex[numVerts]; + Vector3 *faceVertPos = new Vector3[6]; + + Vector3 *norm = new Vector3(Vector3::VEC_J); for(int i = 0; i < numHorQuads; i++){ for(int j = 0; j < numVertQuads; j++){ int id = i * 6 * numHorQuads + j * 6; Vector2 offset = Vector2(subQuadSize.x, subQuadSize.y); - Vector3 faceVertPos[]{ - Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * i), - Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * (i + 1)), - Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * i), - Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * i), - Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * (i + 1)), - Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * (i + 1)) - }; + + faceVertPos[0] = Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * i); + faceVertPos[1] = Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * (i + 1)); + faceVertPos[2] = Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * i); + faceVertPos[3] = Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * i); + faceVertPos[4] = Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * (i + 1)); + faceVertPos[5] = Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * (i + 1)); + Vector2 faceVertUv[]{ Vector2(float(j) / numHorQuads, float(i) / numVertQuads), Vector2(float(j + 1) / numHorQuads, float(i + 1) / numVertQuads), @@ -48,10 +51,10 @@ namespace vb01{ } MeshData::Vertex v; - v.pos = faceVertPos[k]; + v.pos = &faceVertPos[k]; v.uv = faceVertUv[k]; v.tan = Vector3::VEC_I; - v.norm = Vector3::VEC_J; + v.norm = norm; v.biTan = Vector3::VEC_K; vertices[id + k] = v; } @@ -63,6 +66,6 @@ namespace vb01{ for(int i = 0; i < numVerts; i++) indices[i] = i; - meshBase = MeshData(vertices, indices, numTris); + meshBase = MeshData((Vector3*)faceVertPos, nullptr, nullptr, nullptr, 6, nullptr, vertices, indices, numTris); } } diff --git a/rayCaster.cpp b/rayCaster.cpp index 43e09df..dc6f6d2 100644 --- a/rayCaster.cpp +++ b/rayCaster.cpp @@ -42,7 +42,7 @@ namespace vb01{ bool skip = false; for(int j = 0; j < 3; j++){ - Vector3 rayPosToVert = (vertices[i * 3 + j].pos - rayPos); + Vector3 rayPosToVert = (*(vertices[i * 3 + j].pos) - rayPos); float angle = rayDir.getAngleBetween(rayPosToVert.norm()); if(angle > PI / 2) angle = PI - angle; @@ -58,7 +58,7 @@ namespace vb01{ if(skip) continue; } - Vector3 pointA = pos + rot * vertices[indices[i * 3]].pos, pointB = pos + rot * vertices[indices[i * 3 + 1]].pos, pointC = pos + rot * vertices[indices[i * 3 + 2]].pos; + Vector3 pointA = pos + rot * *(vertices[indices[i * 3]].pos), pointB = pos + rot * *(vertices[indices[i * 3 + 1]].pos), pointC = pos + rot * *(vertices[indices[i * 3 + 2]].pos); Vector3 hypVec = pointA - rayPos; Vector3 perpVec = (pointB - pointA).cross(pointC - pointA).norm(); float a1 = hypVec.norm().getAngleBetween(perpVec); diff --git a/xmlModelReader.cpp b/xmlModelReader.cpp index 234c27f..8c2c879 100644 --- a/xmlModelReader.cpp +++ b/xmlModelReader.cpp @@ -59,44 +59,61 @@ namespace vb01{ } } + //TODO remove the 4 literal for bone weights and indices Mesh* XmlModelReader::processMesh(XMLElement *meshEl){ - vector vertPos, vertNorm; - vector weights; + int numVertPos = 0; + vector vp; + vector w; const char *tagName = "vertdata"; - for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement()){ + for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement(), numVertPos++){ float posX = atof(vertEl->Attribute("px")); float posY = atof(vertEl->Attribute("py")); float posZ = atof(vertEl->Attribute("pz")); - vertPos.push_back(Vector3(posX, posY, posZ)); - - float normX = atof(vertEl->Attribute("nx")); - float normY = atof(vertEl->Attribute("ny")); - float normZ = atof(vertEl->Attribute("nz")); - vertNorm.push_back(Vector3(normX, normY, normZ)); + vp.push_back(Vector3(posX, posY, posZ)); for(XMLElement *weightEl = vertEl->FirstChildElement("weight"); weightEl; weightEl = weightEl->NextSiblingElement()) - weights.push_back(atof(weightEl->Attribute("value"))); + w.push_back(atof(weightEl->Attribute("value"))); } int numVertexGroups = atoi(meshEl->Attribute("num_vertex_groups")); + + Vector3 *vertPos = new Vector3[numVertPos]; + float **weights = new float*[numVertPos]; + int **boneIndices = new int*[numVertPos]; + + for(int i = 0; i < vp.size(); i++){ + vertPos[i] = vp[i]; + weights[i] = new float[4]; + boneIndices[i] = new int[4]; + + for(int j = 0; j < 4; j++){ + weights[i][j] = 0; + //weights[i][j] = w[i * numVertexGroups + j]; + boneIndices[i][j] = -1; + } + } + + vp.clear(); + w.clear(); + string *vertexGroups = new string[numVertexGroups]; tagName = "vertexgroup"; int i = 0; for(XMLElement *vertGroupEl = meshEl->FirstChildElement(tagName); vertGroupEl && strcmp(vertGroupEl->Name(), tagName) == 0; vertGroupEl = vertGroupEl->NextSiblingElement(), i++) - vertexGroups[i] = (vertGroupEl->Attribute("name")); + vertexGroups[i] = (vertGroupEl->Attribute("name")); i = 0; int numVertices = 3 * atoi(meshEl->Attribute("num_faces")); MeshData::Vertex *vertices = new MeshData::Vertex[numVertices]; tagName = "vert"; - vector vertIds; u32 *indices = new u32[numVertices]; + Vector3 *normals = new Vector3[numVertices]; + for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement(), i++){ int id = atoi(vertEl->Attribute("id")); - vertIds.push_back(id); float uvX = atof(vertEl->Attribute("uvx")); float uvY = atof(vertEl->Attribute("uvy")); @@ -112,30 +129,39 @@ namespace vb01{ float biTanZ = atof(vertEl->Attribute("bz")); Vector3 biTan = Vector3(biTanX, biTanY, biTanZ); + normals[i] = tan.cross(biTan); + MeshData::Vertex vertex; - vertex.pos = vertPos[id]; - vertex.norm = vertNorm[id]; + vertex.pos = &vertPos[id]; + vertex.norm = &normals[id]; vertex.uv = uv; vertex.tan = tan; vertex.biTan = biTan; for(int j = 0, boneIndex = 0; j < numVertexGroups; j++){ - if(weights[id * numVertexGroups + j] > 0){ - vertex.boneIndices[boneIndex] = j; - vertex.weights[boneIndex] = weights[id * numVertexGroups + j]; + if(weights[id][j] > 0){ + boneIndices[id][boneIndex] = j; + //weights[id][boneIndex] = weights[id * numVertexGroups + j]; boneIndex++; } } + vertex.weights = weights[id]; + vertex.boneIndices = boneIndices[id]; + indices[i] = i; vertices[i] = vertex; } - vertNorm.clear(); tagName = "shapekey"; i = 0; int numShapeKeys = atoi(meshEl->Attribute("num_shape_keys")); MeshData::ShapeKey *shapeKeys = new MeshData::ShapeKey[numShapeKeys]; + Vector3 **shapeKeyOffsets = new Vector3*[numVertPos]; + + for(int i = 0; i < numVertPos; i++){ + shapeKeyOffsets[i] = new Vector3[100]; + } for(XMLElement *shapeKeyEl = meshEl->FirstChildElement(tagName); shapeKeyEl && strcmp(shapeKeyEl->Name(), tagName) == 0; shapeKeyEl = shapeKeyEl->NextSiblingElement(), i++){ string name = shapeKeyEl->Attribute("name"); @@ -159,13 +185,19 @@ namespace vb01{ shapeKeyPos.push_back(Vector3(posX, posY, posZ)); } - for(int j = 0; j < numVertices; j++) - vertices[j].shapeKeyOffsets[i] = shapeKeyPos[vertIds[j]] - vertPos[vertIds[j]]; + /* + for(int j = 0; j < numVertPos; j++){ + shapeKeyOffsets[i] = new Vector3[100]; + + for(int k = 0; k < 100; k++) + shapeKeyOffsets[i][k] = shapeKeyPos[vertIds[j]] - vertPos[vertIds[j]]; + } + */ } const char *fullSkeletonName = meshEl->Attribute("skeleton"); string name = string(meshEl->Parent()->ToElement()->Attribute("name")) + string(meshEl->Attribute("name")); - Mesh *mesh = new Mesh(MeshData(vertices, indices, numVertices / 3, name, vertexGroups, numVertexGroups, (fullSkeletonName ? fullSkeletonName : ""), shapeKeys, numShapeKeys)); + Mesh *mesh = new Mesh(MeshData(vertPos, weights, boneIndices, shapeKeyOffsets, numVertPos, normals, vertices, indices, numVertices / 3, name, vertexGroups, numVertexGroups, (fullSkeletonName ? fullSkeletonName : ""), shapeKeys, numShapeKeys)); return mesh; } @@ -293,7 +325,7 @@ namespace vb01{ XMLElement *meshTag = xmlEl->FirstChildElement("mesh"); if(meshTag) - node->attachMesh(processMesh(meshTag)); + node->attachMesh(processMesh(meshTag)); XMLElement *lightTag = xmlEl->FirstChildElement("light"); From 36f15b6dd944705e4e455c14a863e68e00d03d79 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 1 Sep 2024 16:13:53 +0300 Subject: [PATCH 03/19] improved model parsing --- box.cpp | 38 +- meshData.cpp | 5 +- meshData.h | 2 +- samples/models/kek.xml | 2068 ++++++++++++++++++++-------------------- script.py | 2 + xmlModelReader.cpp | 131 ++- 6 files changed, 1119 insertions(+), 1127 deletions(-) diff --git a/box.cpp b/box.cpp index 118cf2f..671656b 100755 --- a/box.cpp +++ b/box.cpp @@ -9,27 +9,23 @@ namespace vb01{ void Box::setSize(Vector3 size){ this->size = size; - Vector3 pos[] = { - Vector3(size.x / 2, size.y / 2, size.z / 2), - Vector3(-size.x / 2, size.y / 2, size.z / 2), - Vector3(-size.x / 2, size.y / 2, -size.z / 2), - Vector3(size.x / 2, size.y / 2, -size.z / 2), + Vector3 *pos = new Vector3[8]; + pos[0] = Vector3(size.x / 2, size.y / 2, size.z / 2); + pos[1] = Vector3(-size.x / 2, size.y / 2, size.z / 2); + pos[2] = Vector3(-size.x / 2, size.y / 2, -size.z / 2); + pos[3] = Vector3(size.x / 2, size.y / 2, -size.z / 2); + pos[4] = Vector3(size.x / 2, -size.y / 2, size.z / 2); + pos[5] = Vector3(-size.x / 2, -size.y / 2, size.z / 2); + pos[6] = Vector3(-size.x / 2, -size.y / 2, -size.z / 2); + pos[7] = Vector3(size.x / 2, -size.y / 2, -size.z / 2); - Vector3(size.x / 2, -size.y / 2, size.z / 2), - Vector3(-size.x / 2, -size.y / 2, size.z / 2), - Vector3(-size.x / 2, -size.y / 2, -size.z / 2), - Vector3(size.x / 2, -size.y / 2, -size.z / 2) - }; - - Vector3 norm[] = { - Vector3(0, 0, 1), - Vector3(0, 1, 0), - Vector3(1, 0, 0), - - Vector3(0, 0, -1), - Vector3(0, -1, 0), - Vector3(-1, 0, 0) - }; + Vector3 *norm = new Vector3[6]; + norm[0] = Vector3(0, 0, 1); + norm[1] = Vector3(0, 1, 0); + norm[2] = Vector3(1, 0, 0); + norm[3] = Vector3(0, 0, -1); + norm[4] = Vector3(0, -1, 0); + norm[5] = Vector3(-1, 0, 0); Vector2 tex[] = { Vector2(1, 1), @@ -71,6 +67,6 @@ namespace vb01{ indices[i] = i; } - meshBase = MeshData((Vector3*)pos, nullptr, nullptr, nullptr, 8, (Vector3*)norm, vertices, indices, numTris); + meshBase = MeshData(pos, nullptr, nullptr, nullptr, 8, norm, vertices, indices, numTris); } } diff --git a/meshData.cpp b/meshData.cpp index 7ae627d..f3d17bb 100644 --- a/meshData.cpp +++ b/meshData.cpp @@ -33,10 +33,11 @@ namespace vb01{ vertData[i].weights[j] = vertices[i].weights[j]; vertData[i].boneIndices[j] = vertices[i].boneIndices[j]; } - } - //if(shapeKeyOffsets) for(int j = 0; j < 100; j++) vertData[i].shapeKeyOffsets[j] = vertices[i].shapeKeyOffsets[j]; + if(shapeKeyOffsets) + for(int j = 0; j < 100; j++) + vertData[i].shapeKeyOffsets[j] = vertices[i].shapeKeyOffsets[j]; } return vertData; diff --git a/meshData.h b/meshData.h index a8738d8..568047f 100644 --- a/meshData.h +++ b/meshData.h @@ -14,7 +14,7 @@ namespace vb01{ std::string name; float minValue, value, maxValue; - ShapeKey(std::string n, float v, float mnv, float mxv) : name(n), value(v), minValue(mnv), maxValue(mxv), Animatable(Animatable::SHAPE_KEY, name){} + ShapeKey(std::string n, float v, float mnv, float mxv) : name(n), value(v), minValue(mnv), maxValue(mxv), Animatable(Animatable::SHAPE_KEY, n){} ShapeKey() : Animatable(Animatable::SHAPE_KEY){} void animate(float, KeyframeChannel); }; diff --git a/samples/models/kek.xml b/samples/models/kek.xml index 25080a7..a510627 100644 --- a/samples/models/kek.xml +++ b/samples/models/kek.xml @@ -1,6 +1,6 @@ - - + + @@ -144,9 +144,9 @@ - - - + + + @@ -162,7 +162,7 @@ - + @@ -178,7 +178,7 @@ - + @@ -194,7 +194,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -226,7 +226,7 @@ - + @@ -242,7 +242,7 @@ - + @@ -258,7 +258,7 @@ - + @@ -274,7 +274,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -306,7 +306,7 @@ - + @@ -322,7 +322,7 @@ - + @@ -338,7 +338,7 @@ - + @@ -354,7 +354,7 @@ - + @@ -370,7 +370,7 @@ - + @@ -386,7 +386,7 @@ - + @@ -402,7 +402,7 @@ - + @@ -418,7 +418,7 @@ - + @@ -434,7 +434,7 @@ - + @@ -450,7 +450,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -482,7 +482,7 @@ - + @@ -498,7 +498,7 @@ - + @@ -514,7 +514,7 @@ - + @@ -530,7 +530,7 @@ - + @@ -546,7 +546,7 @@ - + @@ -562,7 +562,7 @@ - + @@ -578,7 +578,7 @@ - + @@ -594,7 +594,7 @@ - + @@ -610,7 +610,7 @@ - + @@ -626,7 +626,7 @@ - + @@ -642,7 +642,7 @@ - + @@ -658,7 +658,7 @@ - + @@ -674,7 +674,7 @@ - + @@ -690,7 +690,7 @@ - + @@ -706,7 +706,7 @@ - + @@ -722,7 +722,7 @@ - + @@ -738,7 +738,7 @@ - + @@ -754,7 +754,7 @@ - + @@ -770,7 +770,7 @@ - + @@ -786,7 +786,7 @@ - + @@ -802,7 +802,7 @@ - + @@ -818,7 +818,7 @@ - + @@ -834,7 +834,7 @@ - + @@ -850,7 +850,7 @@ - + @@ -866,7 +866,7 @@ - + @@ -882,7 +882,7 @@ - + @@ -898,7 +898,7 @@ - + @@ -914,7 +914,7 @@ - + @@ -930,7 +930,7 @@ - + @@ -946,7 +946,7 @@ - + @@ -962,7 +962,7 @@ - + @@ -978,7 +978,7 @@ - + @@ -994,7 +994,7 @@ - + @@ -1010,7 +1010,7 @@ - + @@ -1026,7 +1026,7 @@ - + @@ -1042,7 +1042,7 @@ - + @@ -1058,7 +1058,7 @@ - + @@ -1074,7 +1074,7 @@ - + @@ -1090,7 +1090,7 @@ - + @@ -1106,7 +1106,7 @@ - + @@ -1122,7 +1122,7 @@ - + @@ -1138,7 +1138,7 @@ - + @@ -1154,7 +1154,7 @@ - + @@ -1170,7 +1170,7 @@ - + @@ -1186,7 +1186,7 @@ - + @@ -1202,7 +1202,7 @@ - + @@ -1218,7 +1218,7 @@ - + @@ -1234,7 +1234,7 @@ - + @@ -1250,7 +1250,7 @@ - + @@ -1266,7 +1266,7 @@ - + @@ -1282,7 +1282,7 @@ - + @@ -1298,7 +1298,7 @@ - + @@ -1314,7 +1314,7 @@ - + @@ -1330,7 +1330,7 @@ - + @@ -1346,7 +1346,7 @@ - + @@ -1362,7 +1362,7 @@ - + @@ -1378,7 +1378,7 @@ - + @@ -1394,7 +1394,7 @@ - + @@ -1410,7 +1410,7 @@ - + @@ -1426,7 +1426,7 @@ - + @@ -1442,7 +1442,7 @@ - + @@ -1458,7 +1458,7 @@ - + @@ -1474,7 +1474,7 @@ - + @@ -1490,7 +1490,7 @@ - + @@ -1506,7 +1506,7 @@ - + @@ -1522,7 +1522,7 @@ - + @@ -1538,7 +1538,7 @@ - + @@ -1554,7 +1554,7 @@ - + @@ -1570,7 +1570,7 @@ - + @@ -1586,7 +1586,7 @@ - + @@ -1602,7 +1602,7 @@ - + @@ -1618,7 +1618,7 @@ - + @@ -1634,7 +1634,7 @@ - + @@ -1650,7 +1650,7 @@ - + @@ -1666,7 +1666,7 @@ - + @@ -1682,7 +1682,7 @@ - + @@ -1698,7 +1698,7 @@ - + @@ -1714,7 +1714,7 @@ - + @@ -1730,7 +1730,7 @@ - + @@ -1746,7 +1746,7 @@ - + @@ -1762,7 +1762,7 @@ - + @@ -1778,7 +1778,7 @@ - + @@ -1794,7 +1794,7 @@ - + @@ -1810,7 +1810,7 @@ - + @@ -1826,7 +1826,7 @@ - + @@ -1842,7 +1842,7 @@ - + @@ -1858,7 +1858,7 @@ - + @@ -1874,7 +1874,7 @@ - + @@ -1890,7 +1890,7 @@ - + @@ -1906,7 +1906,7 @@ - + @@ -1922,7 +1922,7 @@ - + @@ -1938,7 +1938,7 @@ - + @@ -1954,7 +1954,7 @@ - + @@ -1970,7 +1970,7 @@ - + @@ -1986,7 +1986,7 @@ - + @@ -2002,7 +2002,7 @@ - + @@ -2018,7 +2018,7 @@ - + @@ -2034,7 +2034,7 @@ - + @@ -2050,7 +2050,7 @@ - + @@ -2066,7 +2066,7 @@ - + @@ -2082,7 +2082,7 @@ - + @@ -2098,7 +2098,7 @@ - + @@ -2114,7 +2114,7 @@ - + @@ -2130,7 +2130,7 @@ - + @@ -2146,7 +2146,7 @@ - + @@ -2162,7 +2162,7 @@ - + @@ -2178,7 +2178,7 @@ - + @@ -2194,7 +2194,7 @@ - + @@ -2210,7 +2210,7 @@ - + @@ -2226,7 +2226,7 @@ - + @@ -2242,7 +2242,7 @@ - + @@ -2258,7 +2258,7 @@ - + @@ -2274,7 +2274,7 @@ - + @@ -2290,7 +2290,7 @@ - + @@ -2306,7 +2306,7 @@ - + @@ -2322,7 +2322,7 @@ - + @@ -2338,7 +2338,7 @@ - + @@ -2354,7 +2354,7 @@ - + @@ -2370,7 +2370,7 @@ - + @@ -2386,7 +2386,7 @@ - + @@ -2402,7 +2402,7 @@ - + @@ -2418,7 +2418,7 @@ - + @@ -2434,7 +2434,7 @@ - + @@ -2450,7 +2450,7 @@ - + @@ -2466,7 +2466,7 @@ - + @@ -2482,7 +2482,7 @@ - + @@ -2498,7 +2498,7 @@ - + @@ -2514,7 +2514,7 @@ - + @@ -2530,7 +2530,7 @@ - + @@ -2546,7 +2546,7 @@ - + @@ -2562,7 +2562,7 @@ - + @@ -2578,7 +2578,7 @@ - + @@ -2594,7 +2594,7 @@ - + @@ -2610,7 +2610,7 @@ - + @@ -2626,7 +2626,7 @@ - + @@ -2642,7 +2642,7 @@ - + @@ -2658,7 +2658,7 @@ - + @@ -2674,7 +2674,7 @@ - + @@ -2690,7 +2690,7 @@ - + @@ -2706,7 +2706,7 @@ - + @@ -2722,7 +2722,7 @@ - + @@ -2738,7 +2738,7 @@ - + @@ -2754,7 +2754,7 @@ - + @@ -2770,7 +2770,7 @@ - + @@ -2786,7 +2786,7 @@ - + @@ -2802,7 +2802,7 @@ - + @@ -2818,7 +2818,7 @@ - + @@ -2834,7 +2834,7 @@ - + @@ -2850,7 +2850,7 @@ - + @@ -2866,7 +2866,7 @@ - + @@ -2882,7 +2882,7 @@ - + @@ -2898,7 +2898,7 @@ - + @@ -2914,7 +2914,7 @@ - + @@ -2930,7 +2930,7 @@ - + @@ -2946,7 +2946,7 @@ - + @@ -2962,7 +2962,7 @@ - + @@ -2978,7 +2978,7 @@ - + @@ -2994,7 +2994,7 @@ - + @@ -3010,7 +3010,7 @@ - + @@ -3026,7 +3026,7 @@ - + @@ -3042,7 +3042,7 @@ - + @@ -3058,7 +3058,7 @@ - + @@ -3074,7 +3074,7 @@ - + @@ -3090,7 +3090,7 @@ - + @@ -3106,7 +3106,7 @@ - + @@ -3122,7 +3122,7 @@ - + @@ -3138,7 +3138,7 @@ - + @@ -3154,7 +3154,7 @@ - + @@ -3170,7 +3170,7 @@ - + @@ -3186,7 +3186,7 @@ - + @@ -3202,7 +3202,7 @@ - + @@ -3218,7 +3218,7 @@ - + @@ -3234,7 +3234,7 @@ - + @@ -3250,7 +3250,7 @@ - + @@ -3266,7 +3266,7 @@ - + @@ -3282,7 +3282,7 @@ - + @@ -3298,7 +3298,7 @@ - + @@ -3314,7 +3314,7 @@ - + @@ -3330,7 +3330,7 @@ - + @@ -3346,7 +3346,7 @@ - + @@ -3362,7 +3362,7 @@ - + @@ -3378,7 +3378,7 @@ - + @@ -3394,7 +3394,7 @@ - + @@ -3410,7 +3410,7 @@ - + @@ -3426,7 +3426,7 @@ - + @@ -3442,7 +3442,7 @@ - + @@ -3458,7 +3458,7 @@ - + @@ -3474,7 +3474,7 @@ - + @@ -3490,7 +3490,7 @@ - + @@ -3506,7 +3506,7 @@ - + @@ -3522,7 +3522,7 @@ - + @@ -3538,7 +3538,7 @@ - + @@ -3554,7 +3554,7 @@ - + @@ -3570,7 +3570,7 @@ - + @@ -3586,7 +3586,7 @@ - + @@ -3602,7 +3602,7 @@ - + @@ -3618,7 +3618,7 @@ - + @@ -3634,7 +3634,7 @@ - + @@ -3650,7 +3650,7 @@ - + @@ -3666,7 +3666,7 @@ - + @@ -3682,7 +3682,7 @@ - + @@ -3698,7 +3698,7 @@ - + @@ -3714,7 +3714,7 @@ - + @@ -3730,7 +3730,7 @@ - + @@ -3746,7 +3746,7 @@ - + @@ -3762,7 +3762,7 @@ - + @@ -3778,7 +3778,7 @@ - + @@ -3794,7 +3794,7 @@ - + @@ -3810,7 +3810,7 @@ - + @@ -3826,7 +3826,7 @@ - + @@ -3842,7 +3842,7 @@ - + @@ -3858,7 +3858,7 @@ - + @@ -3874,7 +3874,7 @@ - + @@ -3890,7 +3890,7 @@ - + @@ -3906,7 +3906,7 @@ - + @@ -3922,7 +3922,7 @@ - + @@ -3938,7 +3938,7 @@ - + @@ -3954,7 +3954,7 @@ - + @@ -3970,7 +3970,7 @@ - + @@ -3986,7 +3986,7 @@ - + @@ -4002,7 +4002,7 @@ - + @@ -4018,7 +4018,7 @@ - + @@ -4034,7 +4034,7 @@ - + @@ -4050,7 +4050,7 @@ - + @@ -4066,7 +4066,7 @@ - + @@ -4082,7 +4082,7 @@ - + @@ -4098,7 +4098,7 @@ - + @@ -4114,7 +4114,7 @@ - + @@ -4130,7 +4130,7 @@ - + @@ -4146,7 +4146,7 @@ - + @@ -4162,7 +4162,7 @@ - + @@ -4178,7 +4178,7 @@ - + @@ -4194,7 +4194,7 @@ - + @@ -4210,7 +4210,7 @@ - + @@ -4226,7 +4226,7 @@ - + @@ -4256,61 +4256,61 @@ - - + + - - + + - - + + - - + + - + - - + + - - - + + + - - - + + + - - - - - + + + + + - - + + - + - + - + @@ -4325,311 +4325,311 @@ - - + + - + - + - - + + - + - + - + - + - - + + - + - - + + - + - + - - + + - + - - - - + + + + - - + + - + - - - - - - + + + + + + - - + + - - + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - - - + + + + - - + + - + - - + + - - + + - - + + - + - + - - + + - - + + - - - - + + + + - + - - + + - - + + - + - - + + - - + + - - + + - - - - - + + + + + - - + + - + - - + + - + - - + + - - - - - + + + + + - - - - - + + + + + - - + + - + - - - - - + + + + + - + - + - + - + - + - - + + - + - - + + - + - + @@ -4642,18 +4642,18 @@ - - - + + + - - + + - + - + @@ -4679,8 +4679,8 @@ - - + + @@ -4688,351 +4688,351 @@ - - + + - - + + - - + + - + - + - + - + - - + + - - + + - + - + - - + + - + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - + + - - - - - - - - + + + + + + + + - - + + - + - + - - + + - - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - + + - - + + - - - - - - - - + + + + + + + + - - + + - - + + - - + + - + - + - + - + - + - - + + - - + + - + - - - - + + + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - - - + + + + - - + + - + - - + + - - + + - - + + - - + + - + - - - - + + + + - + - - + + - - - - + + + + - - + + - + - - - - + + + + - + - - + + - - + + - - + + - + - + - - + + - + - + - + - + - + - - - - - + + + + + - + - - - - + + + + - - + + - - + + - + @@ -5041,8 +5041,8 @@ - - + + @@ -5057,312 +5057,312 @@ - + - - + + - + - + - - + + - + - + - + - + - - + + - + - - + + - + - + - + - - - + + + - + - + - - + + - - + + - - - - - + + + + + - + - + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - + + - - - - - - - - + + + + + + + + - - - - + + + + - - - - - + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - - + + - - + + - - + + - + - + - + - + - + - + - + - - + + - + - + - - - + + + - - + + - + - + - + - + - + - - + + - - + + - + - + - + - - - + + + - + - + - + - - + + - - + + - - + + - - - - - + + + + + - + - - + + - - - - + + + + - + - + - - + + - - + + - + - + - + - + - + - + @@ -5375,18 +5375,18 @@ - + - - + + - - - + + + - + @@ -5411,315 +5411,315 @@ - + - + - + - - + + - - + + - + - + - + - + - + - - + + - - + + - + - + - + - - - + + + - + - - - + + + - + - - - - + + + + - - + + - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - + + + + + - - + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - + + - - + + - - - - - + + + + + - - + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - + + - - + + - - + + - + - - + + - + - + - + - + - + - + - - + + - - + + - - + + - - - + + + - + - - + + - - + + - + - - - + + + - - + + - + - - + + - + - - + + - - + + - + - + - - + + - - + + - + - - + + - + - + - - - + + + - + - - + + - - - - - + + + + + - - + + - + - - + + - + - - + + - + - + - + - + @@ -6251,4 +6251,4 @@ - \ No newline at end of file + diff --git a/script.py b/script.py index 5af0a9a..a7a85e7 100644 --- a/script.py +++ b/script.py @@ -166,6 +166,7 @@ def export(node, parentTag): if node.type == 'MESH': mesh = node.data + numVertexPos = len(mesh.vertices) numFaces = len(mesh.polygons) numVerts = len(mesh.vertices) numGroups = len(node.vertex_groups) @@ -176,6 +177,7 @@ def export(node, parentTag): meshTag = ET.SubElement(nodeTag, 'mesh') meshTag.set('name', node.name + mesh.name_full) + meshTag.set('num_vertex_pos', str(numVertexPos)) meshTag.set('num_faces', str(numFaces)) meshTag.set('num_vertex_groups', str(numGroups)) meshTag.set('num_shape_keys', str(numShapeKeys)) diff --git a/xmlModelReader.cpp b/xmlModelReader.cpp index 8c2c879..25eeb38 100644 --- a/xmlModelReader.cpp +++ b/xmlModelReader.cpp @@ -61,48 +61,49 @@ namespace vb01{ //TODO remove the 4 literal for bone weights and indices Mesh* XmlModelReader::processMesh(XMLElement *meshEl){ - int numVertPos = 0; - vector vp; - vector w; - const char *tagName = "vertdata"; - - for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement(), numVertPos++){ - float posX = atof(vertEl->Attribute("px")); - float posY = atof(vertEl->Attribute("py")); - float posZ = atof(vertEl->Attribute("pz")); - vp.push_back(Vector3(posX, posY, posZ)); - - for(XMLElement *weightEl = vertEl->FirstChildElement("weight"); weightEl; weightEl = weightEl->NextSiblingElement()) - w.push_back(atof(weightEl->Attribute("value"))); - } - + int numVertPos = atoi(meshEl->Attribute("num_vertex_pos")); int numVertexGroups = atoi(meshEl->Attribute("num_vertex_groups")); + const char *tagName = "vertdata"; + Vector3 *vertPos = new Vector3[numVertPos]; float **weights = new float*[numVertPos]; - int **boneIndices = new int*[numVertPos]; + int **boneIndices = new int*[numVertPos], i = 0; - for(int i = 0; i < vp.size(); i++){ - vertPos[i] = vp[i]; - weights[i] = new float[4]; - boneIndices[i] = new int[4]; + for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0, i < numVertPos; vertEl = vertEl->NextSiblingElement(), i++){ + float posX = atof(vertEl->Attribute("px")); + float posY = atof(vertEl->Attribute("py")); + float posZ = atof(vertEl->Attribute("pz")); + vertPos[i] = Vector3(posX, posY, posZ); - for(int j = 0; j < 4; j++){ - weights[i][j] = 0; - //weights[i][j] = w[i * numVertexGroups + j]; - boneIndices[i][j] = -1; - } + weights[i] = new float[4]; + boneIndices[i] = new int[4]; + + for(int j = 0; j < 4; j++){ + weights[i][j] = 0; + boneIndices[i][j] = -1; + } + + int boneIndex = 0, j = 0; + + for(XMLElement *weightEl = vertEl->FirstChildElement("weight"); weightEl, j < numVertexGroups; weightEl = weightEl->NextSiblingElement(), j++){ + float w = atof(weightEl->Attribute("value")); + + if(w > 0){ + weights[i][boneIndex] = w; + boneIndices[i][boneIndex] = j; + boneIndex++; + } + } } - vp.clear(); - w.clear(); - string *vertexGroups = new string[numVertexGroups]; tagName = "vertexgroup"; - int i = 0; + i = 0; - for(XMLElement *vertGroupEl = meshEl->FirstChildElement(tagName); vertGroupEl && strcmp(vertGroupEl->Name(), tagName) == 0; vertGroupEl = vertGroupEl->NextSiblingElement(), i++) - vertexGroups[i] = (vertGroupEl->Attribute("name")); + if(numVertexGroups > 0) + for(XMLElement *vertGroupEl = meshEl->FirstChildElement(tagName); vertGroupEl && strcmp(vertGroupEl->Name(), tagName) == 0 && i < numVertexGroups; vertGroupEl = vertGroupEl->NextSiblingElement(), i++) + vertexGroups[i] = vertGroupEl->Attribute("name"); i = 0; int numVertices = 3 * atoi(meshEl->Attribute("num_faces")); @@ -111,9 +112,11 @@ namespace vb01{ u32 *indices = new u32[numVertices]; Vector3 *normals = new Vector3[numVertices]; + vector vertIds; for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement(), i++){ int id = atoi(vertEl->Attribute("id")); + vertIds.push_back(id); float uvX = atof(vertEl->Attribute("uvx")); float uvY = atof(vertEl->Attribute("uvy")); @@ -138,14 +141,6 @@ namespace vb01{ vertex.tan = tan; vertex.biTan = biTan; - for(int j = 0, boneIndex = 0; j < numVertexGroups; j++){ - if(weights[id][j] > 0){ - boneIndices[id][boneIndex] = j; - //weights[id][boneIndex] = weights[id * numVertexGroups + j]; - boneIndex++; - } - } - vertex.weights = weights[id]; vertex.boneIndices = boneIndices[id]; @@ -156,43 +151,41 @@ namespace vb01{ tagName = "shapekey"; i = 0; int numShapeKeys = atoi(meshEl->Attribute("num_shape_keys")); - MeshData::ShapeKey *shapeKeys = new MeshData::ShapeKey[numShapeKeys]; - Vector3 **shapeKeyOffsets = new Vector3*[numVertPos]; + MeshData::ShapeKey *shapeKeys = nullptr; + Vector3 **shapeKeyOffsets = nullptr; - for(int i = 0; i < numVertPos; i++){ - shapeKeyOffsets[i] = new Vector3[100]; - } + if(numShapeKeys > 0){ + shapeKeys = new MeshData::ShapeKey[numShapeKeys]; + shapeKeyOffsets = new Vector3*[numVertPos]; - for(XMLElement *shapeKeyEl = meshEl->FirstChildElement(tagName); shapeKeyEl && strcmp(shapeKeyEl->Name(), tagName) == 0; shapeKeyEl = shapeKeyEl->NextSiblingElement(), i++){ - string name = shapeKeyEl->Attribute("name"); - float minValue = atof(shapeKeyEl->Attribute("min")); - float maxValue = atof(shapeKeyEl->Attribute("max")); - shapeKeys[i] = MeshData::ShapeKey(name, minValue, minValue, maxValue); + for(int i = 0; i < numVertPos; i++) + shapeKeyOffsets[i] = new Vector3[100]; - XMLElement *driverEl = shapeKeyEl->FirstChildElement("driver"); - KeyframeChannel channel = processKeyframeChannells(driverEl)[0]; - const char *nodeName = driverEl->Attribute("obj"); - const char *boneName = driverEl->Attribute("bone"); - Driver::VariableType type = Driver::getDriverVariableType(driverEl->Attribute("type")); - driversByNodeNames.push_back(make_pair(string(nodeName) + (boneName ? "." + string(boneName) : ""), new Driver(&shapeKeys[i], channel, type))); + for(XMLElement *shapeKeyEl = meshEl->FirstChildElement(tagName); shapeKeyEl && strcmp(shapeKeyEl->Name(), tagName) == 0 && i < numShapeKeys; shapeKeyEl = shapeKeyEl->NextSiblingElement(), i++){ + string name = shapeKeyEl->Attribute("name"); + float minValue = atof(shapeKeyEl->Attribute("min")); + float maxValue = atof(shapeKeyEl->Attribute("max")); + shapeKeys[i] = MeshData::ShapeKey(name, minValue, minValue, maxValue); - vector shapeKeyPos; + XMLElement *driverEl = shapeKeyEl->FirstChildElement("driver"); + KeyframeChannel channel = processKeyframeChannells(driverEl)[0]; + const char *nodeName = driverEl->Attribute("obj"); + const char *boneName = driverEl->Attribute("bone"); + Driver::VariableType type = Driver::getDriverVariableType(driverEl->Attribute("type")); + driversByNodeNames.push_back(make_pair(string(nodeName) + (boneName ? "." + string(boneName) : ""), new Driver(&shapeKeys[i], channel, type))); - for(XMLElement *vertEl = shapeKeyEl->FirstChildElement("vert"); vertEl; vertEl = vertEl->NextSiblingElement()){ - float posX = atof(vertEl->Attribute("px")); - float posY = atof(vertEl->Attribute("py")); - float posZ = atof(vertEl->Attribute("pz")); - shapeKeyPos.push_back(Vector3(posX, posY, posZ)); - } + int j = 0; - /* - for(int j = 0; j < numVertPos; j++){ - shapeKeyOffsets[i] = new Vector3[100]; + for(XMLElement *vertEl = shapeKeyEl->FirstChildElement("vert"); vertEl; vertEl = vertEl->NextSiblingElement(), j++){ + float posX = atof(vertEl->Attribute("px")); + float posY = atof(vertEl->Attribute("py")); + float posZ = atof(vertEl->Attribute("pz")); + shapeKeyOffsets[j][i] = Vector3(posX, posY, posZ) - vertPos[j]; + } + } - for(int k = 0; k < 100; k++) - shapeKeyOffsets[i][k] = shapeKeyPos[vertIds[j]] - vertPos[vertIds[j]]; - } - */ + for(int i = 0; i < numVertices; i++) + vertices[i].shapeKeyOffsets = shapeKeyOffsets[vertIds[i]]; } const char *fullSkeletonName = meshEl->Attribute("skeleton"); From 112a73fb8a1417771585997e59b7751ea8ad9d62 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 1 Sep 2024 16:14:01 +0300 Subject: [PATCH 04/19] fixed quad subdivision bugs --- mesh.cpp | 5 +++- quad.cpp | 78 ++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/mesh.cpp b/mesh.cpp index 1ac93b4..1728d9b 100755 --- a/mesh.cpp +++ b/mesh.cpp @@ -95,7 +95,10 @@ namespace vb01{ void Mesh::updateVerts(MeshData meshData){ glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * sizeof(MeshData::Vertex) * meshBase.numTris, meshData.vertices); + + MeshData::OldVertex *glVertData = meshBase.toGlVerts(); + glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * sizeof(MeshData::OldVertex) * meshBase.numTris, glVertData); + delete glVertData; } void Mesh::update(){ diff --git a/quad.cpp b/quad.cpp index 96adad6..076b313 100755 --- a/quad.cpp +++ b/quad.cpp @@ -1,6 +1,10 @@ #include "quad.h" +#include + namespace vb01{ + using namespace std; + Quad::Quad(Vector3 size, bool spatial, int numVertDiv, int numHorDiv){ this->spatial = spatial; this->numVertDiv = numVertDiv; @@ -14,58 +18,72 @@ namespace vb01{ this->size = size; const int numHorQuads = numVertDiv + 1, numVertQuads = numHorDiv + 1; - const int numTris = 2 * numHorQuads * numVertQuads, numVerts = 3 * numTris; + const int numVertPos = (numHorQuads + 1) * (numVertQuads + 1), numTris = 2 * numHorQuads * numVertQuads, numVerts = 3 * numTris; Vector2 subQuadSize = Vector2(size.x / numHorQuads, size.y / numVertQuads); MeshData::Vertex *vertices = new MeshData::Vertex[numVerts]; - Vector3 *faceVertPos = new Vector3[6]; - Vector3 *norm = new Vector3(Vector3::VEC_J); + if(!meshBase.positions){ + meshBase.positions = new Vector3[numVertPos]; + meshBase.normals = new Vector3(Vector3::VEC_J); + meshBase.indices = new u32[numVerts]; + + for(int i = 0; i < numVerts; i++) + meshBase.indices[i] = i; + } + + Vector3 *faceVertPos = meshBase.positions; + Vector3 *norm = meshBase.normals; + u32 *indices = meshBase.indices; for(int i = 0; i < numHorQuads; i++){ for(int j = 0; j < numVertQuads; j++){ - int id = i * 6 * numHorQuads + j * 6; + int vertPosId = i * (numHorQuads + 1) + j; + int vertPosId2 = (i + 1) * (numHorQuads + 1) + j; Vector2 offset = Vector2(subQuadSize.x, subQuadSize.y); - faceVertPos[0] = Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * i); - faceVertPos[1] = Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * (i + 1)); - faceVertPos[2] = Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * i); - faceVertPos[3] = Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * i); - faceVertPos[4] = Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * (i + 1)); - faceVertPos[5] = Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * (i + 1)); + faceVertPos[vertPosId] = Vector3(-.5 * size.x + offset.x * i, 0, -.5 * size.y + offset.y * j); + faceVertPos[vertPosId + 1] = Vector3(-.5 * size.x + offset.x * i, 0, -.5 * size.y + offset.y * (j + 1)); + faceVertPos[vertPosId2] = Vector3(-.5 * size.x + offset.x * (i + 1), 0, -.5 * size.y + offset.y * j); + faceVertPos[vertPosId2 + 1] = Vector3(-.5 * size.x + offset.x * (i + 1), 0, -.5 * size.y + offset.y * (j + 1)); + + if(!spatial){ + int ids[4]{vertPosId, vertPosId + 1, vertPosId2, vertPosId2 + 1}; + + swap(faceVertPos[ids[0]].z, faceVertPos[ids[1]].z); + swap(faceVertPos[ids[2]].z, faceVertPos[ids[3]].z); + + for(int k = 0; k < 4; k++){ + faceVertPos[ids[k]].y = -faceVertPos[ids[k]].z; + faceVertPos[ids[k]].z = 0; + faceVertPos[ids[k]] += .5 * Vector3(size.x, size.y, 0); + } + } Vector2 faceVertUv[]{ - Vector2(float(j) / numHorQuads, float(i) / numVertQuads), - Vector2(float(j + 1) / numHorQuads, float(i + 1) / numVertQuads), - Vector2(float(j + 1) / numHorQuads, float(i) / numVertQuads), - Vector2(float(j) / numHorQuads, float(i) / numVertQuads), - Vector2(float(j) / numHorQuads, float(i + 1) / numVertQuads), - Vector2(float(j + 1) / numHorQuads, float(i + 1) / numVertQuads), + Vector2(float(i) / numHorQuads, 1 - float(j) / numVertQuads), + Vector2(float(i) / numHorQuads, 1 - float(j + 1) / numVertQuads), + Vector2(float(i + 1) / numHorQuads, 1 - float(j + 1) / numVertQuads), + Vector2(float(i + 1) / numHorQuads, 1 - float(j + 1) / numVertQuads), + Vector2(float(i + 1) / numHorQuads, 1 - float(j) / numVertQuads), + Vector2(float(i) / numHorQuads, 1 - float(j) / numVertQuads), }; - for(int k = 0; k < 6; k++){ - if(!spatial){ - faceVertPos[k].y = -faceVertPos[k].z; - faceVertPos[k].z = 0; - faceVertPos[k] += .5 * Vector3(size.x, size.y, 0); - } + int quadId = 6 * (i * numHorQuads + j); + int vertPosIds[6]{vertPosId, vertPosId + 1, vertPosId2 + 1, vertPosId2 + 1, vertPosId2, vertPosId}; + for(int k = 0; k < 6; k++){ MeshData::Vertex v; - v.pos = &faceVertPos[k]; + v.pos = &faceVertPos[vertPosIds[k]]; v.uv = faceVertUv[k]; v.tan = Vector3::VEC_I; v.norm = norm; v.biTan = Vector3::VEC_K; - vertices[id + k] = v; + vertices[quadId + k] = v; } } } - u32 *indices = new u32[numVerts]; - - for(int i = 0; i < numVerts; i++) - indices[i] = i; - - meshBase = MeshData((Vector3*)faceVertPos, nullptr, nullptr, nullptr, 6, nullptr, vertices, indices, numTris); + meshBase = MeshData(faceVertPos, nullptr, nullptr, nullptr, 6, norm, vertices, indices, numTris); } } From 8eca2ecc708546f8acd5465cfa5073436ff6dad7 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Thu, 5 Sep 2024 20:35:09 +0300 Subject: [PATCH 05/19] renamed struct --- mesh.cpp | 22 +++++++++++----------- meshData.cpp | 4 ++-- meshData.h | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/mesh.cpp b/mesh.cpp index 1728d9b..64de30e 100755 --- a/mesh.cpp +++ b/mesh.cpp @@ -44,12 +44,12 @@ namespace vb01{ glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); - u32 size = sizeof(MeshData::OldVertex); + u32 size = sizeof(MeshData::GpuVertex); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); - MeshData::OldVertex *glVertData = meshBase.toGlVerts(); + MeshData::GpuVertex *glVertData = meshBase.toGpuVerts(); glBufferData(GL_ARRAY_BUFFER, 3 * meshBase.numTris * size, glVertData, GL_DYNAMIC_DRAW); delete glVertData; @@ -58,21 +58,21 @@ namespace vb01{ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, size, (void*)0); glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, norm))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, norm))); glEnableVertexAttribArray(1); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, uv))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, uv))); glEnableVertexAttribArray(2); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, tan))); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, tan))); glEnableVertexAttribArray(3); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, biTan))); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, biTan))); glEnableVertexAttribArray(4); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, weights))); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, weights))); glEnableVertexAttribArray(5); - glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, boneIndices))); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, boneIndices))); glEnableVertexAttribArray(6); for(int i = 0; i < meshBase.numShapeKeys; i++){ - glVertexAttribPointer(7 + i, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::OldVertex, shapeKeyOffsets) + 3 * i * sizeof(float))); + glVertexAttribPointer(7 + i, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, shapeKeyOffsets) + 3 * i * sizeof(float))); glEnableVertexAttribArray(7 + i); } } @@ -96,8 +96,8 @@ namespace vb01{ void Mesh::updateVerts(MeshData meshData){ glBindBuffer(GL_ARRAY_BUFFER, VBO); - MeshData::OldVertex *glVertData = meshBase.toGlVerts(); - glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * sizeof(MeshData::OldVertex) * meshBase.numTris, glVertData); + MeshData::GpuVertex *glVertData = meshBase.toGpuVerts(); + glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * sizeof(MeshData::GpuVertex) * meshBase.numTris, glVertData); delete glVertData; } diff --git a/meshData.cpp b/meshData.cpp index f3d17bb..ba7572b 100644 --- a/meshData.cpp +++ b/meshData.cpp @@ -17,9 +17,9 @@ namespace vb01{ } } - MeshData::OldVertex* MeshData::toGlVerts(){ + MeshData::GpuVertex* MeshData::toGpuVerts(){ int numVertices = 3 * numTris; - OldVertex *vertData = new OldVertex[numVertices]; + GpuVertex *vertData = new GpuVertex[numVertices]; for(int i = 0; i < numVertices; i++){ vertData[i].pos = *vertices[i].pos; diff --git a/meshData.h b/meshData.h index 568047f..6ca0ced 100644 --- a/meshData.h +++ b/meshData.h @@ -19,7 +19,7 @@ namespace vb01{ void animate(float, KeyframeChannel); }; - struct OldVertex{ + struct GpuVertex{ Vector3 pos, norm, tan, biTan; Vector2 uv; float weights[4]{0, 0, 0, 0}; @@ -35,7 +35,7 @@ namespace vb01{ Vector3 *shapeKeyOffsets = nullptr; }; - OldVertex* toGlVerts(); + GpuVertex* toGpuVerts(); Vector3 *positions = nullptr, *normals = nullptr, **shapeKeyOffsets = nullptr; float **weights = nullptr; From 8ba95bbbfe61c5684b3b0274798e0cfc5b3749f1 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Fri, 6 Sep 2024 18:36:45 +0300 Subject: [PATCH 06/19] bugfix --- model.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/model.cpp b/model.cpp index bb5dbd0..8d5f46a 100755 --- a/model.cpp +++ b/model.cpp @@ -32,10 +32,8 @@ namespace vb01{ getDescendants(descendants); for(Node *node : descendants) - for(Mesh *mesh : node->getMeshes()){ - delete mesh->getMaterial(); + for(Mesh *mesh : node->getMeshes()) mesh->setMaterial(nullptr); - } while(!children.empty()){ Node *c = children[children.size() - 1]; From 37b791342abd722c13621220c461bc5dffbe84ab Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sat, 7 Sep 2024 11:34:14 +0300 Subject: [PATCH 07/19] lighting calculation bugfix --- texture.frag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/texture.frag b/texture.frag index e0b6333..ae5330c 100755 --- a/texture.frag +++ b/texture.frag @@ -133,9 +133,9 @@ void main(){ float shadow = getShadow(i); diffuseCol *= (1.0 - shadow); } - - finalColor *= vec4(diffuseCol + specularCol, 1); } + + finalColor *= vec4(diffuseCol + specularCol, 1); } float brightness = dot(finalColor.rgb, vec3(0.2126, 0.7152, 0.0722)); From 1f5d1bc94d7ee0df2e9fba63bd877568a4e6faf0 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 8 Sep 2024 14:23:23 +0300 Subject: [PATCH 08/19] reader shaders as assets --- CMakeLists.txt | 4 +-- assetManager.cpp | 34 ++++++++++++++++++ assetManager.h | 1 + shader.cpp | 94 +++++++++--------------------------------------- shader.h | 10 +++--- shaderAsset.h | 17 +++++++++ shaderReader.cpp | 30 ++++++++++++++++ shaderReader.h | 16 +++++++++ 8 files changed, 122 insertions(+), 84 deletions(-) create mode 100644 shaderAsset.h create mode 100644 shaderReader.cpp create mode 100644 shaderReader.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ef4915..5800646 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,8 +18,8 @@ set(MATH quaternion.cpp vector.cpp matrix.cpp rayCaster.cpp) set(RENDER lineRenderer.cpp particleEmitter.cpp camera.cpp light.cpp material.cpp mesh.cpp meshData.cpp model.cpp node.cpp quad.cpp box.cpp root.cpp shader.cpp texture.cpp) set(ANIM animationController.cpp animationChannel.cpp animation.cpp animatable.cpp keyframeChannel.cpp driver.cpp) set(ARMATURE skeleton.cpp bone.cpp ikSolver.cpp) -set(ASSET_MANAGER assetManager.cpp textAsset.h imageAsset.h modelAsset.h fontAsset.h) -set(ASSET_READERS imageReader.cpp fontReader.cpp modelReader.cpp xmlModelReader.cpp) +set(ASSET_MANAGER assetManager.cpp shaderAsset.h textAsset.h imageAsset.h modelAsset.h fontAsset.h) +set(ASSET_READERS shaderReader.cpp imageReader.cpp fontReader.cpp modelReader.cpp xmlModelReader.cpp) if(BUILD_WITH_ASSIMP) set(ASSET_READERS ${ASSET_READERS} assimpModelReader.cpp) diff --git a/assetManager.cpp b/assetManager.cpp index 63b106b..8bdfdf8 100644 --- a/assetManager.cpp +++ b/assetManager.cpp @@ -1,8 +1,13 @@ #include "assetManager.h" #include "abstractAssetReader.h" #include "util.h" +#include "root.h" +#include "node.h" +#include "mesh.h" +#include "material.h" #include "imageReader.h" #include "fontReader.h" +#include "shaderReader.h" #include "xmlModelReader.h" #include @@ -71,6 +76,11 @@ namespace vb01{ if(find(modelFormats.begin(), modelFormats.end(), format) != modelFormats.end()) assetReader = XmlModelReader::getSingleton(); + vector shaderFormats = vector{"vert", "frag", "geo"}; + + if(find(shaderFormats.begin(), shaderFormats.end(), format) != shaderFormats.end()) + assetReader = ShaderReader::getSingleton(); + if(assetReader) assets.push_back(assetReader->readAsset(file)); else @@ -85,4 +95,28 @@ namespace vb01{ return nullptr; } + + void AssetManager::editAsset(string path, Asset &newAsset){ + ShaderAsset *oldAsset = (ShaderAsset*)getAsset(path); + + if(oldAsset){ + oldAsset->shaderString = ((ShaderAsset&)newAsset).shaderString; + + Root *root = Root::getSingleton(); + vector descendants; + root->getRootNode()->getDescendants(descendants); + root->getGuiNode()->getDescendants(descendants); + + for(Node *desc : descendants){ + vector meshes = desc->getMeshes(); + + for(Mesh *mesh : meshes){ + Material *mat = mesh->getMaterial(); + + if(mat) + mat->getShader()->loadShaders(); + } + } + } + } } diff --git a/assetManager.h b/assetManager.h index 262e9c1..d84e4f7 100644 --- a/assetManager.h +++ b/assetManager.h @@ -12,6 +12,7 @@ namespace vb01{ public: static AssetManager* getSingleton(); void load(std::string, bool = false); + void editAsset(std::string, Asset&); Asset* getAsset(std::string); inline Asset* getAsset(int i){return assets[i];} inline std::vector getAssets(){return assets;} diff --git a/shader.cpp b/shader.cpp index 79e6035..4a63f0c 100755 --- a/shader.cpp +++ b/shader.cpp @@ -1,20 +1,19 @@ #include "glad.h" #include #include -#include -#include -#include "shader.h" #include #include +#include "shader.h" +#include "assetManager.h" + using namespace std; using namespace glm; namespace vb01{ Shader::Shader(string shaderPath, bool geometry){ this->geometry = geometry; - this->path = shaderPath; initShaders(shaderPath + ".vert", shaderPath + ".frag", shaderPath + ".geo"); loadShaders(); @@ -22,7 +21,6 @@ namespace vb01{ Shader::Shader(string vertShader, string fragShader){ this->geometry = false; - this->path = vertShader; initShaders(vertShader, fragShader, ""); loadShaders(); @@ -30,88 +28,30 @@ namespace vb01{ Shader::Shader(string vertShader, string fragShader, string geoShader){ this->geometry = true; - this->path = vertShader; initShaders(vertShader, fragShader, geoShader); loadShaders(); } - Shader::~Shader(){} - string Shader::getName(){ - int dirId = path.find_last_of('/'); - string name = (dirId != -1 ? path.substr(dirId + 1) : path); + int dirId = vString->path.find_last_of('/'); + string name = (dirId != -1 ? vString->path.substr(dirId + 1) : vString->path); - int dotId = path.find_last_of('.'); + int dotId = name.find_last_of('.'); - if(dotId != -1) - name = name.substr(0, dotId); + if(dotId != -1) + name = name.substr(0, dotId); - return name; + return name; } void Shader::initShaders(string vertShaderPath, string fragShaderPath, string geoShaderPath){ - ifstream vertShaderFile, fragShaderFile; - vertShaderFile.open(vertShaderPath); - fragShaderFile.open(fragShaderPath); - - stringstream vertShaderStream, fragShaderStream; - vertShaderStream << vertShaderFile.rdbuf(); - fragShaderStream << fragShaderFile.rdbuf(); - - vertShaderFile.close(); - fragShaderFile.close(); - - vString = vertShaderStream.str(); - fString = fragShaderStream.str(); + AssetManager *am = AssetManager::getSingleton(); + vString = (ShaderAsset*)am->getAsset(vertShaderPath); + fString = (ShaderAsset*)am->getAsset(fragShaderPath); - if(geometry){ - ifstream geoShaderFile; - geoShaderFile.open(geoShaderPath); - - stringstream geoShaderStream; - geoShaderStream << geoShaderFile.rdbuf(); - - geoShaderFile.close(); - gString = geoShaderStream.str(); - } - } - - void Shader::editShader(ShaderType type, int line, string insertion){ - replaceLine(type, line, insertion); - loadShaders(); - } - - void Shader::replaceLine(ShaderType type, int line, string insertion){ - string *shaderString; - - switch(type){ - case VERTEX_SHADER: - shaderString = &vString; - break; - case FRAGMENT_SHADER: - shaderString = &fString; - break; - case GEOMETRY_SHADER: - shaderString = &gString; - break; - } - - int numPassedLines = 0, lineStart = -1, lineEnd = -1; - for(int i = 0; i < shaderString->length(); i++) - if(shaderString[0][i] == '\n'){ - if(numPassedLines == line - 1) - lineStart = i + 1; - - if(numPassedLines == line){ - lineEnd = i; - break; - } - - numPassedLines++; - } - - *shaderString = shaderString->substr(0, lineStart) + insertion + shaderString->substr(lineEnd); + if(geometry) + gString = (ShaderAsset*)am->getAsset(geoShaderPath); } void Shader::pushShader(u32 &type, string &sString, int glType, ErrorType errorType){ @@ -124,11 +64,11 @@ namespace vb01{ void Shader::loadShaders(){ u32 vert, geo, frag; - pushShader(vert, vString, GL_VERTEX_SHADER, VERTEX_ERROR); - pushShader(frag, fString, GL_FRAGMENT_SHADER, FRAGMENT_ERROR); + pushShader(vert, vString->shaderString, GL_VERTEX_SHADER, VERTEX_ERROR); + pushShader(frag, fString->shaderString, GL_FRAGMENT_SHADER, FRAGMENT_ERROR); if(geometry) - pushShader(geo, gString, GL_GEOMETRY_SHADER, GEOMETRY_ERROR); + pushShader(geo, gString->shaderString, GL_GEOMETRY_SHADER, GEOMETRY_ERROR); id = glCreateProgram(); glAttachShader(id, vert); diff --git a/shader.h b/shader.h index 7092516..15ea0a0 100755 --- a/shader.h +++ b/shader.h @@ -4,6 +4,7 @@ #include #include +#include "shaderAsset.h" #include "vector.h" #include "util.h" @@ -17,10 +18,10 @@ namespace vb01{ Shader(std::string, bool = false); Shader(std::string, std::string); Shader(std::string, std::string, std::string); - ~Shader(); + ~Shader(){} std::string getName(); - void setNumLights(int); void use(); + void loadShaders(); void setMat4(glm::mat4, std::string); void setVec4(Vector4, std::string); void setVec3(Vector3, std::string); @@ -29,17 +30,16 @@ namespace vb01{ void setBool(bool, std::string); void setInt(int, std::string); void setUnsignedInt(u32, std::string); - void editShader(ShaderType, int, std::string); + void editShader(ShaderType, int, std::string){} inline bool isGeometry(){return geometry;} private: void initShaders(std::string, std::string, std::string); void replaceLine(ShaderType, int, std::string); - void loadShaders(); void pushShader(u32&, std::string&, int, ErrorType); void checkCompileErrors(u32, ErrorType); u32 id; bool geometry = false; - std::string path, vString, fString, gString; + ShaderAsset *vString = nullptr, *fString = nullptr, *gString = nullptr; friend class ShaderTest; }; diff --git a/shaderAsset.h b/shaderAsset.h new file mode 100644 index 0000000..75fa384 --- /dev/null +++ b/shaderAsset.h @@ -0,0 +1,17 @@ +#ifndef SHADER_ASSET_H +#define SHADER_ASSET_H + +#include "asset.h" + +namespace vb01{ + struct ShaderAsset : public Asset{ + std::string shaderString = ""; + + ShaderAsset(std::string p, std::string str){ + path = p; + shaderString = str; + } + }; +} + +#endif diff --git a/shaderReader.cpp b/shaderReader.cpp new file mode 100644 index 0000000..48a6682 --- /dev/null +++ b/shaderReader.cpp @@ -0,0 +1,30 @@ +#include "shaderReader.h" +#include "shaderAsset.h" + +#include +#include + +namespace vb01{ + using namespace std; + + static ShaderReader *shaderReader = nullptr; + + ShaderReader* ShaderReader::getSingleton(){ + if(!shaderReader) + shaderReader = new ShaderReader(); + + return shaderReader; + } + + Asset* ShaderReader::readAsset(string path){ + ifstream shaderFile; + shaderFile.open(path); + + stringstream shaderStream; + shaderStream << shaderFile.rdbuf(); + + shaderFile.close(); + + return new ShaderAsset(path, shaderStream.str()); + } +} diff --git a/shaderReader.h b/shaderReader.h new file mode 100644 index 0000000..379b0a4 --- /dev/null +++ b/shaderReader.h @@ -0,0 +1,16 @@ +#ifndef SHADER_READER_H +#define SHADER_READER_H + +#include "abstractAssetReader.h" + +namespace vb01{ + class ShaderReader : public AbstractAssetReader{ + public: + static ShaderReader* getSingleton(); + Asset* readAsset(std::string); + private: + ShaderReader(){} + }; +} + +#endif From 1719cdf98d96e23f79118bd41cc7d7afbff9cba1 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 8 Sep 2024 14:23:56 +0300 Subject: [PATCH 09/19] adding shader assets --- root.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/root.cpp b/root.cpp index 01bb698..0c0c1d5 100755 --- a/root.cpp +++ b/root.cpp @@ -5,6 +5,7 @@ #include "box.h" #include "quad.h" #include "lineRenderer.h" +#include "assetManager.h" #include "animationController.h" #include "glad.h" @@ -22,6 +23,7 @@ namespace vb01{ Root* Root::getSingleton(){ if(!root) root = new Root(); + return root; } @@ -47,6 +49,8 @@ namespace vb01{ this->height = height; this->libPath = libPath; + AssetManager::getSingleton()->load(Root::getSingleton()->getLibPath()); + initWindow(name); brdfLutPlane = new Quad(Vector3(1, 1, 1) * 2); @@ -59,7 +63,7 @@ namespace vb01{ initBloomFramebuffer(); initGuiPlane(fragTexture, brightTexture); - shader = new Shader(Root::getSingleton()->getLibPath() + "line3D"); + shader = new Shader(Root::getSingleton()->getLibPath() + "line3D"); } void Root::initWindow(string name){ From 63429dacbe02917ece2cc3d01e84fb44011ba98d Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 8 Sep 2024 14:24:17 +0300 Subject: [PATCH 10/19] fixed normal calculation --- xmlModelReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmlModelReader.cpp b/xmlModelReader.cpp index 25eeb38..f268ab7 100644 --- a/xmlModelReader.cpp +++ b/xmlModelReader.cpp @@ -132,7 +132,7 @@ namespace vb01{ float biTanZ = atof(vertEl->Attribute("bz")); Vector3 biTan = Vector3(biTanX, biTanY, biTanZ); - normals[i] = tan.cross(biTan); + normals[i] = biTan.cross(tan); MeshData::Vertex vertex; vertex.pos = &vertPos[id]; From 39dc1afd25c12290e8e49b1df56a4e474c13ad47 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 8 Sep 2024 14:24:44 +0300 Subject: [PATCH 11/19] using new way to edit shaders --- node.cpp | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/node.cpp b/node.cpp index d57cd3e..3560121 100755 --- a/node.cpp +++ b/node.cpp @@ -1,19 +1,24 @@ #include "root.h" #include "bone.h" #include "mesh.h" -#include "particleEmitter.h" -#include "light.h" #include "text.h" -#include "material.h" +#include "light.h" #include "matrix.h" +#include "material.h" #include "skeleton.h" +#include "shaderAsset.h" +#include "particleEmitter.h" +#include "assetManager.h" #include "animationController.h" +#include + #include #include using namespace std; using namespace glm; +using namespace boost; namespace vb01{ Node::Node(Vector3 pos, Quaternion orientation, Vector3 scale, string name, Animatable::Type type) : Animatable(type, name){ @@ -245,6 +250,7 @@ namespace vb01{ lights.push_back(light); light->onAttached(this); updateShaders(); + } void Node::removeLight(int id){ @@ -439,27 +445,23 @@ namespace vb01{ void Node::updateShaders(){ Root *root = Root::getSingleton(); + AssetManager *am = AssetManager::getSingleton(); + ShaderAsset *sa = (ShaderAsset*)am->getAsset(root->getLibPath() + "texture.frag"); + string shaderStr = sa->shaderString; + int numLights = root->getNumLights(); - Node *rootNode = root->getRootNode(); - vector descendants; - rootNode->getDescendants(descendants); - descendants.push_back(rootNode); + string str1 = "const int numLights = " + to_string(numLights > 0 ? numLights : 1) + ";"; + int a1 = std::distance(shaderStr.begin(), find_nth(shaderStr, "\n", 0).begin()); + int a2 = std::distance(shaderStr.begin(), find_nth(shaderStr, "\n", 1).begin()); + shaderStr.replace(a1 + 1, a2 - a1 - 1, str1); - for(Node *n : descendants){ - vector meshes = n->getMeshes(); + string str2 = "const bool checkLights = " + string(numLights > 0 ? "true" : "false") + ";"; + a1 = std::distance(shaderStr.begin(), find_nth(shaderStr, "\n", 1).begin()); + a2 = std::distance(shaderStr.begin(), find_nth(shaderStr, "\n", 2).begin()); + shaderStr.replace(a1 + 1, a2 - a1 - 1, str2); - for(Mesh *m : meshes){ - Material *mat = m->getMaterial(); - - if(mat){ - int numLights = root->getNumLights(); - string str1 = "const int numLights = " + to_string(numLights > 0 ? numLights : 1) + ";"; - mat->getShader()->editShader(Shader::FRAGMENT_SHADER, 1, str1); - string str2 = "const bool checkLights = " + string(numLights > 0 ? "true" : "false") + ";"; - mat->getShader()->editShader(Shader::FRAGMENT_SHADER, 2, str2); - } - } - } + ShaderAsset sa2(sa->path, shaderStr); + am->editAsset(sa->path, sa2); } void Node::setOrientation(Quaternion q){ From 93e479662f24be28e77ba00d944a620b38c57248 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 8 Sep 2024 20:32:34 +0300 Subject: [PATCH 12/19] lighting fixes --- texture.frag | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/texture.frag b/texture.frag index ae5330c..38a3aa4 100755 --- a/texture.frag +++ b/texture.frag @@ -98,11 +98,14 @@ void main(){ if(checkLights){ for(int i = 0; i < numLights; i++){ vec3 lightDir = vec3(0), viewDir = normalize(camPos - fragPos); - float attenuation = 1.0; - float a = lights[i].a, b = lights[i].b, c = lights[i].c, dist = length(fragPos - lights[i].pos), factor, coef = 1; + float attenuation = 1.0, coef = 1; if(lights[i].type == 0){ lightDir = normalize(lights[i].pos - fragPos); + + float a = lights[i].a, b = lights[i].b, c = lights[i].c; + float dist = length(fragPos - lights[i].pos); + attenuation = 1.0 / (a * dist * dist + b * dist + c); } else if(lights[i].type == 1) @@ -120,8 +123,8 @@ void main(){ continue; } - factor = max(dot(lightDir, normal), 0.); - diffuseCol += lights[i].color * (factor * attenuation * coef); + float factor = (lights[i].type < 3 ? (max(dot(lightDir, normalize(normal)), 0.) * attenuation * coef) : 1); + diffuseCol += lights[i].color * factor; if(specularMapEnabled){ float specularSample = texture(textures[2].pastTexture, texCoords).r; @@ -130,8 +133,8 @@ void main(){ specularCol += specularStrength * spec * specularSample * lights[i].color; } - float shadow = getShadow(i); - diffuseCol *= (1.0 - shadow); + if(castShadow) + diffuseCol *= (1.0 - getShadow(i)); } } From 059136a6887587ba7d2d0be8a70c70b6541dfe3b Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sun, 8 Sep 2024 20:33:13 +0300 Subject: [PATCH 13/19] removing lights by pointer --- node.cpp | 12 ++++++++++++ node.h | 1 + 2 files changed, 13 insertions(+) diff --git a/node.cpp b/node.cpp index 3560121..ce478d9 100755 --- a/node.cpp +++ b/node.cpp @@ -253,6 +253,18 @@ namespace vb01{ } + void Node::removeLight(Light *light){ + for(int i = 0; i < lights.size(); i++) + if(lights[i] == light){ + lights.erase(lights.begin() + i); + + Root::getSingleton()->shiftNumLights(false); + updateShaders(); + + break; + } + } + void Node::removeLight(int id){ Root::getSingleton()->shiftNumLights(false); Light *light = lights[id]; diff --git a/node.h b/node.h index bce352c..46aec28 100755 --- a/node.h +++ b/node.h @@ -31,6 +31,7 @@ namespace vb01{ void attachChild(Node*); void dettachChild(Node*); void addLight(Light*); + void removeLight(Light*); void removeLight(int); void addText(Text*); virtual void lookAt(Vector3, Vector3); From 1103e527a8a7e622318208d6f436d734d6eb4863 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Wed, 11 Sep 2024 20:23:25 +0300 Subject: [PATCH 14/19] added angle usage, attenuation, additive lighting properties --- light.cpp | 4 ++++ light.h | 12 +++++++++++- texture.frag | 49 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/light.cpp b/light.cpp index 4984e62..db080fe 100755 --- a/light.cpp +++ b/light.cpp @@ -185,6 +185,7 @@ namespace vb01{ shader->setVec3(color, "lights[" + to_string(thisId) + "].color"); shader->setFloat(nearPlane, "lights[" + to_string(thisId) + "].near"); shader->setFloat(farPlane, "lights[" + to_string(thisId) + "].far"); + shader->setBool(additiveLighting, "lights[" + to_string(thisId) + "].additive"); int depthMapId = 10; shader->setInt(depthMapId, "lights[" + to_string(thisId) + "].depthMap"); @@ -194,9 +195,12 @@ namespace vb01{ switch(type){ case POINT: shader->setVec3(position, "lights[" + to_string(thisId) + "].pos"); + shader->setInt((int)attenuation, "lights[" + to_string(thisId) + "].attenuation"); + shader->setFloat(radius, "lights[" + to_string(thisId) + "].radius"); shader->setFloat(attenuationValues.x, "lights[" + to_string(thisId) + "].a"); shader->setFloat(attenuationValues.y, "lights[" + to_string(thisId) + "].b"); shader->setFloat(attenuationValues.z, "lights[" + to_string(thisId) + "].c"); + shader->setBool(useAngle, "lights[" + to_string(thisId) + "].additive"); break; case DIRECTIONAL: shader->setMat4(proj * view, "lights[" + to_string(thisId) + "].lightMat"); diff --git a/light.h b/light.h index 1732d94..93d47b5 100755 --- a/light.h +++ b/light.h @@ -17,6 +17,7 @@ namespace vb01{ class Light : public Animatable, public Attachable{ public: enum Type{POINT, DIRECTIONAL, SPOT, AMBIENT}; + enum Attenuation{QUADRATIC, LINEAR, NONE}; Light(Type, std::string = ""); ~Light(); @@ -31,7 +32,14 @@ namespace vb01{ inline void setOuterAngle(float outerAngle){this->outerAngle = outerAngle;} inline void setShadowNearPlane(float nearPlane){this->nearPlane = nearPlane;} inline void setShadowFarPlane(float farPlane){this->farPlane = farPlane;} + inline void setAttenuation(Attenuation at){this->attenuation = at;} + inline void setRadius(float r){this->radius = r;} + inline void setAdditiveLighting(bool al){this->additiveLighting = al;} + inline void setUseAngle(bool ua){this->useAngle = ua;} + inline Attenuation getAttenuation(){return attenuation;} inline Vector3 getAttenuationValues(){return attenuationValues;} + inline bool isAdditiveLighting(){return additiveLighting;} + inline float getRadius(){return radius;} inline float getInnerAngle(){return innerAngle;} inline float getOuterAngle(){return outerAngle;} inline float getShadowNearPlane(){return nearPlane;} @@ -43,10 +51,12 @@ namespace vb01{ void updateShader(std::vector, int, glm::mat4&, glm::mat4&); Type type; + bool additiveLighting = true, useAngle = true; + Attenuation attenuation = Attenuation::QUADRATIC; Shader *depthMapShader; Texture *depthMap = nullptr; Vector3 color = Vector3::VEC_IJK, attenuationValues = Vector3(1.8, .7, 1); - float innerAngle = .707, outerAngle = .714, nearPlane = .1, farPlane = 100; + float innerAngle = .707, outerAngle = .714, nearPlane = .1, farPlane = 100, radius = 0; unsigned int depthmapFBO, depthMapSize = 1024; }; } diff --git a/texture.frag b/texture.frag index 38a3aa4..b8023e1 100755 --- a/texture.frag +++ b/texture.frag @@ -15,10 +15,11 @@ layout (location = 1) out vec4 BrightColor; //0-POINT,1-DIRECTIONAL,2-SPOT struct Light{ - int type; + bool useAngle, additive; + int type, attenuation; vec3 pos, color, direction; float innerAngle, outerAngle; - float a, b, c, near, far; + float a, b, c, near, far, radius; sampler2D depthMap; samplerCube depthMapCube; mat4 lightMat; @@ -33,7 +34,7 @@ struct Texture{ uniform Texture textures[4]; uniform samplerCube environmentMap; uniform Light lights[numLights]; -uniform bool lightingEnabled, texturingEnabled, normalMapEnabled, specularMapEnabled, castShadow, environmentMapEnabled; +uniform bool lightingEnabled, constLightingEnabled, texturingEnabled, normalMapEnabled, specularMapEnabled, castShadow, environmentMapEnabled; uniform vec4 diffuseColor, specularColor; uniform float shinyness, specularStrength; uniform vec3 camPos; @@ -96,20 +97,36 @@ void main(){ vec3 diffuseCol = vec3(0), specularCol = vec3(0); if(checkLights){ + bool addedLighting = false; + for(int i = 0; i < numLights; i++){ vec3 lightDir = vec3(0), viewDir = normalize(camPos - fragPos); - float attenuation = 1.0, coef = 1; + float attenuation = 0, coef = 1; + float factor = 0; + bool canAdd = false; if(lights[i].type == 0){ lightDir = normalize(lights[i].pos - fragPos); + float dist = length(lights[i].pos - fragPos), radius = lights[i].radius; - float a = lights[i].a, b = lights[i].b, c = lights[i].c; - float dist = length(fragPos - lights[i].pos); - - attenuation = 1.0 / (a * dist * dist + b * dist + c); + if(lights[i].attenuation == 0){ + float a = lights[i].a, b = lights[i].b, c = lights[i].c; + attenuation = 1.0 / (a * dist * dist + b * dist + c); + factor = (lights[i].useAngle ? max(dot(lightDir, normalize(normal)), 0.) : 1) * attenuation; + } + else if(lights[i].attenuation == 1 && dist < radius && radius > 0){ + canAdd = !lights[i].additive; + factor = 1.0 - dist / lights[i].radius; + } + else if(lights[i].attenuation == 2 && dist < radius && radius > 0){ + canAdd = !lights[i].additive; + factor = 1; + } } - else if(lights[i].type == 1) + else if(lights[i].type == 1){ lightDir = -normalize(lights[i].direction); + factor = max(dot(lightDir, normalize(normal)), 0.) * attenuation * coef; + } else if(lights[i].type == 2){ lightDir = normalize(lights[i].pos - fragPos); float innerAngle = lights[i].innerAngle; @@ -121,10 +138,18 @@ void main(){ if(angle > lights[i].outerAngle) continue; - } - float factor = (lights[i].type < 3 ? (max(dot(lightDir, normalize(normal)), 0.) * attenuation * coef) : 1); - diffuseCol += lights[i].color * factor; + factor = max(dot(lightDir, normalize(normal)), 0.) * attenuation * coef; + } + else factor = 1; + + + if(lights[i].additive) + diffuseCol += lights[i].color * factor; + else if(!lights[i].additive && constLightingEnabled && !addedLighting && canAdd){ + addedLighting = true; + diffuseCol += lights[i].color * factor; + } if(specularMapEnabled){ float specularSample = texture(textures[2].pastTexture, texCoords).r; From 0b99083bab7c4ec6dc706ac4b0df0f4d1b8d60b9 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Fri, 13 Sep 2024 19:46:57 +0300 Subject: [PATCH 15/19] refactored light updating to account for lights in hidden nodes --- light.cpp | 19 ++++++++++++++----- light.h | 4 +++- node.cpp | 6 +++--- texture.frag | 8 +++++--- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/light.cpp b/light.cpp index db080fe..0f423e2 100755 --- a/light.cpp +++ b/light.cpp @@ -75,32 +75,39 @@ namespace vb01{ glBindFramebuffer(GL_FRAMEBUFFER, *(Root::getSingleton()->getFBO())); } - void Light::update(){ + void Light::update(bool render){ Root *root = Root::getSingleton(); Node *rootNode = root->getRootNode(); vector descendants; rootNode->getDescendants(descendants); descendants.push_back(rootNode); + vector lights; vector materials; for(Node *d : descendants){ for(Light *l : d->getLights()) lights.push_back(l); - for(Mesh *m : d->getMeshes()) - materials.push_back(m->getMaterial()); + for(Mesh *mesh : d->getMeshes()) + materials.push_back(mesh->getMaterial()); } int thisId = -1; + for(int i = 0; i < lights.size(); i++) if(lights[i] == this) thisId = i; + for(Material *mat : materials){ + Shader *shader = mat->getShader(); + shader->use(); + shader->setBool(render, "lights[" + to_string(thisId) + "].render"); + } + mat4 proj = mat4(1.), view = mat4(1.); renderShadow(descendants, proj, view); updateShader(materials, thisId, proj, view); - } void Light::renderShadow(std::vector descendants, mat4 &proj, mat4 &view){ @@ -176,8 +183,10 @@ namespace vb01{ glViewport(0, 0, root->getWidth(), root->getHeight()); } + //TODO replace depth map id literals void Light::updateShader(vector materials, int thisId, mat4 &proj, mat4 &view){ Vector3 position = node->localToGlobalPosition(Vector3::VEC_ZERO), direction = node->getGlobalAxis(2); + for(Material *m : materials){ Shader *shader = m->getShader(); shader->use(); @@ -200,7 +209,7 @@ namespace vb01{ shader->setFloat(attenuationValues.x, "lights[" + to_string(thisId) + "].a"); shader->setFloat(attenuationValues.y, "lights[" + to_string(thisId) + "].b"); shader->setFloat(attenuationValues.z, "lights[" + to_string(thisId) + "].c"); - shader->setBool(useAngle, "lights[" + to_string(thisId) + "].additive"); + shader->setBool(useAngle, "lights[" + to_string(thisId) + "].useAngle"); break; case DIRECTIONAL: shader->setMat4(proj * view, "lights[" + to_string(thisId) + "].lightMat"); diff --git a/light.h b/light.h index 93d47b5..9fe4424 100755 --- a/light.h +++ b/light.h @@ -21,7 +21,9 @@ namespace vb01{ Light(Type, std::string = ""); ~Light(); - void update(); + void update(bool); + inline Vector3 getColor(){return color;} + inline Type getLightType(){return type;} inline void setColor(Vector3 color){this->color = color;} inline void setAttenuationValues(float a, float b, float c){ attenuationValues.x = a; diff --git a/node.cpp b/node.cpp index ce478d9..f49aaaf 100755 --- a/node.cpp +++ b/node.cpp @@ -58,10 +58,10 @@ namespace vb01{ if(!render) break; } - if(render){ - for(Light *l : lights) - l->update(); + for(Light *l : lights) + l->update(render); + if(render){ for(Mesh *m : meshes) m->update(); diff --git a/texture.frag b/texture.frag index b8023e1..75de987 100755 --- a/texture.frag +++ b/texture.frag @@ -15,7 +15,7 @@ layout (location = 1) out vec4 BrightColor; //0-POINT,1-DIRECTIONAL,2-SPOT struct Light{ - bool useAngle, additive; + bool useAngle, additive, render; int type, attenuation; vec3 pos, color, direction; float innerAngle, outerAngle; @@ -100,8 +100,10 @@ void main(){ bool addedLighting = false; for(int i = 0; i < numLights; i++){ + if(!lights[i].render) continue; + vec3 lightDir = vec3(0), viewDir = normalize(camPos - fragPos); - float attenuation = 0, coef = 1; + float attenuation = 1, coef = 1; float factor = 0; bool canAdd = false; @@ -125,7 +127,7 @@ void main(){ } else if(lights[i].type == 1){ lightDir = -normalize(lights[i].direction); - factor = max(dot(lightDir, normalize(normal)), 0.) * attenuation * coef; + factor = max(dot(lightDir, normalize(normal)), 0.) * attenuation; } else if(lights[i].type == 2){ lightDir = normalize(lights[i].pos - fragPos); From c08ac0fd12273d461ac9ee8abbc79e6bfc1653fc Mon Sep 17 00:00:00 2001 From: devZoGok Date: Fri, 27 Sep 2024 17:25:18 +0300 Subject: [PATCH 16/19] loading new image data into a texture additional ImageAsset property --- imageAsset.h | 5 +++-- imageReader.cpp | 2 +- texture.cpp | 21 ++++++++++++--------- texture.h | 3 +++ 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/imageAsset.h b/imageAsset.h index 54a4a8c..1701c21 100644 --- a/imageAsset.h +++ b/imageAsset.h @@ -5,15 +5,16 @@ namespace vb01{ struct ImageAsset : public Asset{ - ImageAsset(std::string path, u8 *image, int width, int height){ + ImageAsset(std::string path, u8 *image, int width, int height, int numChannels){ this->path = path; this->image = image; this->width = width; this->height = height; + this->numChannels = numChannels; } u8 *image; - int width, height; + int width, height, numChannels; }; } diff --git a/imageReader.cpp b/imageReader.cpp index 5a95612..c32d787 100644 --- a/imageReader.cpp +++ b/imageReader.cpp @@ -18,6 +18,6 @@ namespace vb01{ stbi_set_flip_vertically_on_load(flip); int width, height, numChannels; u8 *data = stbi_load(path.c_str(), &width, &height, &numChannels, 0); - return new ImageAsset(path, data, width, height); + return new ImageAsset(path, data, width, height, numChannels); } } diff --git a/texture.cpp b/texture.cpp index c97fdec..dd7c064 100755 --- a/texture.cpp +++ b/texture.cpp @@ -60,6 +60,16 @@ namespace vb01{ } } + void Texture::loadImageData(ImageAsset *asset, int i){ + width = asset->width; + height = asset->height; + + glGenTextures(1, &texture[i]); + glBindTexture(GL_TEXTURE_2D, texture[i]); + glTexImage2D(GL_TEXTURE_2D, 0, png ? GL_RGBA : GL_RGB, width, height, 0, png ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, asset->image); + glGenerateMipmap(GL_TEXTURE_2D); + } + void Texture::create2DTexture(bool flip){ mixRatio = .1; @@ -69,19 +79,12 @@ namespace vb01{ if(paths[i].substr(length - 4, string::npos) == ".png") png = true; - glGenTextures(1, &texture[i]); - glBindTexture(GL_TEXTURE_2D, texture[i]); + loadImageData((ImageAsset*)AssetManager::getSingleton()->getAsset(paths[i])); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - ImageAsset *asset = (ImageAsset*)AssetManager::getSingleton()->getAsset(paths[i]); - width = asset->width; - height = asset->height; - - glTexImage2D(GL_TEXTURE_2D, 0, png ? GL_RGBA : GL_RGB, width, height, 0, png ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, asset->image); - glGenerateMipmap(GL_TEXTURE_2D); } } diff --git a/texture.h b/texture.h index beb1cb0..55f073d 100755 --- a/texture.h +++ b/texture.h @@ -10,6 +10,8 @@ #include FT_FREETYPE_H namespace vb01{ + struct ImageAsset; + class Texture : public Animatable{ public: ~Texture(); @@ -20,6 +22,7 @@ namespace vb01{ void select(int = 0, int = 0); void update(int = 0); void animate(float, KeyframeChannel); + void loadImageData(ImageAsset*, int = 0); inline u32* getTexture(int i = 0){return &(texture[i]);} inline std::string* getPath(){return paths;} inline int getNumFrames(){return numFrames;} From acac13d2addd634d12b08e5c9d0694c9a800c2db Mon Sep 17 00:00:00 2001 From: devZoGok Date: Fri, 27 Sep 2024 17:28:05 +0300 Subject: [PATCH 17/19] GUI utilities --- abstractGuiManager.cpp | 8 ++++++++ abstractGuiManager.h | 1 + button.cpp | 2 +- button.h | 9 +++++---- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/abstractGuiManager.cpp b/abstractGuiManager.cpp index 5c37d69..df06b81 100644 --- a/abstractGuiManager.cpp +++ b/abstractGuiManager.cpp @@ -154,6 +154,14 @@ namespace vb01Gui{ textboxes.push_back(t); } + Button* AbstractGuiManager::getButton(string name){ + for(Button *b : buttons) + if(b->getName() == name) + return b; + + return nullptr; + } + void AbstractGuiManager::removeButton(Button *b) { for (int i = 0; i < buttons.size(); i++) { if (b == buttons[i]) { diff --git a/abstractGuiManager.h b/abstractGuiManager.h index 90de87f..6eac215 100644 --- a/abstractGuiManager.h +++ b/abstractGuiManager.h @@ -22,6 +22,7 @@ namespace vb01Gui{ std::vector findClickedButtons(); void updateGui(); void addButton(Button *b){buttons.push_back(b);} + Button* getButton(std::string); void removeButton(Button*); void removeButton(std::string); void addListbox(Listbox*); diff --git a/button.cpp b/button.cpp index 5f67102..503c835 100644 --- a/button.cpp +++ b/button.cpp @@ -46,7 +46,7 @@ namespace vb01Gui{ rectNode->attachMesh(rect); guiNode->attachChild(rectNode); - if(separate){ + if(separate && fontPath != ""){ text = new Text(fontPath, stringToWstring(name)); float sc = .2; diff --git a/button.h b/button.h index dc340c9..d49fc9f 100644 --- a/button.h +++ b/button.h @@ -24,18 +24,19 @@ namespace vb01Gui{ virtual void onMouseOver(); virtual void onMouseOff(); virtual void onClick(){} - inline vb01::Vector3 getPos(){return pos;} void setPos(vb01::Vector3); - inline vb01::Vector2 getSize(){return size;} void setSize(vb01::Vector2); + void setColor(vb01::Vector4); + void setImage(std::string); + inline vb01::Node* getRectNode(){return rectNode;} + inline vb01::Vector3 getPos(){return pos;} + inline vb01::Vector2 getSize(){return size;} inline std::string getName(){return name;} inline void setActive(bool active){this->active = active;} inline bool isSeparate(){return separate;} inline bool isActive(){return active;} inline vb01::Vector4 getColor(){return color;} inline int getTrigger(){return trigger;} - void setColor(vb01::Vector4); - void setImage(std::string); protected: int trigger, initWindowSize[2]; bool separate, active = true, mouseOver = false; From c2e126c475ea318af3d13ce74c7de30fd801fb59 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Fri, 27 Sep 2024 18:32:45 +0300 Subject: [PATCH 18/19] added stb_image_write.h --- external/stb/stb_image_write.h | 1724 ++++++++++++++++++++++++++++++++ 1 file changed, 1724 insertions(+) create mode 100644 external/stb/stb_image_write.h diff --git a/external/stb/stb_image_write.h b/external/stb/stb_image_write.h new file mode 100644 index 0000000..e4b32ed --- /dev/null +++ b/external/stb/stb_image_write.h @@ -0,0 +1,1724 @@ +/* stb_image_write - v1.16 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio or a callback. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + Andrew Kensler + +LICENSE + + See end of file for license information. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#include + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +STBIWDEF int stbi_write_tga_with_rle; +STBIWDEF int stbi_write_png_compression_level; +STBIWDEF int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBIW_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +static int stbi__flip_vertically_on_write = 0; + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; + unsigned char buffer[64]; + int buf_used; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__write_flush(stbi__write_context *s) +{ + if (s->buf_used) { + s->func(s->context, &s->buffer, s->buf_used); + s->buf_used = 0; + } +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write1(stbi__write_context *s, unsigned char a) +{ + if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) + stbiw__write_flush(s); + s->buffer[s->buf_used++] = a; +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + int n; + if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) + stbiw__write_flush(s); + n = s->buf_used; + s->buf_used = n+3; + s->buffer[n+0] = a; + s->buffer[n+1] = b; + s->buffer[n+2] = c; +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + stbiw__write1(s, d[comp - 1]); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + stbiw__write1(s, d[0]); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + stbiw__write1(s, d[comp - 1]); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + stbiw__write_flush(s); + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + if (comp != 4) { + // write RGB bitmap + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header + } else { + // RGBA bitmaps need a v4 header + // use BI_BITFIELDS mode with 32bpp and alpha mask + // (straight BI_RGB with alpha mask doesn't work in most readers) + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, + "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", + 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header + 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header + } +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + stbiw__write1(s, header); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + stbiw__write1(s, header); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + stbiw__write_flush(s); + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +#ifndef STBI_WRITE_NO_STDIO + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef __STDC_LIB_EXT1__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) { best=d; bestloc=hlist[j]; } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + // store uncompressed instead if compression was worse + if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { + stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 + for (j = 0; j < data_len;) { + int blocklen = data_len - j; + if (blocklen > 32767) blocklen = 32767; + stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression + stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN + stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN + stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); + memcpy(out+stbiw__sbn(out), data+j, blocklen); + stbiw__sbn(out) += blocklen; + j += blocklen; + } + } + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.16 (2021-07-11) + make Deflate code emit uncompressed blocks when it would otherwise expand + support writing BMPs with alpha channel + 1.15 (2020-07-13) unknown + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ From 341ada95b8d36753e80e529aa210696adfcb6e2b Mon Sep 17 00:00:00 2001 From: devZoGok Date: Thu, 10 Oct 2024 20:30:25 +0300 Subject: [PATCH 19/19] replaced boost functionality to find nth string occurences --- node.cpp | 12 +++++------- util.cpp | 11 +++++++++++ util.h | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/node.cpp b/node.cpp index f49aaaf..7b3a5f7 100755 --- a/node.cpp +++ b/node.cpp @@ -2,6 +2,7 @@ #include "bone.h" #include "mesh.h" #include "text.h" +#include "util.h" #include "light.h" #include "matrix.h" #include "material.h" @@ -11,14 +12,11 @@ #include "assetManager.h" #include "animationController.h" -#include - #include #include using namespace std; using namespace glm; -using namespace boost; namespace vb01{ Node::Node(Vector3 pos, Quaternion orientation, Vector3 scale, string name, Animatable::Type type) : Animatable(type, name){ @@ -463,13 +461,13 @@ namespace vb01{ int numLights = root->getNumLights(); string str1 = "const int numLights = " + to_string(numLights > 0 ? numLights : 1) + ";"; - int a1 = std::distance(shaderStr.begin(), find_nth(shaderStr, "\n", 0).begin()); - int a2 = std::distance(shaderStr.begin(), find_nth(shaderStr, "\n", 1).begin()); + int a1 = findNthOccurence(shaderStr, "\n", 0); + int a2 = findNthOccurence(shaderStr, "\n", 1); shaderStr.replace(a1 + 1, a2 - a1 - 1, str1); string str2 = "const bool checkLights = " + string(numLights > 0 ? "true" : "false") + ";"; - a1 = std::distance(shaderStr.begin(), find_nth(shaderStr, "\n", 1).begin()); - a2 = std::distance(shaderStr.begin(), find_nth(shaderStr, "\n", 2).begin()); + a1 = findNthOccurence(shaderStr, "\n", 1); + a2 = findNthOccurence(shaderStr, "\n", 2); shaderStr.replace(a1 + 1, a2 - a1 - 1, str2); ShaderAsset sa2(sa->path, shaderStr); diff --git a/util.cpp b/util.cpp index 10fa66d..b60ab1e 100755 --- a/util.cpp +++ b/util.cpp @@ -90,4 +90,15 @@ namespace vb01{ return str; } + + int findNthOccurence(string &str, string occ, int occId, bool forward){ + int occurenceId = (forward ? str.find(occ) : str.rfind(occ)), iteration = 0; + + while(occurenceId != -1 && iteration != occId){ + occurenceId = (forward ? str.find(occ, occurenceId + 1) : str.rfind(occ, occurenceId - 1)); + iteration++; + } + + return occurenceId; + } } diff --git a/util.h b/util.h index 5e40d5d..05b70e3 100755 --- a/util.h +++ b/util.h @@ -23,6 +23,7 @@ namespace vb01{ void readFile(std::string, std::vector&, int = 0, int = -1); void getLineData(std::string, std::string[], int, int = 0); + int findNthOccurence(std::string&, std::string, int, bool = true); int getCharId(std::string, char, bool = false); std::wstring stringToWstring(std::string str); std::string wstringToString(std::wstring wstr);