mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-12 23:24:41 +00:00
* Adjustment: Update Bullet version to 3.24.
This commit is contained in:
parent
35de012ee7
commit
4a3f31df2a
6148 changed files with 2112532 additions and 56873 deletions
13
Engine/lib/bullet/examples/TinyRenderer/LICENSE.txt
Normal file
13
Engine/lib/bullet/examples/TinyRenderer/LICENSE.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Tiny Renderer, https://github.com/ssloy/tinyrenderer
|
||||
Copyright Dmitry V. Sokolov
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
656
Engine/lib/bullet/examples/TinyRenderer/TinyRenderer.cpp
Normal file
656
Engine/lib/bullet/examples/TinyRenderer/TinyRenderer.cpp
Normal file
|
|
@ -0,0 +1,656 @@
|
|||
#include "TinyRenderer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include "../CommonInterfaces/CommonFileIOInterface.h"
|
||||
#include "../OpenGLWindow/ShapeData.h"
|
||||
#include "../Utils/b3BulletDefaultFileIO.h"
|
||||
#include "../Utils/b3ResourcePath.h"
|
||||
#include "Bullet3Common/b3Logging.h"
|
||||
#include "Bullet3Common/b3MinMax.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "LinearMath/btVector3.h"
|
||||
#include "geometry.h"
|
||||
#include "model.h"
|
||||
#include "our_gl.h"
|
||||
#include "tgaimage.h"
|
||||
|
||||
using namespace TinyRender;
|
||||
|
||||
struct DepthShader : public IShader
|
||||
{
|
||||
Model* m_model;
|
||||
Matrix& m_modelMat;
|
||||
Matrix m_invModelMat;
|
||||
|
||||
Matrix& m_projectionMat;
|
||||
Vec3f m_localScaling;
|
||||
Matrix& m_lightModelView;
|
||||
float m_lightDistance;
|
||||
|
||||
mat<2, 3, float> varying_uv; // triangle uv coordinates, written by the vertex shader, read by the fragment shader
|
||||
mat<4, 3, float> varying_tri; // triangle coordinates (clip coordinates), written by VS, read by FS
|
||||
|
||||
mat<3, 3, float> varying_nrm; // normal per vertex to be interpolated by FS
|
||||
|
||||
DepthShader(Model* model, Matrix& lightModelView, Matrix& projectionMat, Matrix& modelMat, Vec3f localScaling, float lightDistance)
|
||||
: m_model(model),
|
||||
m_modelMat(modelMat),
|
||||
m_projectionMat(projectionMat),
|
||||
m_localScaling(localScaling),
|
||||
m_lightModelView(lightModelView),
|
||||
m_lightDistance(lightDistance)
|
||||
{
|
||||
m_nearPlane = m_projectionMat.col(3)[2] / (m_projectionMat.col(2)[2] - 1);
|
||||
m_farPlane = m_projectionMat.col(3)[2] / (m_projectionMat.col(2)[2] + 1);
|
||||
|
||||
m_invModelMat = m_modelMat.invert_transpose();
|
||||
}
|
||||
virtual Vec4f vertex(int iface, int nthvert)
|
||||
{
|
||||
Vec2f uv = m_model->uv(iface, nthvert);
|
||||
varying_uv.set_col(nthvert, uv);
|
||||
varying_nrm.set_col(nthvert, proj<3>(m_invModelMat * embed<4>(m_model->normal(iface, nthvert), 0.f)));
|
||||
Vec3f unScaledVert = m_model->vert(iface, nthvert);
|
||||
Vec3f scaledVert = Vec3f(unScaledVert[0] * m_localScaling[0],
|
||||
unScaledVert[1] * m_localScaling[1],
|
||||
unScaledVert[2] * m_localScaling[2]);
|
||||
Vec4f gl_Vertex = m_projectionMat * m_lightModelView * embed<4>(scaledVert);
|
||||
varying_tri.set_col(nthvert, gl_Vertex);
|
||||
return gl_Vertex;
|
||||
}
|
||||
|
||||
virtual bool fragment(Vec3f bar, TGAColor& color)
|
||||
{
|
||||
Vec4f p = varying_tri * bar;
|
||||
color = TGAColor(255, 255, 255) * (p[2] / m_lightDistance);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Shader : public IShader
|
||||
{
|
||||
Model* m_model;
|
||||
Vec3f m_light_dir_local;
|
||||
Vec3f m_light_color;
|
||||
Matrix& m_modelMat;
|
||||
Matrix m_invModelMat;
|
||||
Matrix& m_modelView1;
|
||||
Matrix& m_projectionMat;
|
||||
Vec3f m_localScaling;
|
||||
Matrix& m_lightModelView;
|
||||
Vec4f m_colorRGBA;
|
||||
Matrix& m_viewportMat;
|
||||
Matrix m_projectionModelViewMat;
|
||||
Matrix m_projectionLightViewMat;
|
||||
float m_ambient_coefficient;
|
||||
float m_diffuse_coefficient;
|
||||
float m_specular_coefficient;
|
||||
|
||||
b3AlignedObjectArray<float>* m_shadowBuffer;
|
||||
|
||||
int m_width;
|
||||
int m_height;
|
||||
|
||||
int m_index;
|
||||
|
||||
mat<2, 3, float> varying_uv; // triangle uv coordinates, written by the vertex shader, read by the fragment shader
|
||||
mat<4, 3, float> varying_tri; // triangle coordinates (clip coordinates), written by VS, read by FS
|
||||
mat<4, 3, float> varying_tri_light_view;
|
||||
mat<3, 3, float> varying_nrm; // normal per vertex to be interpolated by FS
|
||||
mat<4, 3, float> world_tri; // model triangle coordinates in the world space used for backface culling, written by VS
|
||||
|
||||
Shader(Model* model, Vec3f light_dir_local, Vec3f light_color, Matrix& modelView, Matrix& lightModelView, Matrix& projectionMat, Matrix& modelMat, Matrix& viewportMat, Vec3f localScaling, const Vec4f& colorRGBA, int width, int height, b3AlignedObjectArray<float>* shadowBuffer, float ambient_coefficient = 0.6, float diffuse_coefficient = 0.35, float specular_coefficient = 0.05)
|
||||
: m_model(model),
|
||||
m_light_dir_local(light_dir_local),
|
||||
m_light_color(light_color),
|
||||
m_modelMat(modelMat),
|
||||
m_modelView1(modelView),
|
||||
m_projectionMat(projectionMat),
|
||||
m_localScaling(localScaling),
|
||||
m_lightModelView(lightModelView),
|
||||
m_colorRGBA(colorRGBA),
|
||||
m_viewportMat(viewportMat),
|
||||
m_ambient_coefficient(ambient_coefficient),
|
||||
m_diffuse_coefficient(diffuse_coefficient),
|
||||
m_specular_coefficient(specular_coefficient),
|
||||
|
||||
m_shadowBuffer(shadowBuffer),
|
||||
m_width(width),
|
||||
m_height(height)
|
||||
|
||||
{
|
||||
m_nearPlane = m_projectionMat.col(3)[2] / (m_projectionMat.col(2)[2] - 1);
|
||||
m_farPlane = m_projectionMat.col(3)[2] / (m_projectionMat.col(2)[2] + 1);
|
||||
//printf("near=%f, far=%f\n", m_nearPlane, m_farPlane);
|
||||
m_invModelMat = m_modelMat.invert_transpose();
|
||||
m_projectionModelViewMat = m_projectionMat * m_modelView1;
|
||||
m_projectionLightViewMat = m_projectionMat * m_lightModelView;
|
||||
}
|
||||
virtual Vec4f vertex(int iface, int nthvert)
|
||||
{
|
||||
//B3_PROFILE("vertex");
|
||||
Vec2f uv = m_model->uv(iface, nthvert);
|
||||
varying_uv.set_col(nthvert, uv);
|
||||
varying_nrm.set_col(nthvert, proj<3>(m_invModelMat * embed<4>(m_model->normal(iface, nthvert), 0.f)));
|
||||
Vec3f unScaledVert = m_model->vert(iface, nthvert);
|
||||
Vec3f scaledVert = Vec3f(unScaledVert[0] * m_localScaling[0],
|
||||
unScaledVert[1] * m_localScaling[1],
|
||||
unScaledVert[2] * m_localScaling[2]);
|
||||
Vec4f gl_Vertex = m_projectionModelViewMat * embed<4>(scaledVert);
|
||||
varying_tri.set_col(nthvert, gl_Vertex);
|
||||
Vec4f world_Vertex = m_modelMat * embed<4>(scaledVert);
|
||||
world_tri.set_col(nthvert, world_Vertex);
|
||||
Vec4f gl_VertexLightView = m_projectionLightViewMat * embed<4>(scaledVert);
|
||||
varying_tri_light_view.set_col(nthvert, gl_VertexLightView);
|
||||
return gl_Vertex;
|
||||
}
|
||||
|
||||
virtual bool fragment(Vec3f bar, TGAColor& color)
|
||||
{
|
||||
//B3_PROFILE("fragment");
|
||||
Vec4f p = m_viewportMat * (varying_tri_light_view * bar);
|
||||
float depth = p[2];
|
||||
p = p / p[3];
|
||||
|
||||
float index_x = b3Max(float(0.0), b3Min(float(m_width - 1), p[0]));
|
||||
float index_y = b3Max(float(0.0), b3Min(float(m_height - 1), p[1]));
|
||||
int idx = int(index_x) + int(index_y) * m_width; // index in the shadowbuffer array
|
||||
float shadow = 1.0;
|
||||
if (m_shadowBuffer && idx >=0 && idx <m_shadowBuffer->size())
|
||||
{
|
||||
shadow = 0.8 + 0.2 * (m_shadowBuffer->at(idx) < -depth + 0.05); // magic coeff to avoid z-fighting
|
||||
}
|
||||
Vec3f bn = (varying_nrm * bar).normalize();
|
||||
Vec2f uv = varying_uv * bar;
|
||||
|
||||
Vec3f reflection_direction = (bn * (bn * m_light_dir_local * 2.f) - m_light_dir_local).normalize();
|
||||
float specular = std::pow(b3Max(reflection_direction.z, 0.f),
|
||||
m_model->specular(uv));
|
||||
float diffuse = b3Max(0.f, bn * m_light_dir_local);
|
||||
|
||||
color = m_model->diffuse(uv);
|
||||
color[0] *= m_colorRGBA[0];
|
||||
color[1] *= m_colorRGBA[1];
|
||||
color[2] *= m_colorRGBA[2];
|
||||
color[3] *= m_colorRGBA[3];
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
int orgColor = 0;
|
||||
float floatColor = (m_ambient_coefficient * color[i] + shadow * (m_diffuse_coefficient * diffuse + m_specular_coefficient * specular) * color[i] * m_light_color[i]);
|
||||
if (floatColor==floatColor)
|
||||
{
|
||||
orgColor=int(floatColor);
|
||||
}
|
||||
color[i] = b3Min(orgColor, 255);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
TinyRenderObjectData::TinyRenderObjectData(TGAImage& rgbColorBuffer, b3AlignedObjectArray<float>& depthBuffer, b3AlignedObjectArray<float>* shadowBuffer)
|
||||
: m_model(0),
|
||||
m_rgbColorBuffer(rgbColorBuffer),
|
||||
m_depthBuffer(depthBuffer),
|
||||
m_shadowBuffer(shadowBuffer),
|
||||
m_segmentationMaskBufferPtr(0),
|
||||
m_userData(0),
|
||||
m_userIndex(-1),
|
||||
m_objectIndex(-1),
|
||||
m_doubleSided(false)
|
||||
{
|
||||
Vec3f eye(1, 1, 3);
|
||||
Vec3f center(0, 0, 0);
|
||||
Vec3f up(0, 0, 1);
|
||||
m_lightDirWorld.setValue(0, 0, 0);
|
||||
m_lightColor.setValue(1, 1, 1);
|
||||
m_localScaling.setValue(1, 1, 1);
|
||||
m_modelMatrix = Matrix::identity();
|
||||
m_lightAmbientCoeff = 0.6;
|
||||
m_lightDiffuseCoeff = 0.35;
|
||||
m_lightSpecularCoeff = 0.05;
|
||||
|
||||
}
|
||||
|
||||
TinyRenderObjectData::TinyRenderObjectData(TGAImage& rgbColorBuffer, b3AlignedObjectArray<float>& depthBuffer, b3AlignedObjectArray<float>* shadowBuffer, b3AlignedObjectArray<int>* segmentationMaskBuffer, int objectIndex, int linkIndex)
|
||||
: m_model(0),
|
||||
m_rgbColorBuffer(rgbColorBuffer),
|
||||
m_depthBuffer(depthBuffer),
|
||||
m_shadowBuffer(shadowBuffer),
|
||||
m_segmentationMaskBufferPtr(segmentationMaskBuffer),
|
||||
m_userData(0),
|
||||
m_userIndex(-1),
|
||||
m_objectIndex(objectIndex),
|
||||
m_linkIndex(linkIndex),
|
||||
m_doubleSided(false)
|
||||
{
|
||||
Vec3f eye(1, 1, 3);
|
||||
Vec3f center(0, 0, 0);
|
||||
Vec3f up(0, 0, 1);
|
||||
m_lightDirWorld.setValue(0, 0, 0);
|
||||
m_lightColor.setValue(1, 1, 1);
|
||||
m_localScaling.setValue(1, 1, 1);
|
||||
m_modelMatrix = Matrix::identity();
|
||||
m_lightAmbientCoeff = 0.6;
|
||||
m_lightDiffuseCoeff = 0.35;
|
||||
m_lightSpecularCoeff = 0.05;
|
||||
}
|
||||
|
||||
TinyRenderObjectData::TinyRenderObjectData(TGAImage& rgbColorBuffer, b3AlignedObjectArray<float>& depthBuffer)
|
||||
: m_model(0),
|
||||
m_rgbColorBuffer(rgbColorBuffer),
|
||||
m_depthBuffer(depthBuffer),
|
||||
m_shadowBuffer(0),
|
||||
m_segmentationMaskBufferPtr(0),
|
||||
m_userData(0),
|
||||
m_userIndex(-1),
|
||||
m_objectIndex(-1),
|
||||
m_doubleSided(false)
|
||||
{
|
||||
Vec3f eye(1, 1, 3);
|
||||
Vec3f center(0, 0, 0);
|
||||
Vec3f up(0, 0, 1);
|
||||
m_lightDirWorld.setValue(0, 0, 0);
|
||||
m_lightDistance = 10;
|
||||
m_lightColor.setValue(1, 1, 1);
|
||||
m_localScaling.setValue(1, 1, 1);
|
||||
m_modelMatrix = Matrix::identity();
|
||||
m_lightAmbientCoeff = 0.6;
|
||||
m_lightDiffuseCoeff = 0.35;
|
||||
m_lightSpecularCoeff = 0.05;
|
||||
}
|
||||
|
||||
TinyRenderObjectData::TinyRenderObjectData(TGAImage& rgbColorBuffer, b3AlignedObjectArray<float>& depthBuffer, b3AlignedObjectArray<int>* segmentationMaskBuffer, int objectIndex)
|
||||
: m_model(0),
|
||||
m_rgbColorBuffer(rgbColorBuffer),
|
||||
m_depthBuffer(depthBuffer),
|
||||
m_shadowBuffer(0),
|
||||
m_segmentationMaskBufferPtr(segmentationMaskBuffer),
|
||||
m_userData(0),
|
||||
m_userIndex(-1),
|
||||
m_objectIndex(objectIndex),
|
||||
m_doubleSided(false)
|
||||
{
|
||||
Vec3f eye(1, 1, 3);
|
||||
Vec3f center(0, 0, 0);
|
||||
Vec3f up(0, 0, 1);
|
||||
m_lightDirWorld.setValue(0, 0, 0);
|
||||
m_lightColor.setValue(1, 1, 1);
|
||||
m_localScaling.setValue(1, 1, 1);
|
||||
m_modelMatrix = Matrix::identity();
|
||||
m_lightAmbientCoeff = 0.6;
|
||||
m_lightDiffuseCoeff = 0.35;
|
||||
m_lightSpecularCoeff = 0.05;
|
||||
}
|
||||
|
||||
void TinyRenderObjectData::loadModel(const char* fileName, CommonFileIOInterface* fileIO)
|
||||
{
|
||||
//todo(erwincoumans) move the file loading out of here
|
||||
char relativeFileName[1024];
|
||||
if (!fileIO->findResourcePath(fileName, relativeFileName, 1024))
|
||||
{
|
||||
printf("Cannot find file %s\n", fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_model = new Model(relativeFileName);
|
||||
}
|
||||
}
|
||||
|
||||
void TinyRenderObjectData::registerMeshShape(const float* vertices, int numVertices, const int* indices, int numIndices, const float rgbaColor[4],
|
||||
unsigned char* textureImage, int textureWidth, int textureHeight)
|
||||
{
|
||||
if (0 == m_model)
|
||||
{
|
||||
{
|
||||
B3_PROFILE("setColorRGBA");
|
||||
|
||||
m_model = new Model();
|
||||
m_model->setColorRGBA(rgbaColor);
|
||||
}
|
||||
if (textureImage)
|
||||
{
|
||||
{
|
||||
B3_PROFILE("setDiffuseTextureFromData");
|
||||
m_model->setDiffuseTextureFromData(textureImage, textureWidth, textureHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*char relativeFileName[1024];
|
||||
if (b3ResourcePath::findResourcePath("floor_diffuse.tga", relativeFileName, 1024))
|
||||
{
|
||||
m_model->loadDiffuseTexture(relativeFileName);
|
||||
}
|
||||
*/
|
||||
}
|
||||
{
|
||||
B3_PROFILE("reserveMemory");
|
||||
m_model->reserveMemory(numVertices, numIndices);
|
||||
}
|
||||
{
|
||||
B3_PROFILE("addVertex");
|
||||
for (int i = 0; i < numVertices; i++)
|
||||
{
|
||||
m_model->addVertex(vertices[i * 9],
|
||||
vertices[i * 9 + 1],
|
||||
vertices[i * 9 + 2],
|
||||
vertices[i * 9 + 4],
|
||||
vertices[i * 9 + 5],
|
||||
vertices[i * 9 + 6],
|
||||
vertices[i * 9 + 7],
|
||||
vertices[i * 9 + 8]);
|
||||
}
|
||||
}
|
||||
{
|
||||
B3_PROFILE("addTriangle");
|
||||
for (int i = 0; i < numIndices; i += 3)
|
||||
{
|
||||
m_model->addTriangle(indices[i], indices[i], indices[i],
|
||||
indices[i + 1], indices[i + 1], indices[i + 1],
|
||||
indices[i + 2], indices[i + 2], indices[i + 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TinyRenderObjectData::registerMesh2(btAlignedObjectArray<btVector3>& vertices, btAlignedObjectArray<btVector3>& normals, btAlignedObjectArray<int>& indices, CommonFileIOInterface* fileIO)
|
||||
{
|
||||
if (0 == m_model)
|
||||
{
|
||||
int numVertices = vertices.size();
|
||||
int numIndices = indices.size();
|
||||
|
||||
m_model = new Model();
|
||||
char relativeFileName[1024];
|
||||
if (fileIO->findResourcePath("floor_diffuse.tga", relativeFileName, 1024))
|
||||
{
|
||||
m_model->loadDiffuseTexture(relativeFileName);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numVertices; i++)
|
||||
{
|
||||
m_model->addVertex(vertices[i].x(),
|
||||
vertices[i].y(),
|
||||
vertices[i].z(),
|
||||
normals[i].x(),
|
||||
normals[i].y(),
|
||||
normals[i].z(),
|
||||
0.5, 0.5);
|
||||
}
|
||||
for (int i = 0; i < numIndices; i += 3)
|
||||
{
|
||||
m_model->addTriangle(indices[i], indices[i], indices[i],
|
||||
indices[i + 1], indices[i + 1], indices[i + 1],
|
||||
indices[i + 2], indices[i + 2], indices[i + 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TinyRenderObjectData::createCube(float halfExtentsX, float halfExtentsY, float halfExtentsZ, CommonFileIOInterface* fileIO)
|
||||
{
|
||||
b3BulletDefaultFileIO defaultFileIO;
|
||||
|
||||
if (fileIO==0)
|
||||
{
|
||||
fileIO = &defaultFileIO;
|
||||
}
|
||||
m_model = new Model();
|
||||
|
||||
char relativeFileName[1024];
|
||||
if (fileIO->findResourcePath("floor_diffuse.tga", relativeFileName, 1024))
|
||||
{
|
||||
m_model->loadDiffuseTexture(relativeFileName);
|
||||
}
|
||||
|
||||
int strideInBytes = 9 * sizeof(float);
|
||||
int numVertices = sizeof(cube_vertices_textured) / strideInBytes;
|
||||
int numIndices = sizeof(cube_indices) / sizeof(int);
|
||||
|
||||
for (int i = 0; i < numVertices; i++)
|
||||
{
|
||||
m_model->addVertex(halfExtentsX * cube_vertices_textured[i * 9],
|
||||
halfExtentsY * cube_vertices_textured[i * 9 + 1],
|
||||
halfExtentsZ * cube_vertices_textured[i * 9 + 2],
|
||||
cube_vertices_textured[i * 9 + 4],
|
||||
cube_vertices_textured[i * 9 + 5],
|
||||
cube_vertices_textured[i * 9 + 6],
|
||||
cube_vertices_textured[i * 9 + 7],
|
||||
cube_vertices_textured[i * 9 + 8]);
|
||||
}
|
||||
for (int i = 0; i < numIndices; i += 3)
|
||||
{
|
||||
m_model->addTriangle(cube_indices[i], cube_indices[i], cube_indices[i],
|
||||
cube_indices[i + 1], cube_indices[i + 1], cube_indices[i + 1],
|
||||
cube_indices[i + 2], cube_indices[i + 2], cube_indices[i + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
TinyRenderObjectData::~TinyRenderObjectData()
|
||||
{
|
||||
delete m_model;
|
||||
}
|
||||
|
||||
static bool equals(const Vec4f& vA, const Vec4f& vB)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void clipEdge(const mat<4, 3, float>& triangleIn, int vertexIndexA, int vertexIndexB, b3AlignedObjectArray<Vec4f>& vertices)
|
||||
{
|
||||
Vec4f v0New = triangleIn.col(vertexIndexA);
|
||||
Vec4f v1New = triangleIn.col(vertexIndexB);
|
||||
|
||||
bool v0Inside = v0New[3] > 0.f && v0New[2] > -v0New[3];
|
||||
bool v1Inside = v1New[3] > 0.f && v1New[2] > -v1New[3];
|
||||
|
||||
if (v0Inside && v1Inside)
|
||||
{
|
||||
}
|
||||
else if (v0Inside || v1Inside)
|
||||
{
|
||||
float d0 = v0New[2] + v0New[3];
|
||||
float d1 = v1New[2] + v1New[3];
|
||||
float factor = 1.0 / (d1 - d0);
|
||||
Vec4f newVertex = (v0New * d1 - v1New * d0) * factor;
|
||||
if (v0Inside)
|
||||
{
|
||||
v1New = newVertex;
|
||||
}
|
||||
else
|
||||
{
|
||||
v0New = newVertex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (vertices.size() == 0 || !(equals(vertices[vertices.size() - 1], v0New)))
|
||||
{
|
||||
vertices.push_back(v0New);
|
||||
}
|
||||
|
||||
vertices.push_back(v1New);
|
||||
}
|
||||
|
||||
static bool clipTriangleAgainstNearplane(const mat<4, 3, float>& triangleIn, b3AlignedObjectArray<mat<4, 3, float> >& clippedTrianglesOut)
|
||||
{
|
||||
//discard triangle if all vertices are behind near-plane
|
||||
if (triangleIn[3][0] < 0 && triangleIn[3][1] < 0 && triangleIn[3][2] < 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//accept triangle if all vertices are in front of the near-plane
|
||||
if (triangleIn[3][0] >= 0 && triangleIn[3][1] >= 0 && triangleIn[3][2] >= 0)
|
||||
{
|
||||
clippedTrianglesOut.push_back(triangleIn);
|
||||
return false;
|
||||
}
|
||||
|
||||
Vec4f vtxCache[5];
|
||||
|
||||
b3AlignedObjectArray<Vec4f> vertices;
|
||||
vertices.initializeFromBuffer(vtxCache, 0, 5);
|
||||
clipEdge(triangleIn, 0, 1, vertices);
|
||||
clipEdge(triangleIn, 1, 2, vertices);
|
||||
clipEdge(triangleIn, 2, 0, vertices);
|
||||
|
||||
if (vertices.size() < 3)
|
||||
return true;
|
||||
|
||||
if (equals(vertices[0], vertices[vertices.size() - 1]))
|
||||
{
|
||||
vertices.pop_back();
|
||||
}
|
||||
|
||||
//create a fan of triangles
|
||||
for (int i = 1; i < vertices.size() - 1; i++)
|
||||
{
|
||||
mat<4, 3, float>& vtx = clippedTrianglesOut.expand();
|
||||
vtx.set_col(0, vertices[0]);
|
||||
vtx.set_col(1, vertices[i]);
|
||||
vtx.set_col(2, vertices[i + 1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TinyRenderer::renderObject(TinyRenderObjectData& renderData)
|
||||
{
|
||||
B3_PROFILE("renderObject");
|
||||
int width = renderData.m_rgbColorBuffer.get_width();
|
||||
int height = renderData.m_rgbColorBuffer.get_height();
|
||||
|
||||
Vec3f light_dir_local = Vec3f(renderData.m_lightDirWorld[0], renderData.m_lightDirWorld[1], renderData.m_lightDirWorld[2]);
|
||||
Vec3f light_color = Vec3f(renderData.m_lightColor[0], renderData.m_lightColor[1], renderData.m_lightColor[2]);
|
||||
float light_distance = renderData.m_lightDistance;
|
||||
Model* model = renderData.m_model;
|
||||
if (0 == model)
|
||||
return;
|
||||
//discard invisible objects (zero alpha)
|
||||
if (model->getColorRGBA()[3] == 0)
|
||||
return;
|
||||
|
||||
renderData.m_viewportMatrix = viewport(0, 0, width, height);
|
||||
|
||||
b3AlignedObjectArray<float>& zbuffer = renderData.m_depthBuffer;
|
||||
b3AlignedObjectArray<float>* shadowBufferPtr = renderData.m_shadowBuffer;
|
||||
int* segmentationMaskBufferPtr = (renderData.m_segmentationMaskBufferPtr && renderData.m_segmentationMaskBufferPtr->size()) ? &renderData.m_segmentationMaskBufferPtr->at(0) : 0;
|
||||
|
||||
TGAImage& frame = renderData.m_rgbColorBuffer;
|
||||
|
||||
{
|
||||
// light target is set to be the origin, and the up direction is set to be vertical up.
|
||||
Matrix lightViewMatrix = lookat(light_dir_local * light_distance, Vec3f(0.0, 0.0, 0.0), Vec3f(0.0, 0.0, 1.0));
|
||||
Matrix lightModelViewMatrix = lightViewMatrix * renderData.m_modelMatrix;
|
||||
Matrix modelViewMatrix = renderData.m_viewMatrix * renderData.m_modelMatrix;
|
||||
Vec3f localScaling(renderData.m_localScaling[0], renderData.m_localScaling[1], renderData.m_localScaling[2]);
|
||||
Matrix viewMatrixInv = renderData.m_viewMatrix.invert();
|
||||
btVector3 P(viewMatrixInv[0][3], viewMatrixInv[1][3], viewMatrixInv[2][3]);
|
||||
|
||||
Shader shader(model, light_dir_local, light_color, modelViewMatrix, lightModelViewMatrix, renderData.m_projectionMatrix, renderData.m_modelMatrix, renderData.m_viewportMatrix, localScaling, model->getColorRGBA(), width, height, shadowBufferPtr, renderData.m_lightAmbientCoeff, renderData.m_lightDiffuseCoeff, renderData.m_lightSpecularCoeff);
|
||||
|
||||
{
|
||||
B3_PROFILE("face");
|
||||
|
||||
for (int i = 0; i < model->nfaces(); i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
shader.vertex(i, j);
|
||||
}
|
||||
|
||||
if (!renderData.m_doubleSided)
|
||||
{
|
||||
// backface culling
|
||||
btVector3 v0(shader.world_tri.col(0)[0], shader.world_tri.col(0)[1], shader.world_tri.col(0)[2]);
|
||||
btVector3 v1(shader.world_tri.col(1)[0], shader.world_tri.col(1)[1], shader.world_tri.col(1)[2]);
|
||||
btVector3 v2(shader.world_tri.col(2)[0], shader.world_tri.col(2)[1], shader.world_tri.col(2)[2]);
|
||||
btVector3 N = (v1 - v0).cross(v2 - v0);
|
||||
if ((v0 - P).dot(N) >= 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
mat<4, 3, float> stackTris[3];
|
||||
|
||||
b3AlignedObjectArray<mat<4, 3, float> > clippedTriangles;
|
||||
clippedTriangles.initializeFromBuffer(stackTris, 0, 3);
|
||||
|
||||
bool hasClipped = clipTriangleAgainstNearplane(shader.varying_tri, clippedTriangles);
|
||||
|
||||
if (hasClipped)
|
||||
{
|
||||
for (int t = 0; t < clippedTriangles.size(); t++)
|
||||
{
|
||||
triangleClipped(clippedTriangles[t], shader.varying_tri, shader, frame, &zbuffer[0], segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex + ((renderData.m_linkIndex + 1) << 24));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
triangle(shader.varying_tri, shader, frame, &zbuffer[0], segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex + ((renderData.m_linkIndex + 1) << 24));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TinyRenderer::renderObjectDepth(TinyRenderObjectData& renderData)
|
||||
{
|
||||
int width = renderData.m_rgbColorBuffer.get_width();
|
||||
int height = renderData.m_rgbColorBuffer.get_height();
|
||||
|
||||
Vec3f light_dir_local = Vec3f(renderData.m_lightDirWorld[0], renderData.m_lightDirWorld[1], renderData.m_lightDirWorld[2]);
|
||||
float light_distance = renderData.m_lightDistance;
|
||||
Model* model = renderData.m_model;
|
||||
if (0 == model)
|
||||
return;
|
||||
|
||||
renderData.m_viewportMatrix = viewport(0, 0, width, height);
|
||||
|
||||
float* shadowBufferPtr = (renderData.m_shadowBuffer && renderData.m_shadowBuffer->size()) ? &renderData.m_shadowBuffer->at(0) : 0;
|
||||
int* segmentationMaskBufferPtr = 0;
|
||||
|
||||
TGAImage depthFrame(width, height, TGAImage::RGB);
|
||||
|
||||
{
|
||||
// light target is set to be the origin, and the up direction is set to be vertical up.
|
||||
Matrix lightViewMatrix = lookat(light_dir_local * light_distance, Vec3f(0.0, 0.0, 0.0), Vec3f(0.0, 0.0, 1.0));
|
||||
Matrix lightModelViewMatrix = lightViewMatrix * renderData.m_modelMatrix;
|
||||
Matrix lightViewProjectionMatrix = renderData.m_projectionMatrix;
|
||||
Vec3f localScaling(renderData.m_localScaling[0], renderData.m_localScaling[1], renderData.m_localScaling[2]);
|
||||
|
||||
DepthShader shader(model, lightModelViewMatrix, lightViewProjectionMatrix, renderData.m_modelMatrix, localScaling, light_distance);
|
||||
for (int i = 0; i < model->nfaces(); i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
shader.vertex(i, j);
|
||||
}
|
||||
|
||||
mat<4, 3, float> stackTris[3];
|
||||
|
||||
b3AlignedObjectArray<mat<4, 3, float> > clippedTriangles;
|
||||
clippedTriangles.initializeFromBuffer(stackTris, 0, 3);
|
||||
|
||||
bool hasClipped = clipTriangleAgainstNearplane(shader.varying_tri, clippedTriangles);
|
||||
|
||||
if (hasClipped)
|
||||
{
|
||||
for (int t = 0; t < clippedTriangles.size(); t++)
|
||||
{
|
||||
triangleClipped(clippedTriangles[t], shader.varying_tri, shader, depthFrame, shadowBufferPtr, segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
triangle(shader.varying_tri, shader, depthFrame, shadowBufferPtr, segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Engine/lib/bullet/examples/TinyRenderer/TinyRenderer.h
Normal file
66
Engine/lib/bullet/examples/TinyRenderer/TinyRenderer.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef TINY_RENDERER_H
|
||||
#define TINY_RENDERER_H
|
||||
|
||||
#include "geometry.h"
|
||||
#include "model.h"
|
||||
#include "Bullet3Common/b3AlignedObjectArray.h"
|
||||
#include "Bullet3Common/b3Vector3.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "LinearMath/btVector3.h"
|
||||
|
||||
#include "tgaimage.h"
|
||||
|
||||
struct TinyRenderObjectData
|
||||
{
|
||||
//Camera
|
||||
TinyRender::Matrix m_viewMatrix;
|
||||
TinyRender::Matrix m_projectionMatrix;
|
||||
TinyRender::Matrix m_viewportMatrix;
|
||||
btVector3 m_localScaling;
|
||||
btVector3 m_lightDirWorld;
|
||||
btVector3 m_lightColor;
|
||||
float m_lightDistance;
|
||||
float m_lightAmbientCoeff;
|
||||
float m_lightDiffuseCoeff;
|
||||
float m_lightSpecularCoeff;
|
||||
|
||||
//Model (vertices, indices, textures, shader)
|
||||
TinyRender::Matrix m_modelMatrix;
|
||||
TinyRender::Model* m_model;
|
||||
//class IShader* m_shader; todo(erwincoumans) expose the shader, for now we use a default shader
|
||||
|
||||
//Output
|
||||
|
||||
TGAImage& m_rgbColorBuffer;
|
||||
b3AlignedObjectArray<float>& m_depthBuffer; //required, hence a reference
|
||||
b3AlignedObjectArray<float>* m_shadowBuffer; //optional, hence a pointer
|
||||
b3AlignedObjectArray<int>* m_segmentationMaskBufferPtr; //optional, hence a pointer
|
||||
|
||||
TinyRenderObjectData(TGAImage& rgbColorBuffer, b3AlignedObjectArray<float>& depthBuffer);
|
||||
TinyRenderObjectData(TGAImage& rgbColorBuffer, b3AlignedObjectArray<float>& depthBuffer, b3AlignedObjectArray<int>* segmentationMaskBuffer, int objectIndex);
|
||||
TinyRenderObjectData(TGAImage& rgbColorBuffer, b3AlignedObjectArray<float>& depthBuffer, b3AlignedObjectArray<float>* shadowBuffer);
|
||||
TinyRenderObjectData(TGAImage& rgbColorBuffer, b3AlignedObjectArray<float>& depthBuffer, b3AlignedObjectArray<float>* shadowBuffer, b3AlignedObjectArray<int>* segmentationMaskBuffer, int objectIndex, int linkIndex);
|
||||
virtual ~TinyRenderObjectData();
|
||||
|
||||
void loadModel(const char* fileName, struct CommonFileIOInterface* fileIO);
|
||||
void createCube(float HalfExtentsX, float HalfExtentsY, float HalfExtentsZ, struct CommonFileIOInterface* fileIO=0);
|
||||
void registerMeshShape(const float* vertices, int numVertices, const int* indices, int numIndices, const float rgbaColor[4],
|
||||
unsigned char* textureImage = 0, int textureWidth = 0, int textureHeight = 0);
|
||||
|
||||
void registerMesh2(btAlignedObjectArray<btVector3>& vertices, btAlignedObjectArray<btVector3>& normals, btAlignedObjectArray<int>& indices, struct CommonFileIOInterface* fileIO);
|
||||
|
||||
void* m_userData;
|
||||
int m_userIndex;
|
||||
int m_objectIndex;
|
||||
int m_linkIndex;
|
||||
bool m_doubleSided;
|
||||
};
|
||||
|
||||
class TinyRenderer
|
||||
{
|
||||
public:
|
||||
static void renderObjectDepth(TinyRenderObjectData& renderData);
|
||||
static void renderObject(TinyRenderObjectData& renderData);
|
||||
};
|
||||
|
||||
#endif // TINY_RENDERER_Hbla
|
||||
25
Engine/lib/bullet/examples/TinyRenderer/geometry.cpp
Normal file
25
Engine/lib/bullet/examples/TinyRenderer/geometry.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#include "geometry.h"
|
||||
|
||||
namespace TinyRender
|
||||
{
|
||||
template <>
|
||||
template <>
|
||||
vec<3, int>::vec(const vec<3, float> &v) : x(int(v.x + .5f)), y(int(v.y + .5f)), z(int(v.z + .5f))
|
||||
{
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
vec<3, float>::vec(const vec<3, int> &v) : x(v.x), y(v.y), z(v.z)
|
||||
{
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
vec<2, int>::vec(const vec<2, float> &v) : x(int(v.x + .5f)), y(int(v.y + .5f))
|
||||
{
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
vec<2, float>::vec(const vec<2, int> &v) : x(v.x), y(v.y)
|
||||
{
|
||||
}
|
||||
}
|
||||
327
Engine/lib/bullet/examples/TinyRenderer/geometry.h
Normal file
327
Engine/lib/bullet/examples/TinyRenderer/geometry.h
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
#ifndef __GEOMETRY_H__
|
||||
#define __GEOMETRY_H__
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace TinyRender
|
||||
{
|
||||
template <size_t DimCols, size_t DimRows, typename T>
|
||||
class mat;
|
||||
|
||||
template <size_t DIM, typename T>
|
||||
struct vec
|
||||
{
|
||||
vec()
|
||||
{
|
||||
for (size_t i = DIM; i--; data_[i] = T())
|
||||
;
|
||||
}
|
||||
T& operator[](const size_t i)
|
||||
{
|
||||
assert(i < DIM);
|
||||
return data_[i];
|
||||
}
|
||||
const T& operator[](const size_t i) const
|
||||
{
|
||||
assert(i < DIM);
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
T data_[DIM];
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T>
|
||||
struct vec<2, T>
|
||||
{
|
||||
vec() : x(T()), y(T()) {}
|
||||
vec(T X, T Y) : x(X), y(Y) {}
|
||||
template <class U>
|
||||
vec<2, T>(const vec<2, U>& v);
|
||||
T& operator[](const size_t i)
|
||||
{
|
||||
assert(i < 2);
|
||||
return i <= 0 ? x : y;
|
||||
}
|
||||
const T& operator[](const size_t i) const
|
||||
{
|
||||
assert(i < 2);
|
||||
return i <= 0 ? x : y;
|
||||
}
|
||||
|
||||
T x, y;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T>
|
||||
struct vec<3, T>
|
||||
{
|
||||
vec() : x(T()), y(T()), z(T()) {}
|
||||
vec(T X, T Y, T Z) : x(X), y(Y), z(Z) {}
|
||||
template <class U>
|
||||
vec<3, T>(const vec<3, U>& v);
|
||||
T& operator[](const size_t i)
|
||||
{
|
||||
assert(i < 3);
|
||||
return i <= 0 ? x : (1 == i ? y : z);
|
||||
}
|
||||
const T& operator[](const size_t i) const
|
||||
{
|
||||
assert(i < 3);
|
||||
return i <= 0 ? x : (1 == i ? y : z);
|
||||
}
|
||||
float norm() { return std::sqrt(x * x + y * y + z * z); }
|
||||
vec<3, T>& normalize(T l = 1)
|
||||
{
|
||||
*this = (*this) * (l / norm());
|
||||
return *this;
|
||||
}
|
||||
|
||||
T x, y, z;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <size_t DIM, typename T>
|
||||
T operator*(const vec<DIM, T>& lhs, const vec<DIM, T>& rhs)
|
||||
{
|
||||
T ret = T();
|
||||
for (size_t i = DIM; i--; ret += lhs[i] * rhs[i])
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <size_t DIM, typename T>
|
||||
vec<DIM, T> operator+(vec<DIM, T> lhs, const vec<DIM, T>& rhs)
|
||||
{
|
||||
for (size_t i = DIM; i--; lhs[i] += rhs[i])
|
||||
;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <size_t DIM, typename T>
|
||||
vec<DIM, T> operator-(vec<DIM, T> lhs, const vec<DIM, T>& rhs)
|
||||
{
|
||||
for (size_t i = DIM; i--; lhs[i] -= rhs[i])
|
||||
;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <size_t DIM, typename T, typename U>
|
||||
vec<DIM, T> operator*(vec<DIM, T> lhs, const U& rhs)
|
||||
{
|
||||
for (size_t i = DIM; i--; lhs[i] *= rhs)
|
||||
;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <size_t DIM, typename T, typename U>
|
||||
vec<DIM, T> operator/(vec<DIM, T> lhs, const U& rhs)
|
||||
{
|
||||
for (size_t i = DIM; i--; lhs[i] /= rhs)
|
||||
;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <size_t LEN, size_t DIM, typename T>
|
||||
vec<LEN, T> embed(const vec<DIM, T>& v, T fill = 1)
|
||||
{
|
||||
vec<LEN, T> ret;
|
||||
for (size_t i = LEN; i--; ret[i] = (i < DIM ? v[i] : fill))
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <size_t LEN, size_t DIM, typename T>
|
||||
vec<LEN, T> proj(const vec<DIM, T>& v)
|
||||
{
|
||||
vec<LEN, T> ret;
|
||||
for (size_t i = LEN; i--; ret[i] = v[i])
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
vec<3, T> cross(vec<3, T> v1, vec<3, T> v2)
|
||||
{
|
||||
return vec<3, T>(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);
|
||||
}
|
||||
#if 0
|
||||
template <size_t DIM, typename T> std::ostream& operator<<(std::ostream& out, vec<DIM,T>& v) {
|
||||
for(unsigned int i=0; i<DIM; i++) {
|
||||
out << v[i] << " " ;
|
||||
}
|
||||
return out ;
|
||||
}
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <size_t DIM, typename T>
|
||||
struct dt
|
||||
{
|
||||
static T det(const mat<DIM, DIM, T>& src)
|
||||
{
|
||||
T ret = 0;
|
||||
for (size_t i = DIM; i--; ret += src[0][i] * src.cofactor(0, i))
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct dt<1, T>
|
||||
{
|
||||
static T det(const mat<1, 1, T>& src)
|
||||
{
|
||||
return src[0][0];
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <size_t DimRows, size_t DimCols, typename T>
|
||||
class mat
|
||||
{
|
||||
vec<DimCols, T> rows[DimRows];
|
||||
|
||||
public:
|
||||
mat() {}
|
||||
|
||||
vec<DimCols, T>& operator[](const size_t idx)
|
||||
{
|
||||
assert(idx < DimRows);
|
||||
return rows[idx];
|
||||
}
|
||||
|
||||
const vec<DimCols, T>& operator[](const size_t idx) const
|
||||
{
|
||||
assert(idx < DimRows);
|
||||
return rows[idx];
|
||||
}
|
||||
|
||||
vec<DimRows, T> col(const size_t idx) const
|
||||
{
|
||||
assert(idx < DimCols);
|
||||
vec<DimRows, T> ret;
|
||||
for (size_t i = DimRows; i--; ret[i] = rows[i][idx])
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void set_col(size_t idx, vec<DimRows, T> v)
|
||||
{
|
||||
assert(idx < DimCols);
|
||||
for (size_t i = DimRows; i--; rows[i][idx] = v[i])
|
||||
;
|
||||
}
|
||||
|
||||
static mat<DimRows, DimCols, T> identity()
|
||||
{
|
||||
mat<DimRows, DimCols, T> ret;
|
||||
for (size_t i = DimRows; i--;)
|
||||
for (size_t j = DimCols; j--; ret[i][j] = (i == j))
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
T det() const
|
||||
{
|
||||
return dt<DimCols, T>::det(*this);
|
||||
}
|
||||
|
||||
mat<DimRows - 1, DimCols - 1, T> get_minor(size_t row, size_t col) const
|
||||
{
|
||||
mat<DimRows - 1, DimCols - 1, T> ret;
|
||||
for (size_t i = DimRows - 1; i--;)
|
||||
for (size_t j = DimCols - 1; j--; ret[i][j] = rows[i < row ? i : i + 1][j < col ? j : j + 1])
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
T cofactor(size_t row, size_t col) const
|
||||
{
|
||||
return get_minor(row, col).det() * ((row + col) % 2 ? -1 : 1);
|
||||
}
|
||||
|
||||
mat<DimRows, DimCols, T> adjugate() const
|
||||
{
|
||||
mat<DimRows, DimCols, T> ret;
|
||||
for (size_t i = DimRows; i--;)
|
||||
for (size_t j = DimCols; j--; ret[i][j] = cofactor(i, j))
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
mat<DimRows, DimCols, T> invert_transpose()
|
||||
{
|
||||
mat<DimRows, DimCols, T> ret = adjugate();
|
||||
T tmp = ret[0] * rows[0];
|
||||
return ret / tmp;
|
||||
}
|
||||
|
||||
mat<DimRows, DimCols, T> invert()
|
||||
{
|
||||
return invert_transpose().transpose();
|
||||
}
|
||||
|
||||
mat<DimCols, DimRows, T> transpose()
|
||||
{
|
||||
mat<DimCols, DimRows, T> ret;
|
||||
for (size_t i = DimCols; i--; ret[i] = this->col(i))
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <size_t DimRows, size_t DimCols, typename T>
|
||||
vec<DimRows, T> operator*(const mat<DimRows, DimCols, T>& lhs, const vec<DimCols, T>& rhs)
|
||||
{
|
||||
vec<DimRows, T> ret;
|
||||
for (size_t i = DimRows; i--; ret[i] = lhs[i] * rhs)
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <size_t R1, size_t C1, size_t C2, typename T>
|
||||
mat<R1, C2, T> operator*(const mat<R1, C1, T>& lhs, const mat<C1, C2, T>& rhs)
|
||||
{
|
||||
mat<R1, C2, T> result;
|
||||
for (size_t i = R1; i--;)
|
||||
for (size_t j = C2; j--; result[i][j] = lhs[i] * rhs.col(j))
|
||||
;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <size_t DimRows, size_t DimCols, typename T>
|
||||
mat<DimCols, DimRows, T> operator/(mat<DimRows, DimCols, T> lhs, const T& rhs)
|
||||
{
|
||||
for (size_t i = DimRows; i--; lhs[i] = lhs[i] / rhs)
|
||||
;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <size_t DimRows,size_t DimCols,class T> std::ostream& operator<<(std::ostream& out, mat<DimRows,DimCols,T>& m) {
|
||||
for (size_t i=0; i<DimRows; i++) out << m[i] << std::endl;
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef vec<2, float> Vec2f;
|
||||
typedef vec<2, double> Vec2d;
|
||||
typedef vec<2, int> Vec2i;
|
||||
typedef vec<3, float> Vec3f;
|
||||
typedef vec<3, double> Vec3d;
|
||||
typedef vec<3, int> Vec3i;
|
||||
typedef vec<4, float> Vec4f;
|
||||
typedef mat<4, 4, float> Matrix;
|
||||
}
|
||||
|
||||
#endif //__GEOMETRY_H__
|
||||
240
Engine/lib/bullet/examples/TinyRenderer/main.cpp
Normal file
240
Engine/lib/bullet/examples/TinyRenderer/main.cpp
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
#include "OpenGLWindow/SimpleOpenGL3App.h"
|
||||
#include "Bullet3Common/b3Quaternion.h"
|
||||
#include "Bullet3Common/b3CommandLineArgs.h"
|
||||
#include "Bullet3Common/b3Transform.h"
|
||||
#include "Utils/b3BulletDefaultFileIO.h"
|
||||
#include "assert.h"
|
||||
#include <stdio.h>
|
||||
|
||||
char* gVideoFileName = 0;
|
||||
char* gPngFileName = 0;
|
||||
|
||||
static b3WheelCallback sOldWheelCB = 0;
|
||||
static b3ResizeCallback sOldResizeCB = 0;
|
||||
static b3MouseMoveCallback sOldMouseMoveCB = 0;
|
||||
static b3MouseButtonCallback sOldMouseButtonCB = 0;
|
||||
static b3KeyboardCallback sOldKeyboardCB = 0;
|
||||
//static b3RenderCallback sOldRenderCB = 0;
|
||||
|
||||
float gWidth = 0;
|
||||
float gHeight = 0;
|
||||
|
||||
void MyWheelCallback(float deltax, float deltay)
|
||||
{
|
||||
if (sOldWheelCB)
|
||||
sOldWheelCB(deltax, deltay);
|
||||
}
|
||||
void MyResizeCallback(float width, float height)
|
||||
{
|
||||
gWidth = width;
|
||||
gHeight = height;
|
||||
|
||||
if (sOldResizeCB)
|
||||
sOldResizeCB(width, height);
|
||||
}
|
||||
void MyMouseMoveCallback(float x, float y)
|
||||
{
|
||||
printf("Mouse Move: %f, %f\n", x, y);
|
||||
|
||||
if (sOldMouseMoveCB)
|
||||
sOldMouseMoveCB(x, y);
|
||||
}
|
||||
void MyMouseButtonCallback(int button, int state, float x, float y)
|
||||
{
|
||||
if (sOldMouseButtonCB)
|
||||
sOldMouseButtonCB(button, state, x, y);
|
||||
}
|
||||
|
||||
void MyKeyboardCallback(int keycode, int state)
|
||||
{
|
||||
//keycodes are in examples/CommonInterfaces/CommonWindowInterface.h
|
||||
//for example B3G_ESCAPE for escape key
|
||||
//state == 1 for pressed, state == 0 for released.
|
||||
// use app->m_window->isModifiedPressed(...) to check for shift, escape and alt keys
|
||||
printf("MyKeyboardCallback received key:%c in state %d\n", keycode, state);
|
||||
if (sOldKeyboardCB)
|
||||
sOldKeyboardCB(keycode, state);
|
||||
}
|
||||
#include "TinyRenderer.h"
|
||||
#include "our_gl.h"
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
b3CommandLineArgs myArgs(argc, argv);
|
||||
|
||||
SimpleOpenGL3App* app = new SimpleOpenGL3App("SimpleOpenGL3App", 640, 480, true);
|
||||
|
||||
app->m_instancingRenderer->getActiveCamera()->setCameraDistance(13);
|
||||
app->m_instancingRenderer->getActiveCamera()->setCameraPitch(0);
|
||||
app->m_instancingRenderer->getActiveCamera()->setCameraTargetPosition(0, 0, 0);
|
||||
sOldKeyboardCB = app->m_window->getKeyboardCallback();
|
||||
app->m_window->setKeyboardCallback(MyKeyboardCallback);
|
||||
sOldMouseMoveCB = app->m_window->getMouseMoveCallback();
|
||||
app->m_window->setMouseMoveCallback(MyMouseMoveCallback);
|
||||
sOldMouseButtonCB = app->m_window->getMouseButtonCallback();
|
||||
app->m_window->setMouseButtonCallback(MyMouseButtonCallback);
|
||||
sOldWheelCB = app->m_window->getWheelCallback();
|
||||
app->m_window->setWheelCallback(MyWheelCallback);
|
||||
sOldResizeCB = app->m_window->getResizeCallback();
|
||||
app->m_window->setResizeCallback(MyResizeCallback);
|
||||
|
||||
int textureWidth = gWidth;
|
||||
int textureHeight = gHeight;
|
||||
TGAImage rgbColorBuffer(gWidth, gHeight, TGAImage::RGB);
|
||||
b3AlignedObjectArray<float> depthBuffer;
|
||||
depthBuffer.resize(gWidth * gHeight);
|
||||
|
||||
TinyRenderObjectData renderData(rgbColorBuffer, depthBuffer); //, "african_head/african_head.obj");//floor.obj");
|
||||
|
||||
b3BulletDefaultFileIO fileIO;
|
||||
//renderData.loadModel("african_head/african_head.obj", &fileIO);
|
||||
|
||||
renderData.loadModel("floor.obj",&fileIO);
|
||||
|
||||
//renderData.createCube(1,1,1);
|
||||
|
||||
myArgs.GetCmdLineArgument("mp4_file", gVideoFileName);
|
||||
if (gVideoFileName)
|
||||
app->dumpFramesToVideo(gVideoFileName);
|
||||
|
||||
myArgs.GetCmdLineArgument("png_file", gPngFileName);
|
||||
char fileName[1024];
|
||||
|
||||
unsigned char* image = new unsigned char[textureWidth * textureHeight * 4];
|
||||
|
||||
int textureHandle = app->m_renderer->registerTexture(image, textureWidth, textureHeight);
|
||||
|
||||
int cubeIndex = app->registerCubeShape(1, 1, 1);
|
||||
|
||||
b3Vector3 pos = b3MakeVector3(0, 0, 0);
|
||||
b3Quaternion orn(0, 0, 0, 1);
|
||||
float color[4] = {1,1,1,1};
|
||||
|
||||
b3Vector3 scaling = b3MakeVector3(1, 1, 1);
|
||||
app->m_renderer->registerGraphicsInstance(cubeIndex, pos, orn, color, scaling);
|
||||
app->m_renderer->writeTransforms();
|
||||
|
||||
do
|
||||
{
|
||||
static int frameCount = 0;
|
||||
frameCount++;
|
||||
if (gPngFileName)
|
||||
{
|
||||
printf("gPngFileName=%s\n", gPngFileName);
|
||||
|
||||
sprintf(fileName, "%s%d.png", gPngFileName, frameCount++);
|
||||
app->dumpNextFrameToPng(fileName);
|
||||
}
|
||||
|
||||
app->m_instancingRenderer->init();
|
||||
app->m_instancingRenderer->updateCamera();
|
||||
|
||||
///clear the color and z (depth) buffer
|
||||
for (int y = 0; y < textureHeight; ++y)
|
||||
{
|
||||
unsigned char* pi = image + (y)*textureWidth * 3;
|
||||
for (int x = 0; x < textureWidth; ++x)
|
||||
{
|
||||
TGAColor color;
|
||||
color.bgra[0] = 255;
|
||||
color.bgra[1] = 255;
|
||||
color.bgra[2] = 255;
|
||||
color.bgra[3] = 255;
|
||||
|
||||
renderData.m_rgbColorBuffer.set(x, y, color);
|
||||
renderData.m_depthBuffer[x + y * textureWidth] = -1e30f;
|
||||
}
|
||||
}
|
||||
|
||||
float projMat[16];
|
||||
app->m_instancingRenderer->getActiveCamera()->getCameraProjectionMatrix(projMat);
|
||||
float viewMat[16];
|
||||
app->m_instancingRenderer->getActiveCamera()->getCameraViewMatrix(viewMat);
|
||||
B3_ATTRIBUTE_ALIGNED16(float modelMat[16]);
|
||||
|
||||
//sync the object transform
|
||||
b3Transform tr;
|
||||
tr.setIdentity();
|
||||
static float posUp = 0.f;
|
||||
// posUp += 0.001;
|
||||
b3Vector3 org = b3MakeVector3(0, 0, posUp);
|
||||
tr.setOrigin(org);
|
||||
tr.getOpenGLMatrix(modelMat);
|
||||
|
||||
TinyRender::Vec3f eye(1,1,3);
|
||||
TinyRender::Vec3f center(0,0,0);
|
||||
TinyRender::Vec3f up(0,1,0);
|
||||
|
||||
renderData.m_viewMatrix = TinyRender::lookat(eye, center, up);
|
||||
renderData.m_viewportMatrix = TinyRender::viewport(gWidth/8, gHeight/8, gWidth*3/4, gHeight*3/4);
|
||||
renderData.m_projectionMatrix = TinyRender::projection(-1.f/(eye-center).norm());
|
||||
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
renderData.m_viewMatrix[i][j] = viewMat[i + 4 * j];
|
||||
renderData.m_modelMatrix[i][j] = modelMat[i + 4 * j];
|
||||
}
|
||||
}
|
||||
|
||||
//render the object
|
||||
float color2[4] = { 1,1,1,1 };
|
||||
renderData.m_model->setColorRGBA(color2);
|
||||
TinyRenderer::renderObject(renderData);
|
||||
|
||||
#if 1
|
||||
//update the texels of the texture using a simple pattern, animated using frame index
|
||||
for (int y = 0; y < textureHeight; ++y)
|
||||
{
|
||||
unsigned char* pi = image + (y)*textureWidth * 3;
|
||||
for (int x = 0; x < textureWidth; ++x)
|
||||
{
|
||||
TGAColor color = renderData.m_rgbColorBuffer.get(x, y);
|
||||
pi[0] = color.bgra[2];
|
||||
pi[1] = color.bgra[1];
|
||||
pi[2] = color.bgra[0];
|
||||
pi[3] = 255;
|
||||
pi += 3;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
//update the texels of the texture using a simple pattern, animated using frame index
|
||||
for (int y = 0; y < textureHeight; ++y)
|
||||
{
|
||||
const int t = (y + frameCount) >> 4;
|
||||
unsigned char* pi = image + y * textureWidth * 3;
|
||||
for (int x = 0; x < textureWidth; ++x)
|
||||
{
|
||||
TGAColor color = renderData.m_rgbColorBuffer.get(x, y);
|
||||
|
||||
const int s = x >> 4;
|
||||
const unsigned char b = 180;
|
||||
unsigned char c = b + ((s + (t & 1)) & 1) * (255 - b);
|
||||
pi[0] = pi[1] = pi[2] = pi[3] = c;
|
||||
pi += 3;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
app->m_renderer->activateTexture(textureHandle);
|
||||
app->m_renderer->updateTexture(textureHandle, image);
|
||||
|
||||
float color[4] = {1, 1, 1, 1};
|
||||
app->m_primRenderer->drawTexturedRect(0, 0, gWidth / 3, gHeight / 3, color, 0, 0, 1, 1, true);
|
||||
|
||||
app->m_renderer->renderScene();
|
||||
app->drawGrid();
|
||||
char bla[1024];
|
||||
sprintf(bla, "Simple test frame %d", frameCount);
|
||||
float colorRGBA[4] = { 1,1,1,1 };
|
||||
app->drawText(bla, 10, 10,1, colorRGBA);
|
||||
app->swapBuffer();
|
||||
} while (!app->m_window->requestedExit());
|
||||
|
||||
delete app;
|
||||
return 0;
|
||||
}
|
||||
217
Engine/lib/bullet/examples/TinyRenderer/model.cpp
Normal file
217
Engine/lib/bullet/examples/TinyRenderer/model.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
|
||||
#include "model.h"
|
||||
#include <string.h> // memcpy
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "Bullet3Common/b3Logging.h"
|
||||
|
||||
namespace TinyRender
|
||||
{
|
||||
Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffusemap_(), normalmap_(), specularmap_()
|
||||
{
|
||||
std::ifstream in;
|
||||
in.open(filename, std::ifstream::in);
|
||||
if (in.fail()) return;
|
||||
std::string line;
|
||||
while (!in.eof())
|
||||
{
|
||||
std::getline(in, line);
|
||||
std::istringstream iss(line.c_str());
|
||||
char trash;
|
||||
if (!line.compare(0, 2, "v "))
|
||||
{
|
||||
iss >> trash;
|
||||
Vec3f v;
|
||||
for (int i = 0; i < 3; i++) iss >> v[i];
|
||||
verts_.push_back(v);
|
||||
}
|
||||
else if (!line.compare(0, 3, "vn "))
|
||||
{
|
||||
iss >> trash >> trash;
|
||||
Vec3f n;
|
||||
for (int i = 0; i < 3; i++) iss >> n[i];
|
||||
norms_.push_back(n);
|
||||
}
|
||||
else if (!line.compare(0, 3, "vt "))
|
||||
{
|
||||
iss >> trash >> trash;
|
||||
Vec2f uv;
|
||||
for (int i = 0; i < 2; i++) iss >> uv[i];
|
||||
uv_.push_back(uv);
|
||||
}
|
||||
else if (!line.compare(0, 2, "f "))
|
||||
{
|
||||
std::vector<Vec3i> f;
|
||||
Vec3i tmp;
|
||||
iss >> trash;
|
||||
while (iss >> tmp[0] >> trash >> tmp[1] >> trash >> tmp[2])
|
||||
{
|
||||
for (int i = 0; i < 3; i++) tmp[i]--; // in wavefront obj all indices start at 1, not zero
|
||||
f.push_back(tmp);
|
||||
}
|
||||
faces_.push_back(f);
|
||||
}
|
||||
}
|
||||
std::cerr << "# v# " << verts_.size() << " f# " << faces_.size() << " vt# " << uv_.size() << " vn# " << norms_.size() << std::endl;
|
||||
load_texture(filename, "_diffuse.tga", diffusemap_);
|
||||
load_texture(filename, "_nm_tangent.tga", normalmap_);
|
||||
load_texture(filename, "_spec.tga", specularmap_);
|
||||
}
|
||||
|
||||
Model::Model() : verts_(), faces_(), norms_(), uv_(), diffusemap_(), normalmap_(), specularmap_()
|
||||
{
|
||||
}
|
||||
|
||||
void Model::setDiffuseTextureFromData(unsigned char *textureImage, int textureWidth, int textureHeight)
|
||||
{
|
||||
{
|
||||
B3_PROFILE("new TGAImage");
|
||||
diffusemap_ = TGAImage(textureWidth, textureHeight, TGAImage::RGB);
|
||||
}
|
||||
TGAColor color;
|
||||
color.bgra[3] = 255;
|
||||
|
||||
color.bytespp = 3;
|
||||
{
|
||||
B3_PROFILE("copy texels");
|
||||
memcpy(diffusemap_.buffer(), textureImage, textureHeight * textureWidth * 3);
|
||||
}
|
||||
{
|
||||
B3_PROFILE("flip_vertically");
|
||||
diffusemap_.flip_vertically();
|
||||
}
|
||||
}
|
||||
|
||||
void Model::loadDiffuseTexture(const char *relativeFileName)
|
||||
{
|
||||
diffusemap_.read_tga_file(relativeFileName);
|
||||
}
|
||||
|
||||
void Model::reserveMemory(int numVertices, int numIndices)
|
||||
{
|
||||
verts_.reserve(numVertices);
|
||||
norms_.reserve(numVertices);
|
||||
uv_.reserve(numVertices);
|
||||
faces_.reserve(numIndices);
|
||||
}
|
||||
|
||||
void Model::addVertex(float x, float y, float z, float normalX, float normalY, float normalZ, float u, float v)
|
||||
{
|
||||
verts_.push_back(Vec3f(x, y, z));
|
||||
norms_.push_back(Vec3f(normalX, normalY, normalZ));
|
||||
uv_.push_back(Vec2f(u, v));
|
||||
}
|
||||
void Model::addTriangle(int vertexposIndex0, int normalIndex0, int uvIndex0,
|
||||
int vertexposIndex1, int normalIndex1, int uvIndex1,
|
||||
int vertexposIndex2, int normalIndex2, int uvIndex2)
|
||||
{
|
||||
std::vector<Vec3i> f;
|
||||
f.push_back(Vec3i(vertexposIndex0, normalIndex0, uvIndex0));
|
||||
f.push_back(Vec3i(vertexposIndex1, normalIndex1, uvIndex1));
|
||||
f.push_back(Vec3i(vertexposIndex2, normalIndex2, uvIndex2));
|
||||
faces_.push_back(f);
|
||||
}
|
||||
|
||||
Model::~Model() {}
|
||||
|
||||
int Model::nverts()
|
||||
{
|
||||
return (int)verts_.size();
|
||||
}
|
||||
|
||||
int Model::nfaces()
|
||||
{
|
||||
return (int)faces_.size();
|
||||
}
|
||||
|
||||
std::vector<int> Model::face(int idx)
|
||||
{
|
||||
std::vector<int> face;
|
||||
face.reserve((int)faces_[idx].size());
|
||||
for (int i = 0; i < (int)faces_[idx].size(); i++)
|
||||
face.push_back(faces_[idx][i][0]);
|
||||
return face;
|
||||
}
|
||||
|
||||
|
||||
Vec3f Model::vert(int i)
|
||||
{
|
||||
return verts_[i];
|
||||
}
|
||||
|
||||
Vec3f Model::vert(int iface, int nthvert)
|
||||
{
|
||||
return verts_[faces_[iface][nthvert][0]];
|
||||
}
|
||||
|
||||
void Model::load_texture(std::string filename, const char *suffix, TGAImage &img)
|
||||
{
|
||||
std::string texfile(filename);
|
||||
size_t dot = texfile.find_last_of('.');
|
||||
if (dot != std::string::npos)
|
||||
{
|
||||
texfile = texfile.substr(0, dot) + std::string(suffix);
|
||||
std::cerr << "texture file " << texfile << " loading " << (img.read_tga_file(texfile.c_str()) ? "ok" : "failed") << std::endl;
|
||||
img.flip_vertically();
|
||||
}
|
||||
}
|
||||
|
||||
TGAColor Model::diffuse(Vec2f uvf)
|
||||
{
|
||||
if (diffusemap_.get_width() && diffusemap_.get_height())
|
||||
{
|
||||
double val;
|
||||
// bool repeat = true;
|
||||
// if (repeat)
|
||||
{
|
||||
uvf[0] = std::modf(uvf[0], &val);
|
||||
if (uvf[0] < 0)
|
||||
{
|
||||
uvf[0] = uvf[0] + 1;
|
||||
}
|
||||
uvf[1] = std::modf(uvf[1], &val);
|
||||
if (uvf[1] < 0)
|
||||
{
|
||||
uvf[1] = uvf[1] + 1;
|
||||
}
|
||||
}
|
||||
Vec2i uv(uvf[0] * diffusemap_.get_width(), uvf[1] * diffusemap_.get_height());
|
||||
return diffusemap_.get(uv[0], uv[1]);
|
||||
}
|
||||
return TGAColor(255, 255, 255, 255);
|
||||
}
|
||||
|
||||
|
||||
Vec3f Model::normal(Vec2f uvf)
|
||||
{
|
||||
Vec2i uv(uvf[0] * normalmap_.get_width(), uvf[1] * normalmap_.get_height());
|
||||
TGAColor c = normalmap_.get(uv[0], uv[1]);
|
||||
Vec3f res;
|
||||
for (int i = 0; i < 3; i++)
|
||||
res[2 - i] = (float)c[i] / 255.f * 2.f - 1.f;
|
||||
return res;
|
||||
}
|
||||
|
||||
Vec2f Model::uv(int iface, int nthvert)
|
||||
{
|
||||
return uv_[faces_[iface][nthvert][1]];
|
||||
}
|
||||
|
||||
float Model::specular(Vec2f uvf)
|
||||
{
|
||||
if (specularmap_.get_width() && specularmap_.get_height())
|
||||
{
|
||||
Vec2i uv(uvf[0] * specularmap_.get_width(), uvf[1] * specularmap_.get_height());
|
||||
return specularmap_.get(uv[0], uv[1])[0] / 1.f;
|
||||
}
|
||||
return 2.0;
|
||||
}
|
||||
|
||||
Vec3f Model::normal(int iface, int nthvert)
|
||||
{
|
||||
int idx = faces_[iface][nthvert][2];
|
||||
return norms_[idx].normalize();
|
||||
}
|
||||
}
|
||||
79
Engine/lib/bullet/examples/TinyRenderer/model.h
Normal file
79
Engine/lib/bullet/examples/TinyRenderer/model.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef __MODEL_H__
|
||||
#define __MODEL_H__
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "geometry.h"
|
||||
#include "tgaimage.h"
|
||||
|
||||
namespace TinyRender
|
||||
{
|
||||
class Model
|
||||
{
|
||||
private:
|
||||
std::vector<Vec3f> verts_;
|
||||
std::vector<std::vector<Vec3i> > faces_; // attention, this Vec3i means vertex/uv/normal
|
||||
std::vector<Vec3f> norms_;
|
||||
std::vector<Vec2f> uv_;
|
||||
TGAImage diffusemap_;
|
||||
TGAImage normalmap_;
|
||||
TGAImage specularmap_;
|
||||
Vec4f m_colorRGBA;
|
||||
|
||||
void load_texture(std::string filename, const char* suffix, TGAImage& img);
|
||||
|
||||
public:
|
||||
Model(const char* filename);
|
||||
Model();
|
||||
void setColorRGBA(const float rgba[4])
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_colorRGBA[i] = rgba[i];
|
||||
}
|
||||
|
||||
const Vec4f& getColorRGBA() const
|
||||
{
|
||||
return m_colorRGBA;
|
||||
}
|
||||
void loadDiffuseTexture(const char* relativeFileName);
|
||||
void setDiffuseTextureFromData(unsigned char* textureImage, int textureWidth, int textureHeight);
|
||||
void reserveMemory(int numVertices, int numIndices);
|
||||
void addVertex(float x, float y, float z, float normalX, float normalY, float normalZ, float u, float v);
|
||||
void addTriangle(int vertexposIndex0, int normalIndex0, int uvIndex0,
|
||||
int vertexposIndex1, int normalIndex1, int uvIndex1,
|
||||
int vertexposIndex2, int normalIndex2, int uvIndex2);
|
||||
|
||||
~Model();
|
||||
int nverts();
|
||||
int nnormals()
|
||||
{
|
||||
return norms_.size();
|
||||
}
|
||||
int nfaces();
|
||||
|
||||
Vec3f normal(int iface, int nthvert);
|
||||
Vec3f normal(Vec2f uv);
|
||||
Vec3f vert(int i);
|
||||
Vec3f vert(int iface, int nthvert);
|
||||
Vec3f* readWriteVertices()
|
||||
{
|
||||
if (verts_.size() == 0)
|
||||
return 0;
|
||||
return &verts_[0];
|
||||
}
|
||||
|
||||
Vec3f* readWriteNormals()
|
||||
{
|
||||
if (norms_.size() == 0)
|
||||
return 0;
|
||||
return &norms_[0];
|
||||
}
|
||||
|
||||
|
||||
Vec2f uv(int iface, int nthvert);
|
||||
TGAColor diffuse(Vec2f uv);
|
||||
float specular(Vec2f uv);
|
||||
std::vector<int> face(int idx);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //__MODEL_H__
|
||||
221
Engine/lib/bullet/examples/TinyRenderer/our_gl.cpp
Normal file
221
Engine/lib/bullet/examples/TinyRenderer/our_gl.cpp
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <cstdlib>
|
||||
#include "our_gl.h"
|
||||
#include "Bullet3Common/b3MinMax.h"
|
||||
|
||||
namespace TinyRender
|
||||
{
|
||||
IShader::~IShader() {}
|
||||
|
||||
Matrix viewport(int x, int y, int w, int h)
|
||||
{
|
||||
Matrix Viewport;
|
||||
Viewport = Matrix::identity();
|
||||
Viewport[0][3] = x + w / 2.f;
|
||||
Viewport[1][3] = y + h / 2.f;
|
||||
Viewport[2][3] = .5f;
|
||||
Viewport[0][0] = w / 2.f;
|
||||
Viewport[1][1] = h / 2.f;
|
||||
Viewport[2][2] = .5f;
|
||||
return Viewport;
|
||||
}
|
||||
|
||||
Matrix projection(float coeff)
|
||||
{
|
||||
Matrix Projection;
|
||||
Projection = Matrix::identity();
|
||||
Projection[3][2] = coeff;
|
||||
return Projection;
|
||||
}
|
||||
|
||||
Matrix lookat(Vec3f eye, Vec3f center, Vec3f up)
|
||||
{
|
||||
Vec3f f = (center - eye).normalize();
|
||||
Vec3f u = up.normalize();
|
||||
Vec3f s = cross(f, u).normalize();
|
||||
u = cross(s, f);
|
||||
|
||||
Matrix ModelView;
|
||||
ModelView[0][0] = s.x;
|
||||
ModelView[0][1] = s.y;
|
||||
ModelView[0][2] = s.z;
|
||||
|
||||
ModelView[1][0] = u.x;
|
||||
ModelView[1][1] = u.y;
|
||||
ModelView[1][2] = u.z;
|
||||
|
||||
ModelView[2][0] = -f.x;
|
||||
ModelView[2][1] = -f.y;
|
||||
ModelView[2][2] = -f.z;
|
||||
|
||||
ModelView[3][0] = 0.f;
|
||||
ModelView[3][1] = 0.f;
|
||||
ModelView[3][2] = 0.f;
|
||||
|
||||
ModelView[0][3] = -(s[0] * eye[0] + s[1] * eye[1] + s[2] * eye[2]);
|
||||
ModelView[1][3] = -(u[0] * eye[0] + u[1] * eye[1] + u[2] * eye[2]);
|
||||
ModelView[2][3] = f[0] * eye[0] + f[1] * eye[1] + f[2] * eye[2];
|
||||
ModelView[3][3] = 1.f;
|
||||
|
||||
return ModelView;
|
||||
}
|
||||
|
||||
Vec3d barycentric(Vec2f A1, Vec2f B1, Vec2f C1, Vec2f P1)
|
||||
{
|
||||
|
||||
Vec2d A(A1.x, A1.y);
|
||||
Vec2d B(B1.x, B1.y);
|
||||
Vec2d C(C1.x, C1.y);
|
||||
Vec2d P(P1.x, P1.y);;
|
||||
|
||||
Vec3d s[2];
|
||||
for (int i = 2; i--;)
|
||||
{
|
||||
s[i][0] = C[i] - A[i];
|
||||
s[i][1] = B[i] - A[i];
|
||||
s[i][2] = A[i] - P[i];
|
||||
}
|
||||
Vec3d u = cross(s[0], s[1]);
|
||||
if (std::abs(u[2]) > 1e-2) // dont forget that u[2] is integer. If it is zero then triangle ABC is degenerate
|
||||
return Vec3d(1. - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z);
|
||||
return Vec3d(-1., 1., 1.); // in this case generate negative coordinates, it will be thrown away by the rasterizator
|
||||
}
|
||||
|
||||
void triangleClipped(mat<4, 3, float> &clipc, mat<4, 3, float> &orgClipc, IShader &shader, TGAImage &image, float *zbuffer, const Matrix &viewPortMatrix)
|
||||
{
|
||||
triangleClipped(clipc, orgClipc, shader, image, zbuffer, 0, viewPortMatrix, 0);
|
||||
}
|
||||
|
||||
void triangleClipped(mat<4, 3, float> &clipc, mat<4, 3, float> &orgClipc, IShader &shader, TGAImage &image, float *zbuffer, int *segmentationMaskBuffer, const Matrix &viewPortMatrix, int objectAndLinkIndex)
|
||||
{
|
||||
mat<3, 4, float> screenSpacePts = (viewPortMatrix * clipc).transpose(); // transposed to ease access to each of the points
|
||||
|
||||
mat<3, 2, float> pts2;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
pts2[i] = proj<2>(screenSpacePts[i] / screenSpacePts[i][3]);
|
||||
}
|
||||
|
||||
Vec2f bboxmin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
|
||||
Vec2f bboxmax(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
|
||||
Vec2f clamp(image.get_width() - 1, image.get_height() - 1);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
bboxmin[j] = b3Max(0.f, b3Min(bboxmin[j], pts2[i][j]));
|
||||
bboxmax[j] = b3Min(clamp[j], b3Max(bboxmax[j], pts2[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
Vec2i P;
|
||||
TGAColor color;
|
||||
|
||||
mat<3, 4, float> orgScreenSpacePts = (viewPortMatrix * orgClipc).transpose(); // transposed to ease access to each of the points
|
||||
|
||||
mat<3, 2, float> orgPts2;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
orgPts2[i] = proj<2>(orgScreenSpacePts[i] / orgScreenSpacePts[i][3]);
|
||||
}
|
||||
|
||||
for (P.x = bboxmin.x; P.x <= bboxmax.x; P.x++)
|
||||
{
|
||||
for (P.y = bboxmin.y; P.y <= bboxmax.y; P.y++)
|
||||
{
|
||||
double frag_depth = 0;
|
||||
{
|
||||
Vec3d bc_screen = barycentric(pts2[0], pts2[1], pts2[2], P);
|
||||
Vec3d bc_clip = Vec3d(bc_screen.x / screenSpacePts[0][3], bc_screen.y / screenSpacePts[1][3], bc_screen.z / screenSpacePts[2][3]);
|
||||
bc_clip = bc_clip / (bc_clip.x + bc_clip.y + bc_clip.z);
|
||||
Vec3d clipd(clipc[2].x, clipc[2].y, clipc[2].z);
|
||||
frag_depth = -1. * (clipd * bc_clip);
|
||||
|
||||
if (bc_screen.x < 0 || bc_screen.y < 0 || bc_screen.z < 0 ||
|
||||
zbuffer[P.x + P.y * image.get_width()] > frag_depth)
|
||||
continue;
|
||||
}
|
||||
|
||||
Vec3d bc_screen2 = barycentric(orgPts2[0], orgPts2[1], orgPts2[2], P);
|
||||
Vec3d bc_clip2 = Vec3d(bc_screen2.x / orgScreenSpacePts[0][3], bc_screen2.y / orgScreenSpacePts[1][3], bc_screen2.z / orgScreenSpacePts[2][3]);
|
||||
bc_clip2 = bc_clip2 / (bc_clip2.x + bc_clip2.y + bc_clip2.z);
|
||||
Vec3d orgClipd(orgClipc[2].x, orgClipc[2].y, orgClipc[2].z);
|
||||
double frag_depth2 = -1. * (orgClipd * bc_clip2);
|
||||
|
||||
Vec3f bc_clip2f(bc_clip2.x, bc_clip2.y, bc_clip2.z);
|
||||
bool discard = shader.fragment(bc_clip2f, color);
|
||||
|
||||
if (!discard)
|
||||
{
|
||||
zbuffer[P.x + P.y * image.get_width()] = frag_depth;
|
||||
if (segmentationMaskBuffer)
|
||||
{
|
||||
segmentationMaskBuffer[P.x + P.y * image.get_width()] = objectAndLinkIndex;
|
||||
}
|
||||
image.set(P.x, P.y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void triangle(mat<4, 3, float> &clipc, IShader &shader, TGAImage &image, float *zbuffer, const Matrix &viewPortMatrix)
|
||||
{
|
||||
triangle(clipc, shader, image, zbuffer, 0, viewPortMatrix, 0);
|
||||
}
|
||||
|
||||
void triangle(mat<4, 3, float> &clipc, IShader &shader, TGAImage &image, float *zbuffer, int *segmentationMaskBuffer, const Matrix &viewPortMatrix, int objectAndLinkIndex)
|
||||
{
|
||||
mat<3, 4, float> pts = (viewPortMatrix * clipc).transpose(); // transposed to ease access to each of the points
|
||||
|
||||
mat<3, 2, float> pts2;
|
||||
for (int i = 0; i < 3; i++) pts2[i] = proj<2>(pts[i] / pts[i][3]);
|
||||
|
||||
Vec2f bboxmin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
|
||||
Vec2f bboxmax(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
|
||||
Vec2f clamp(image.get_width() - 1, image.get_height() - 1);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
bboxmin[j] = b3Max(0.f, b3Min(bboxmin[j], pts2[i][j]));
|
||||
bboxmax[j] = b3Min(clamp[j], b3Max(bboxmax[j], pts2[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
Vec2i P;
|
||||
TGAColor color;
|
||||
for (P.x = bboxmin.x; P.x <= bboxmax.x; P.x++)
|
||||
{
|
||||
for (P.y = bboxmin.y; P.y <= bboxmax.y; P.y++)
|
||||
{
|
||||
Vec3d bc_screen = barycentric(pts2[0], pts2[1], pts2[2], P);
|
||||
Vec3d bc_clip = Vec3d(bc_screen.x / pts[0][3], bc_screen.y / pts[1][3], bc_screen.z / pts[2][3]);
|
||||
bc_clip = bc_clip / (bc_clip.x + bc_clip.y + bc_clip.z);
|
||||
Vec3d clipd(clipc[2].x, clipc[2].y, clipc[2].z);
|
||||
double frag_depth = -1. * (clipd * bc_clip);
|
||||
if (bc_screen.x < 0 || bc_screen.y < 0 || bc_screen.z < 0 ||
|
||||
zbuffer[P.x + P.y * image.get_width()] > frag_depth)
|
||||
continue;
|
||||
Vec3f bc_clipf(bc_clip.x, bc_clip.y, bc_clip.z);
|
||||
bool discard = shader.fragment(bc_clipf, color);
|
||||
if (frag_depth < -shader.m_farPlane)
|
||||
discard = true;
|
||||
if (frag_depth > shader.m_nearPlane)
|
||||
discard = true;
|
||||
|
||||
if (!discard)
|
||||
{
|
||||
zbuffer[P.x + P.y * image.get_width()] = frag_depth;
|
||||
if (segmentationMaskBuffer)
|
||||
{
|
||||
segmentationMaskBuffer[P.x + P.y * image.get_width()] = objectAndLinkIndex;
|
||||
}
|
||||
image.set(P.x, P.y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Engine/lib/bullet/examples/TinyRenderer/our_gl.h
Normal file
27
Engine/lib/bullet/examples/TinyRenderer/our_gl.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __OUR_GL_H__
|
||||
#define __OUR_GL_H__
|
||||
#include "tgaimage.h"
|
||||
#include "geometry.h"
|
||||
|
||||
namespace TinyRender
|
||||
{
|
||||
Matrix viewport(int x, int y, int w, int h);
|
||||
Matrix projection(float coeff = 0.f); // coeff = -1/c
|
||||
Matrix lookat(Vec3f eye, Vec3f center, Vec3f up);
|
||||
|
||||
struct IShader
|
||||
{
|
||||
float m_nearPlane;
|
||||
float m_farPlane;
|
||||
virtual ~IShader();
|
||||
virtual Vec4f vertex(int iface, int nthvert) = 0;
|
||||
virtual bool fragment(Vec3f bar, TGAColor &color) = 0;
|
||||
};
|
||||
|
||||
void triangle(mat<4, 3, float> &pts, IShader &shader, TGAImage &image, float *zbuffer, const Matrix &viewPortMatrix);
|
||||
void triangle(mat<4, 3, float> &pts, IShader &shader, TGAImage &image, float *zbuffer, int *segmentationMaskBuffer, const Matrix &viewPortMatrix, int objectIndex);
|
||||
void triangleClipped(mat<4, 3, float> &clippedPts, mat<4, 3, float> &pts, IShader &shader, TGAImage &image, float *zbuffer, const Matrix &viewPortMatrix);
|
||||
void triangleClipped(mat<4, 3, float> &clippedPts, mat<4, 3, float> &pts, IShader &shader, TGAImage &image, float *zbuffer, int *segmentationMaskBuffer, const Matrix &viewPortMatrix, int objectIndex);
|
||||
}
|
||||
|
||||
#endif //__OUR_GL_H__
|
||||
29
Engine/lib/bullet/examples/TinyRenderer/premake4.lua
Normal file
29
Engine/lib/bullet/examples/TinyRenderer/premake4.lua
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
project "App_TinyRenderer"
|
||||
|
||||
language "C++"
|
||||
|
||||
kind "ConsoleApp"
|
||||
|
||||
includedirs {
|
||||
".",
|
||||
"../../src",
|
||||
".."
|
||||
}
|
||||
|
||||
|
||||
links{ "OpenGL_Window","Bullet3Common"}
|
||||
initOpenGL()
|
||||
initGlew()
|
||||
|
||||
files {
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"../Utils/b3ResourcePath.cpp"
|
||||
}
|
||||
|
||||
if os.is("Linux") then initX11() end
|
||||
|
||||
if os.is("MacOSX") then
|
||||
links{"Cocoa.framework"}
|
||||
end
|
||||
443
Engine/lib/bullet/examples/TinyRenderer/tgaimage.cpp
Normal file
443
Engine/lib/bullet/examples/TinyRenderer/tgaimage.cpp
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include "tgaimage.h"
|
||||
|
||||
TGAImage::TGAImage() : data(NULL), width(0), height(0), bytespp(0) {}
|
||||
|
||||
TGAImage::TGAImage(int w, int h, int bpp) : data(NULL), width(w), height(h), bytespp(bpp)
|
||||
{
|
||||
unsigned long nbytes = width * height * bytespp;
|
||||
data = new unsigned char[nbytes];
|
||||
//memset(data, 0, nbytes);
|
||||
}
|
||||
|
||||
TGAImage::TGAImage(const TGAImage &img) : data(NULL), width(img.width), height(img.height), bytespp(img.bytespp)
|
||||
{
|
||||
unsigned long nbytes = width * height * bytespp;
|
||||
data = new unsigned char[nbytes];
|
||||
//memcpy(data, img.data, nbytes);
|
||||
}
|
||||
|
||||
TGAImage::~TGAImage()
|
||||
{
|
||||
if (data) delete[] data;
|
||||
}
|
||||
|
||||
TGAImage &TGAImage::operator=(const TGAImage &img)
|
||||
{
|
||||
if (this != &img)
|
||||
{
|
||||
if (data) delete[] data;
|
||||
width = img.width;
|
||||
height = img.height;
|
||||
bytespp = img.bytespp;
|
||||
unsigned long nbytes = width * height * bytespp;
|
||||
data = new unsigned char[nbytes];
|
||||
memcpy(data, img.data, nbytes);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool TGAImage::read_tga_file(const char *filename)
|
||||
{
|
||||
if (data) delete[] data;
|
||||
data = NULL;
|
||||
std::ifstream in;
|
||||
in.open(filename, std::ios::binary);
|
||||
if (!in.is_open())
|
||||
{
|
||||
std::cerr << "can't open file " << filename << "\n";
|
||||
in.close();
|
||||
return false;
|
||||
}
|
||||
TGA_Header header;
|
||||
in.read((char *)&header, sizeof(header));
|
||||
if (!in.good())
|
||||
{
|
||||
in.close();
|
||||
std::cerr << "an error occured while reading the header\n";
|
||||
return false;
|
||||
}
|
||||
width = header.width;
|
||||
height = header.height;
|
||||
bytespp = header.bitsperpixel >> 3;
|
||||
if (width <= 0 || height <= 0 || (bytespp != GRAYSCALE && bytespp != RGB && bytespp != RGBA))
|
||||
{
|
||||
in.close();
|
||||
std::cerr << "bad bpp (or width/height) value\n";
|
||||
return false;
|
||||
}
|
||||
unsigned long nbytes = bytespp * width * height;
|
||||
data = new unsigned char[nbytes];
|
||||
if (3 == header.datatypecode || 2 == header.datatypecode)
|
||||
{
|
||||
in.read((char *)data, nbytes);
|
||||
if (!in.good())
|
||||
{
|
||||
in.close();
|
||||
std::cerr << "an error occured while reading the data\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (10 == header.datatypecode || 11 == header.datatypecode)
|
||||
{
|
||||
if (!load_rle_data(in))
|
||||
{
|
||||
in.close();
|
||||
std::cerr << "an error occured while reading the data\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
in.close();
|
||||
std::cerr << "unknown file format " << (int)header.datatypecode << "\n";
|
||||
return false;
|
||||
}
|
||||
if (!(header.imagedescriptor & 0x20))
|
||||
{
|
||||
flip_vertically();
|
||||
}
|
||||
if (header.imagedescriptor & 0x10)
|
||||
{
|
||||
flip_horizontally();
|
||||
}
|
||||
std::cerr << width << "x" << height << "/" << bytespp * 8 << "\n";
|
||||
in.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TGAImage::load_rle_data(std::ifstream &in)
|
||||
{
|
||||
unsigned long pixelcount = width * height;
|
||||
unsigned long currentpixel = 0;
|
||||
unsigned long currentbyte = 0;
|
||||
TGAColor colorbuffer;
|
||||
do
|
||||
{
|
||||
unsigned char chunkheader = 0;
|
||||
chunkheader = in.get();
|
||||
if (!in.good())
|
||||
{
|
||||
std::cerr << "an error occured while reading the data\n";
|
||||
return false;
|
||||
}
|
||||
if (chunkheader < 128)
|
||||
{
|
||||
chunkheader++;
|
||||
for (int i = 0; i < chunkheader; i++)
|
||||
{
|
||||
in.read((char *)colorbuffer.bgra, bytespp);
|
||||
if (!in.good())
|
||||
{
|
||||
std::cerr << "an error occured while reading the header\n";
|
||||
return false;
|
||||
}
|
||||
for (int t = 0; t < bytespp; t++)
|
||||
data[currentbyte++] = colorbuffer.bgra[t];
|
||||
currentpixel++;
|
||||
if (currentpixel > pixelcount)
|
||||
{
|
||||
std::cerr << "Too many pixels read\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkheader -= 127;
|
||||
in.read((char *)colorbuffer.bgra, bytespp);
|
||||
if (!in.good())
|
||||
{
|
||||
std::cerr << "an error occured while reading the header\n";
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < chunkheader; i++)
|
||||
{
|
||||
for (int t = 0; t < bytespp; t++)
|
||||
data[currentbyte++] = colorbuffer.bgra[t];
|
||||
currentpixel++;
|
||||
if (currentpixel > pixelcount)
|
||||
{
|
||||
std::cerr << "Too many pixels read\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (currentpixel < pixelcount);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TGAImage::write_tga_file(const char *filename, bool rle) const
|
||||
{
|
||||
unsigned char developer_area_ref[4] = {0, 0, 0, 0};
|
||||
unsigned char extension_area_ref[4] = {0, 0, 0, 0};
|
||||
unsigned char footer[18] = {'T', 'R', 'U', 'E', 'V', 'I', 'S', 'I', 'O', 'N', '-', 'X', 'F', 'I', 'L', 'E', '.', '\0'};
|
||||
std::ofstream out;
|
||||
out.open(filename, std::ios::binary);
|
||||
if (!out.is_open())
|
||||
{
|
||||
std::cerr << "can't open file " << filename << "\n";
|
||||
out.close();
|
||||
return false;
|
||||
}
|
||||
TGA_Header header;
|
||||
memset((void *)&header, 0, sizeof(header));
|
||||
header.bitsperpixel = bytespp << 3;
|
||||
header.width = width;
|
||||
header.height = height;
|
||||
header.datatypecode = (bytespp == GRAYSCALE ? (rle ? 11 : 3) : (rle ? 10 : 2));
|
||||
header.imagedescriptor = 0x20; // top-left origin
|
||||
out.write((char *)&header, sizeof(header));
|
||||
if (!out.good())
|
||||
{
|
||||
out.close();
|
||||
std::cerr << "can't dump the tga file\n";
|
||||
return false;
|
||||
}
|
||||
if (!rle)
|
||||
{
|
||||
out.write((char *)data, width * height * bytespp);
|
||||
if (!out.good())
|
||||
{
|
||||
std::cerr << "can't unload raw data\n";
|
||||
out.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!unload_rle_data(out))
|
||||
{
|
||||
out.close();
|
||||
std::cerr << "can't unload rle data\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
out.write((char *)developer_area_ref, sizeof(developer_area_ref));
|
||||
if (!out.good())
|
||||
{
|
||||
std::cerr << "can't dump the tga file\n";
|
||||
out.close();
|
||||
return false;
|
||||
}
|
||||
out.write((char *)extension_area_ref, sizeof(extension_area_ref));
|
||||
if (!out.good())
|
||||
{
|
||||
std::cerr << "can't dump the tga file\n";
|
||||
out.close();
|
||||
return false;
|
||||
}
|
||||
out.write((char *)footer, sizeof(footer));
|
||||
if (!out.good())
|
||||
{
|
||||
std::cerr << "can't dump the tga file\n";
|
||||
out.close();
|
||||
return false;
|
||||
}
|
||||
out.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: it is not necessary to break a raw chunk for two equal pixels (for the matter of the resulting size)
|
||||
bool TGAImage::unload_rle_data(std::ofstream &out) const
|
||||
{
|
||||
const unsigned char max_chunk_length = 128;
|
||||
unsigned long npixels = width * height;
|
||||
unsigned long curpix = 0;
|
||||
while (curpix < npixels)
|
||||
{
|
||||
unsigned long chunkstart = curpix * bytespp;
|
||||
unsigned long curbyte = curpix * bytespp;
|
||||
unsigned char run_length = 1;
|
||||
bool raw = true;
|
||||
while (curpix + run_length < npixels && run_length < max_chunk_length)
|
||||
{
|
||||
bool succ_eq = true;
|
||||
for (int t = 0; succ_eq && t < bytespp; t++)
|
||||
{
|
||||
succ_eq = (data[curbyte + t] == data[curbyte + t + bytespp]);
|
||||
}
|
||||
curbyte += bytespp;
|
||||
if (1 == run_length)
|
||||
{
|
||||
raw = !succ_eq;
|
||||
}
|
||||
if (raw && succ_eq)
|
||||
{
|
||||
run_length--;
|
||||
break;
|
||||
}
|
||||
if (!raw && !succ_eq)
|
||||
{
|
||||
break;
|
||||
}
|
||||
run_length++;
|
||||
}
|
||||
curpix += run_length;
|
||||
out.put(raw ? run_length - 1 : run_length + 127);
|
||||
if (!out.good())
|
||||
{
|
||||
std::cerr << "can't dump the tga file\n";
|
||||
return false;
|
||||
}
|
||||
out.write((char *)(data + chunkstart), (raw ? run_length * bytespp : bytespp));
|
||||
if (!out.good())
|
||||
{
|
||||
std::cerr << "can't dump the tga file\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TGAColor TGAImage::get(int x, int y) const
|
||||
{
|
||||
if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
if (x >= width)
|
||||
{
|
||||
x = width - 1;
|
||||
}
|
||||
if (y >= height)
|
||||
{
|
||||
y = height - 1;
|
||||
}
|
||||
|
||||
if (!data || x < 0 || y < 0 || x >= width || y >= height)
|
||||
{
|
||||
return TGAColor(128.f, 128.f, 128.f, 255.f);
|
||||
}
|
||||
return TGAColor(data + (x + y * width) * bytespp, bytespp);
|
||||
}
|
||||
|
||||
bool TGAImage::set(int x, int y, TGAColor &c)
|
||||
{
|
||||
if (!data || x < 0 || y < 0 || x >= width || y >= height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memcpy(data + (x + y * width) * bytespp, c.bgra, bytespp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TGAImage::set(int x, int y, const TGAColor &c)
|
||||
{
|
||||
if (!data || x < 0 || y < 0 || x >= width || y >= height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memcpy(data + (x + y * width) * bytespp, c.bgra, bytespp);
|
||||
return true;
|
||||
}
|
||||
|
||||
int TGAImage::get_bytespp()
|
||||
{
|
||||
return bytespp;
|
||||
}
|
||||
|
||||
int TGAImage::get_width()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
int TGAImage::get_height()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
bool TGAImage::flip_horizontally()
|
||||
{
|
||||
if (!data) return false;
|
||||
int half = width >> 1;
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
TGAColor c1 = get(i, j);
|
||||
TGAColor c2 = get(width - 1 - i, j);
|
||||
set(i, j, c2);
|
||||
set(width - 1 - i, j, c1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TGAImage::flip_vertically()
|
||||
{
|
||||
if (!data) return false;
|
||||
unsigned long bytes_per_line = width * bytespp;
|
||||
unsigned char *line = new unsigned char[bytes_per_line];
|
||||
int half = height >> 1;
|
||||
for (int j = 0; j < half; j++)
|
||||
{
|
||||
unsigned long l1 = j * bytes_per_line;
|
||||
unsigned long l2 = (height - 1 - j) * bytes_per_line;
|
||||
memmove((void *)line, (void *)(data + l1), bytes_per_line);
|
||||
memmove((void *)(data + l1), (void *)(data + l2), bytes_per_line);
|
||||
memmove((void *)(data + l2), (void *)line, bytes_per_line);
|
||||
}
|
||||
delete[] line;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char *TGAImage::buffer()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
void TGAImage::clear()
|
||||
{
|
||||
memset((void *)data, 0, width * height * bytespp);
|
||||
}
|
||||
|
||||
bool TGAImage::scale(int w, int h)
|
||||
{
|
||||
if (w <= 0 || h <= 0 || !data) return false;
|
||||
unsigned char *tdata = new unsigned char[w * h * bytespp];
|
||||
int nscanline = 0;
|
||||
int oscanline = 0;
|
||||
int erry = 0;
|
||||
unsigned long nlinebytes = w * bytespp;
|
||||
unsigned long olinebytes = width * bytespp;
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
int errx = width - w;
|
||||
int nx = -bytespp;
|
||||
int ox = -bytespp;
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
ox += bytespp;
|
||||
errx += w;
|
||||
while (errx >= (int)width)
|
||||
{
|
||||
errx -= width;
|
||||
nx += bytespp;
|
||||
memcpy(tdata + nscanline + nx, data + oscanline + ox, bytespp);
|
||||
}
|
||||
}
|
||||
erry += h;
|
||||
oscanline += olinebytes;
|
||||
while (erry >= (int)height)
|
||||
{
|
||||
if (erry >= (int)height << 1) // it means we jump over a scanline
|
||||
memcpy(tdata + nscanline + nlinebytes, tdata + nscanline, nlinebytes);
|
||||
erry -= height;
|
||||
nscanline += nlinebytes;
|
||||
}
|
||||
}
|
||||
delete[] data;
|
||||
data = tdata;
|
||||
width = w;
|
||||
height = h;
|
||||
return true;
|
||||
}
|
||||
112
Engine/lib/bullet/examples/TinyRenderer/tgaimage.h
Normal file
112
Engine/lib/bullet/examples/TinyRenderer/tgaimage.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#ifndef __IMAGE_H__
|
||||
#define __IMAGE_H__
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct TGA_Header
|
||||
{
|
||||
char idlength;
|
||||
char colormaptype;
|
||||
char datatypecode;
|
||||
short colormaporigin;
|
||||
short colormaplength;
|
||||
char colormapdepth;
|
||||
short x_origin;
|
||||
short y_origin;
|
||||
short width;
|
||||
short height;
|
||||
char bitsperpixel;
|
||||
char imagedescriptor;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct TGAColor
|
||||
{
|
||||
unsigned char bgra[4];
|
||||
unsigned char bytespp;
|
||||
|
||||
TGAColor() : bytespp(1)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
bgra[i] = 0;
|
||||
}
|
||||
|
||||
TGAColor(unsigned char R, unsigned char G, unsigned char B, unsigned char A = 255) : bytespp(4)
|
||||
{
|
||||
bgra[0] = B;
|
||||
bgra[1] = G;
|
||||
bgra[2] = R;
|
||||
bgra[3] = A;
|
||||
}
|
||||
|
||||
TGAColor(unsigned char v) : bytespp(1)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) bgra[i] = 0;
|
||||
bgra[0] = v;
|
||||
}
|
||||
|
||||
TGAColor(const unsigned char *p, unsigned char bpp) : bytespp(bpp)
|
||||
{
|
||||
for (int i = 0; i < (int)bpp; i++)
|
||||
{
|
||||
bgra[i] = p[i];
|
||||
}
|
||||
for (int i = bpp; i < 4; i++)
|
||||
{
|
||||
bgra[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char &operator[](const int i) { return bgra[i]; }
|
||||
|
||||
TGAColor operator*(float intensity) const
|
||||
{
|
||||
TGAColor res = *this;
|
||||
intensity = (intensity > 1.f ? 1.f : (intensity < 0.f ? 0.f : intensity));
|
||||
for (int i = 0; i < 4; i++) res.bgra[i] = bgra[i] * intensity;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
class TGAImage
|
||||
{
|
||||
protected:
|
||||
unsigned char *data;
|
||||
int width;
|
||||
int height;
|
||||
int bytespp;
|
||||
|
||||
bool load_rle_data(std::ifstream &in);
|
||||
bool unload_rle_data(std::ofstream &out) const;
|
||||
|
||||
public:
|
||||
enum Format
|
||||
{
|
||||
GRAYSCALE = 1,
|
||||
RGB = 3,
|
||||
RGBA = 4
|
||||
};
|
||||
|
||||
TGAImage();
|
||||
TGAImage(int w, int h, int bpp);
|
||||
TGAImage(const TGAImage &img);
|
||||
bool read_tga_file(const char *filename);
|
||||
bool write_tga_file(const char *filename, bool rle = true) const;
|
||||
bool flip_horizontally();
|
||||
bool flip_vertically();
|
||||
bool scale(int w, int h);
|
||||
TGAColor get(int x, int y) const;
|
||||
|
||||
bool set(int x, int y, TGAColor &c);
|
||||
bool set(int x, int y, const TGAColor &c);
|
||||
~TGAImage();
|
||||
TGAImage &operator=(const TGAImage &img);
|
||||
int get_width();
|
||||
int get_height();
|
||||
int get_bytespp();
|
||||
unsigned char *buffer();
|
||||
void clear();
|
||||
};
|
||||
|
||||
#endif //__IMAGE_H__
|
||||
Loading…
Add table
Add a link
Reference in a new issue