mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-15 22:20:12 +00:00
ae8e83988b
Add inverse dynamics / mass matrix code from DeepMimic, thanks to Xue Bin (Jason) Peng Add example how to use stable PD control for humanoid with spherical joints (see humanoidMotionCapture.py) Fix related to TinyRenderer object transforms not updating when using collision filtering
1188 lines
36 KiB
C++
1188 lines
36 KiB
C++
#ifndef NO_OPENGL3
|
|
|
|
#include "SimpleOpenGL3App.h"
|
|
#include "ShapeData.h"
|
|
|
|
#ifdef BT_USE_EGL
|
|
#include "EGLOpenGLWindow.h"
|
|
#else
|
|
#endif //BT_USE_EGL
|
|
|
|
#ifdef B3_USE_GLFW
|
|
#include "GLFWOpenGLWindow.h"
|
|
#else
|
|
#ifdef __APPLE__
|
|
#include "MacOpenGLWindow.h"
|
|
#else
|
|
|
|
#ifdef _WIN32
|
|
#include "Win32OpenGLWindow.h"
|
|
#else
|
|
//let's cross the fingers it is Linux/X11
|
|
#include "X11OpenGLWindow.h"
|
|
#define BT_USE_X11 // for runtime backend selection, move to build?
|
|
#endif //_WIN32
|
|
#endif //__APPLE__
|
|
#endif //B3_USE_GLFW
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "GLPrimitiveRenderer.h"
|
|
#include "GLInstancingRenderer.h"
|
|
|
|
#include "Bullet3Common/b3Vector3.h"
|
|
#include "Bullet3Common/b3Logging.h"
|
|
|
|
#include "fontstash.h"
|
|
#include "TwFonts.h"
|
|
#include "opengl_fontstashcallbacks.h"
|
|
#include <assert.h>
|
|
#include "GLRenderToTexture.h"
|
|
#include "Bullet3Common/b3Quaternion.h"
|
|
#include <string.h> //memset
|
|
#ifdef _WIN32
|
|
#define popen _popen
|
|
#define pclose _pclose
|
|
#endif // _WIN32
|
|
|
|
struct SimpleInternalData
|
|
{
|
|
GLuint m_fontTextureId;
|
|
GLuint m_largeFontTextureId;
|
|
struct sth_stash* m_fontStash;
|
|
struct sth_stash* m_fontStash2;
|
|
|
|
RenderCallbacks* m_renderCallbacks;
|
|
RenderCallbacks* m_renderCallbacks2;
|
|
|
|
int m_droidRegular;
|
|
int m_droidRegular2;
|
|
int m_textureId;
|
|
|
|
const char* m_frameDumpPngFileName;
|
|
FILE* m_ffmpegFile;
|
|
GLRenderToTexture* m_renderTexture;
|
|
void* m_userPointer;
|
|
int m_upAxis; //y=1 or z=2 is supported
|
|
int m_customViewPortWidth;
|
|
int m_customViewPortHeight;
|
|
SimpleInternalData()
|
|
: m_fontTextureId(0),
|
|
m_largeFontTextureId(0),
|
|
m_fontStash(0),
|
|
m_fontStash2(0),
|
|
m_renderCallbacks(0),
|
|
m_renderCallbacks2(0),
|
|
m_droidRegular(0),
|
|
m_droidRegular2(0),
|
|
m_textureId(-1),
|
|
m_frameDumpPngFileName(0),
|
|
m_ffmpegFile(0),
|
|
m_renderTexture(0),
|
|
m_userPointer(0),
|
|
m_upAxis(1),
|
|
m_customViewPortWidth(-1),
|
|
m_customViewPortHeight(-1)
|
|
{
|
|
}
|
|
};
|
|
|
|
static SimpleOpenGL3App* gApp = 0;
|
|
|
|
static void SimpleResizeCallback(float widthf, float heightf)
|
|
{
|
|
int width = (int)widthf;
|
|
int height = (int)heightf;
|
|
if (gApp && gApp->m_instancingRenderer)
|
|
gApp->m_instancingRenderer->resize(width, height);
|
|
|
|
if (gApp && gApp->m_primRenderer)
|
|
gApp->m_primRenderer->setScreenSize(width, height);
|
|
}
|
|
|
|
static void SimpleKeyboardCallback(int key, int state)
|
|
{
|
|
if (key == B3G_ESCAPE && gApp && gApp->m_window)
|
|
{
|
|
gApp->m_window->setRequestExit();
|
|
}
|
|
else
|
|
{
|
|
//gApp->defaultKeyboardCallback(key,state);
|
|
}
|
|
}
|
|
|
|
void SimpleMouseButtonCallback(int button, int state, float x, float y)
|
|
{
|
|
gApp->defaultMouseButtonCallback(button, state, x, y);
|
|
}
|
|
void SimpleMouseMoveCallback(float x, float y)
|
|
{
|
|
gApp->defaultMouseMoveCallback(x, y);
|
|
}
|
|
|
|
void SimpleWheelCallback(float deltax, float deltay)
|
|
{
|
|
gApp->defaultWheelCallback(deltax, deltay);
|
|
}
|
|
|
|
static GLuint BindFont(const CTexFont* _Font)
|
|
{
|
|
GLuint TexID = 0;
|
|
glGenTextures(1, &TexID);
|
|
glBindTexture(GL_TEXTURE_2D, TexID);
|
|
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
|
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
|
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, _Font->m_TexWidth, _Font->m_TexHeight, 0, GL_RED, GL_UNSIGNED_BYTE, _Font->m_TexBytes);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
return TexID;
|
|
}
|
|
|
|
//static unsigned int s_indexData[INDEX_COUNT];
|
|
//static GLuint s_indexArrayObject, s_indexBuffer;
|
|
//static GLuint s_vertexArrayObject,s_vertexBuffer;
|
|
|
|
extern unsigned char OpenSansData[];
|
|
|
|
struct MyRenderCallbacks : public RenderCallbacks
|
|
{
|
|
GLInstancingRenderer* m_instancingRenderer;
|
|
|
|
b3AlignedObjectArray<unsigned char> m_rgbaTexture;
|
|
float m_color[4];
|
|
float m_worldPosition[3];
|
|
float m_worldOrientation[4];
|
|
|
|
int m_textureIndex;
|
|
|
|
MyRenderCallbacks(GLInstancingRenderer* instancingRenderer)
|
|
: m_instancingRenderer(instancingRenderer),
|
|
m_textureIndex(-1)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
m_color[i] = 1;
|
|
m_worldOrientation[i] = 0;
|
|
}
|
|
m_worldPosition[0] = 0;
|
|
m_worldPosition[1] = 0;
|
|
m_worldPosition[2] = 0;
|
|
|
|
m_worldOrientation[0] = 0;
|
|
m_worldOrientation[1] = 0;
|
|
m_worldOrientation[2] = 0;
|
|
m_worldOrientation[3] = 1;
|
|
}
|
|
virtual ~MyRenderCallbacks()
|
|
{
|
|
m_rgbaTexture.clear();
|
|
}
|
|
|
|
virtual void setWorldPosition(float pos[3])
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
m_worldPosition[i] = pos[i];
|
|
}
|
|
}
|
|
|
|
virtual void setWorldOrientation(float orn[4])
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
m_worldOrientation[i] = orn[i];
|
|
}
|
|
}
|
|
|
|
virtual void setColorRGBA(float color[4])
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
m_color[i] = color[i];
|
|
}
|
|
}
|
|
virtual void updateTexture(sth_texture* texture, sth_glyph* glyph, int textureWidth, int textureHeight)
|
|
{
|
|
if (glyph)
|
|
{
|
|
m_rgbaTexture.resize(textureWidth * textureHeight * 3);
|
|
for (int i = 0; i < textureWidth * textureHeight; i++)
|
|
{
|
|
m_rgbaTexture[i * 3 + 0] = texture->m_texels[i];
|
|
m_rgbaTexture[i * 3 + 1] = texture->m_texels[i];
|
|
m_rgbaTexture[i * 3 + 2] = texture->m_texels[i];
|
|
}
|
|
bool flipPixelsY = false;
|
|
m_instancingRenderer->updateTexture(m_textureIndex, &m_rgbaTexture[0], flipPixelsY);
|
|
}
|
|
else
|
|
{
|
|
if (textureWidth && textureHeight)
|
|
{
|
|
texture->m_texels = (unsigned char*)malloc(textureWidth * textureHeight);
|
|
memset(texture->m_texels, 0, textureWidth * textureHeight);
|
|
if (m_textureIndex < 0)
|
|
{
|
|
m_rgbaTexture.resize(textureWidth * textureHeight * 3);
|
|
bool flipPixelsY = false;
|
|
m_textureIndex = m_instancingRenderer->registerTexture(&m_rgbaTexture[0], textureWidth, textureHeight, flipPixelsY);
|
|
|
|
int strideInBytes = 9 * sizeof(float);
|
|
int numVertices = sizeof(cube_vertices_textured) / strideInBytes;
|
|
int numIndices = sizeof(cube_indices) / sizeof(int);
|
|
|
|
float halfExtentsX = 1;
|
|
float halfExtentsY = 1;
|
|
float halfExtentsZ = 1;
|
|
float textureScaling = 4;
|
|
|
|
b3AlignedObjectArray<GfxVertexFormat1> verts;
|
|
verts.resize(numVertices);
|
|
for (int i = 0; i < numVertices; i++)
|
|
{
|
|
verts[i].x = halfExtentsX * cube_vertices_textured[i * 9];
|
|
verts[i].y = halfExtentsY * cube_vertices_textured[i * 9 + 1];
|
|
verts[i].z = halfExtentsZ * cube_vertices_textured[i * 9 + 2];
|
|
verts[i].w = cube_vertices_textured[i * 9 + 3];
|
|
verts[i].nx = cube_vertices_textured[i * 9 + 4];
|
|
verts[i].ny = cube_vertices_textured[i * 9 + 5];
|
|
verts[i].nz = cube_vertices_textured[i * 9 + 6];
|
|
verts[i].u = cube_vertices_textured[i * 9 + 7] * textureScaling;
|
|
verts[i].v = cube_vertices_textured[i * 9 + 8] * textureScaling;
|
|
}
|
|
|
|
int shapeId = m_instancingRenderer->registerShape(&verts[0].x, numVertices, cube_indices, numIndices, B3_GL_TRIANGLES, m_textureIndex);
|
|
b3Vector3 pos = b3MakeVector3(0, 0, 0);
|
|
b3Quaternion orn(0, 0, 0, 1);
|
|
b3Vector4 color = b3MakeVector4(1, 1, 1, 1);
|
|
b3Vector3 scaling = b3MakeVector3(.1, .1, .1);
|
|
//m_instancingRenderer->registerGraphicsInstance(shapeId, pos, orn, color, scaling);
|
|
m_instancingRenderer->writeTransforms();
|
|
}
|
|
else
|
|
{
|
|
b3Assert(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete texture->m_texels;
|
|
texture->m_texels = 0;
|
|
//there is no m_instancingRenderer->freeTexture (yet), all textures are released at reset/deletion of the renderer
|
|
}
|
|
}
|
|
}
|
|
virtual void render(sth_texture* texture)
|
|
{
|
|
int index = 0;
|
|
|
|
float width = 1;
|
|
b3AlignedObjectArray<unsigned int> indices;
|
|
indices.resize(texture->nverts);
|
|
for (int i = 0; i < indices.size(); i++)
|
|
{
|
|
indices[i] = i;
|
|
}
|
|
|
|
m_instancingRenderer->drawTexturedTriangleMesh(m_worldPosition, m_worldOrientation, &texture->newverts[0].position.p[0], texture->nverts, &indices[0], indices.size(), m_color, m_textureIndex);
|
|
}
|
|
};
|
|
|
|
static void printGLString(const char* name, GLenum s)
|
|
{
|
|
const char* v = (const char*)glGetString(s);
|
|
printf("%s = %s\n", name, v);
|
|
}
|
|
|
|
bool sOpenGLVerbose = true;
|
|
|
|
SimpleOpenGL3App::SimpleOpenGL3App(const char* title, int width, int height, bool allowRetina, int windowType, int renderDevice, int maxNumObjectCapacity, int maxShapeCapacityInBytes)
|
|
{
|
|
gApp = this;
|
|
|
|
m_data = new SimpleInternalData;
|
|
|
|
if (windowType == 0)
|
|
{
|
|
m_window = new b3gDefaultOpenGLWindow();
|
|
}
|
|
else if (windowType == 1)
|
|
{
|
|
#ifdef BT_USE_X11
|
|
m_window = new X11OpenGLWindow();
|
|
#else
|
|
b3Warning("X11 requires Linux. Loading default window instead. \n");
|
|
m_window = new b3gDefaultOpenGLWindow();
|
|
#endif
|
|
}
|
|
else if (windowType == 2)
|
|
{
|
|
#ifdef BT_USE_EGL
|
|
m_window = new EGLOpenGLWindow();
|
|
#else
|
|
b3Warning("EGL window requires compilation with BT_USE_EGL.\n");
|
|
b3Warning("Loading default window instead. \n");
|
|
m_window = new b3gDefaultOpenGLWindow();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
b3Warning("Unknown window type %d must be (0=default, 1=X11, 2=EGL).\n", windowType);
|
|
b3Warning("Loading default window instead. \n");
|
|
m_window = new b3gDefaultOpenGLWindow();
|
|
}
|
|
|
|
m_window->setAllowRetina(allowRetina);
|
|
|
|
b3gWindowConstructionInfo ci;
|
|
ci.m_title = title;
|
|
ci.m_width = width;
|
|
ci.m_height = height;
|
|
ci.m_renderDevice = renderDevice;
|
|
m_window->createWindow(ci);
|
|
|
|
m_window->setWindowTitle(title);
|
|
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
|
|
{
|
|
printGLString("Version", GL_VERSION);
|
|
printGLString("Vendor", GL_VENDOR);
|
|
printGLString("Renderer", GL_RENDERER);
|
|
}
|
|
|
|
glClearColor(m_backgroundColorRGB[0],
|
|
m_backgroundColorRGB[1],
|
|
m_backgroundColorRGB[2],
|
|
1.f);
|
|
|
|
m_window->startRendering();
|
|
width = m_window->getWidth();
|
|
height = m_window->getHeight();
|
|
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
|
|
//gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
|
|
|
|
#ifdef USE_GLEW
|
|
#ifndef __APPLE__
|
|
#ifndef _WIN32
|
|
#ifndef B3_USE_GLFW
|
|
//some Linux implementations need the 'glewExperimental' to be true
|
|
glewExperimental = GL_TRUE;
|
|
#endif //B3_USE_GLFW
|
|
#endif //_WIN32
|
|
|
|
#ifndef B3_USE_GLFW
|
|
if (glewInit() != GLEW_OK)
|
|
exit(1); // or handle the error in a nicer way
|
|
if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API.
|
|
exit(1); // or handle the error in a nicer way
|
|
#endif //B3_USE_GLFW
|
|
#endif //__APPLE__
|
|
#endif //USE_GLEW
|
|
|
|
glGetError(); //don't remove this call, it is needed for Ubuntu
|
|
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
|
|
m_parameterInterface = 0;
|
|
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
|
|
m_instancingRenderer = new GLInstancingRenderer(maxNumObjectCapacity, maxShapeCapacityInBytes);
|
|
|
|
m_primRenderer = new GLPrimitiveRenderer(width, height);
|
|
|
|
m_renderer = m_instancingRenderer;
|
|
m_window->setResizeCallback(SimpleResizeCallback);
|
|
|
|
m_instancingRenderer->init();
|
|
m_instancingRenderer->resize(width, height);
|
|
m_primRenderer->setScreenSize(width, height);
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
|
|
m_instancingRenderer->InitShaders();
|
|
|
|
m_window->setMouseMoveCallback(SimpleMouseMoveCallback);
|
|
m_window->setMouseButtonCallback(SimpleMouseButtonCallback);
|
|
m_window->setKeyboardCallback(SimpleKeyboardCallback);
|
|
m_window->setWheelCallback(SimpleWheelCallback);
|
|
|
|
TwGenerateDefaultFonts();
|
|
m_data->m_fontTextureId = BindFont(g_DefaultNormalFont);
|
|
m_data->m_largeFontTextureId = BindFont(g_DefaultLargeFont);
|
|
|
|
{
|
|
m_data->m_renderCallbacks = new OpenGL2RenderCallbacks(m_primRenderer);
|
|
m_data->m_renderCallbacks2 = new MyRenderCallbacks(m_instancingRenderer);
|
|
m_data->m_fontStash2 = sth_create(512, 512, m_data->m_renderCallbacks2);
|
|
m_data->m_fontStash = sth_create(512, 512, m_data->m_renderCallbacks); //256,256);//,1024);//512,512);
|
|
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
|
|
if (!m_data->m_fontStash)
|
|
{
|
|
b3Warning("Could not create stash");
|
|
//fprintf(stderr, "Could not create stash.\n");
|
|
}
|
|
|
|
if (!m_data->m_fontStash2)
|
|
{
|
|
b3Warning("Could not create fontStash2");
|
|
}
|
|
|
|
unsigned char* data2 = OpenSansData;
|
|
unsigned char* data = (unsigned char*)data2;
|
|
if (!(m_data->m_droidRegular = sth_add_font_from_memory(m_data->m_fontStash, data)))
|
|
{
|
|
b3Warning("error!\n");
|
|
}
|
|
if (!(m_data->m_droidRegular2 = sth_add_font_from_memory(m_data->m_fontStash2, data)))
|
|
{
|
|
b3Warning("error!\n");
|
|
}
|
|
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
}
|
|
}
|
|
|
|
struct sth_stash* SimpleOpenGL3App::getFontStash()
|
|
{
|
|
return m_data->m_fontStash;
|
|
}
|
|
|
|
void SimpleOpenGL3App::drawText3D(const char* txt, float position[3], float orientation[4], float color[4], float size, int optionFlag)
|
|
{
|
|
B3_PROFILE("SimpleOpenGL3App::drawText3D");
|
|
float viewMat[16];
|
|
float projMat[16];
|
|
CommonCameraInterface* cam = m_instancingRenderer->getActiveCamera();
|
|
|
|
cam->getCameraViewMatrix(viewMat);
|
|
cam->getCameraProjectionMatrix(projMat);
|
|
|
|
float camPos[4];
|
|
cam->getCameraPosition(camPos);
|
|
//b3Vector3 cp= b3MakeVector3(camPos[0],camPos[2],camPos[1]);
|
|
//b3Vector3 p = b3MakeVector3(worldPosX,worldPosY,worldPosZ);
|
|
//float dist = (cp-p).length();
|
|
//float dv = 0;//dist/1000.f;
|
|
//
|
|
//printf("str = %s\n",unicodeText);
|
|
|
|
float dx = 0;
|
|
|
|
//int measureOnly=0;
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
int viewport[4] = {0, 0, m_instancingRenderer->getScreenWidth(), m_instancingRenderer->getScreenHeight()};
|
|
|
|
float posX = position[0];
|
|
float posY = position[1];
|
|
float posZ = position[2];
|
|
float winx, winy, winz;
|
|
|
|
if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
|
|
{
|
|
if (!projectWorldCoordToScreen(position[0], position[1], position[2], viewMat, projMat, viewport, &winx, &winy, &winz))
|
|
{
|
|
return;
|
|
}
|
|
posX = winx;
|
|
posY = m_instancingRenderer->getScreenHeight() / 2 + (m_instancingRenderer->getScreenHeight() / 2) - winy;
|
|
posZ = 0.f;
|
|
}
|
|
|
|
if (optionFlag & CommonGraphicsApp::eDrawText3D_TrueType)
|
|
{
|
|
bool measureOnly = false;
|
|
|
|
float fontSize = 64; //512;//128;
|
|
|
|
if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
|
|
{
|
|
sth_draw_text(m_data->m_fontStash,
|
|
m_data->m_droidRegular, fontSize, posX, posY,
|
|
txt, &dx, this->m_instancingRenderer->getScreenWidth(), this->m_instancingRenderer->getScreenHeight(), measureOnly, m_window->getRetinaScale(), color);
|
|
sth_end_draw(m_data->m_fontStash);
|
|
sth_flush_draw(m_data->m_fontStash);
|
|
}
|
|
else
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
m_data->m_renderCallbacks2->setColorRGBA(color);
|
|
|
|
m_data->m_renderCallbacks2->setWorldPosition(position);
|
|
m_data->m_renderCallbacks2->setWorldOrientation(orientation);
|
|
|
|
sth_draw_text3D(m_data->m_fontStash2,
|
|
m_data->m_droidRegular2, fontSize, 0, 0, 0,
|
|
txt, &dx, size, color, 0);
|
|
sth_end_draw(m_data->m_fontStash2);
|
|
sth_flush_draw(m_data->m_fontStash2);
|
|
glDisable(GL_BLEND);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//float width = 0.f;
|
|
int pos = 0;
|
|
//float color[]={0.2f,0.2,0.2f,1.f};
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, m_data->m_largeFontTextureId);
|
|
|
|
//float width = r.x;
|
|
//float extraSpacing = 0.;
|
|
|
|
float startX = posX;
|
|
float startY = posY + g_DefaultLargeFont->m_CharHeight * size;
|
|
float z = position[2]; //2.f*winz-1.f;//*(far
|
|
|
|
if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
|
|
{
|
|
posX = winx;
|
|
posY = m_instancingRenderer->getScreenHeight() / 2 + (m_instancingRenderer->getScreenHeight() / 2) - winy;
|
|
z = 2.f * winz - 1.f;
|
|
startY = posY - g_DefaultLargeFont->m_CharHeight * size;
|
|
}
|
|
|
|
while (txt[pos])
|
|
{
|
|
int c = txt[pos];
|
|
//r.h = g_DefaultNormalFont->m_CharHeight;
|
|
//r.w = g_DefaultNormalFont->m_CharWidth[c]+extraSpacing;
|
|
float endX = startX + g_DefaultLargeFont->m_CharWidth[c] * size;
|
|
if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
|
|
{
|
|
endX = startX + g_DefaultLargeFont->m_CharWidth[c] * size;
|
|
}
|
|
float endY = posY;
|
|
|
|
//float currentColor[]={1.f,1.,0.2f,1.f};
|
|
|
|
// m_primRenderer->drawTexturedRect(startX, startY, endX, endY, currentColor,g_DefaultLargeFont->m_CharU0[c],g_DefaultLargeFont->m_CharV0[c],g_DefaultLargeFont->m_CharU1[c],g_DefaultLargeFont->m_CharV1[c]);
|
|
float u0 = g_DefaultLargeFont->m_CharU0[c];
|
|
float u1 = g_DefaultLargeFont->m_CharU1[c];
|
|
float v0 = g_DefaultLargeFont->m_CharV0[c];
|
|
float v1 = g_DefaultLargeFont->m_CharV1[c];
|
|
//float color[4] = {currentColor[0],currentColor[1],currentColor[2],currentColor[3]};
|
|
float x0 = startX;
|
|
float x1 = endX;
|
|
float y0 = startY;
|
|
float y1 = endY;
|
|
int screenWidth = m_instancingRenderer->getScreenWidth();
|
|
int screenHeight = m_instancingRenderer->getScreenHeight();
|
|
|
|
float identity[16] = {1, 0, 0, 0,
|
|
0, 1, 0, 0,
|
|
0, 0, 1, 0,
|
|
0, 0, 0, 1};
|
|
if (optionFlag & CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera)
|
|
{
|
|
PrimVertex vertexData[4] = {
|
|
PrimVertex(PrimVec4(-1.f + 2.f * x0 / float(screenWidth), 1.f - 2.f * y0 / float(screenHeight), z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u0, v0)),
|
|
PrimVertex(PrimVec4(-1.f + 2.f * x0 / float(screenWidth), 1.f - 2.f * y1 / float(screenHeight), z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u0, v1)),
|
|
PrimVertex(PrimVec4(-1.f + 2.f * x1 / float(screenWidth), 1.f - 2.f * y1 / float(screenHeight), z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u1, v1)),
|
|
PrimVertex(PrimVec4(-1.f + 2.f * x1 / float(screenWidth), 1.f - 2.f * y0 / float(screenHeight), z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u1, v0))};
|
|
m_primRenderer->drawTexturedRect3D(vertexData[0], vertexData[1], vertexData[2], vertexData[3], identity, identity, false);
|
|
}
|
|
else
|
|
{
|
|
PrimVertex vertexData[4] = {
|
|
PrimVertex(PrimVec4(x0, y0, z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u0, v0)),
|
|
PrimVertex(PrimVec4(x0, y1, z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u0, v1)),
|
|
PrimVertex(PrimVec4(x1, y1, z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u1, v1)),
|
|
PrimVertex(PrimVec4(x1, y0, z, 1.f), PrimVec4(color[0], color[1], color[2], color[3]), PrimVec2(u1, v0))};
|
|
|
|
m_primRenderer->drawTexturedRect3D(vertexData[0], vertexData[1], vertexData[2], vertexData[3], viewMat, projMat, false);
|
|
}
|
|
//DrawTexturedRect(0,r,g_DefaultNormalFont->m_CharU0[c],g_DefaultNormalFont->m_CharV0[c],g_DefaultNormalFont->m_CharU1[c],g_DefaultNormalFont->m_CharV1[c]);
|
|
// DrawFilledRect(r);
|
|
|
|
startX = endX;
|
|
//startY = endY;
|
|
|
|
pos++;
|
|
}
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
void SimpleOpenGL3App::drawText3D(const char* txt, float worldPosX, float worldPosY, float worldPosZ, float size1)
|
|
{
|
|
float position[3] = {worldPosX, worldPosY, worldPosZ};
|
|
float orientation[4] = {0, 0, 0, 1};
|
|
float color[4] = {0, 0, 0, 1};
|
|
int optionFlags = CommonGraphicsApp::eDrawText3D_OrtogonalFaceCamera;
|
|
drawText3D(txt, position, orientation, color, size1, optionFlags);
|
|
}
|
|
|
|
void SimpleOpenGL3App::drawText(const char* txt, int posXi, int posYi, float size, float colorRGBA[4])
|
|
{
|
|
float posX = (float)posXi;
|
|
float posY = (float)posYi;
|
|
|
|
//
|
|
//printf("str = %s\n",unicodeText);
|
|
|
|
float dx = 0;
|
|
|
|
//int measureOnly=0;
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
if (1) //m_useTrueTypeFont)
|
|
{
|
|
bool measureOnly = false;
|
|
|
|
float fontSize = 64 * size; //512;//128;
|
|
sth_draw_text(m_data->m_fontStash,
|
|
m_data->m_droidRegular, fontSize, posX, posY,
|
|
txt, &dx, this->m_instancingRenderer->getScreenWidth(),
|
|
this->m_instancingRenderer->getScreenHeight(),
|
|
measureOnly,
|
|
m_window->getRetinaScale(), colorRGBA);
|
|
|
|
sth_end_draw(m_data->m_fontStash);
|
|
sth_flush_draw(m_data->m_fontStash);
|
|
}
|
|
else
|
|
{
|
|
//float width = 0.f;
|
|
int pos = 0;
|
|
//float color[]={0.2f,0.2,0.2f,1.f};
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, m_data->m_largeFontTextureId);
|
|
|
|
//float width = r.x;
|
|
//float extraSpacing = 0.;
|
|
|
|
float startX = posX;
|
|
float startY = posY;
|
|
|
|
while (txt[pos])
|
|
{
|
|
int c = txt[pos];
|
|
//r.h = g_DefaultNormalFont->m_CharHeight;
|
|
//r.w = g_DefaultNormalFont->m_CharWidth[c]+extraSpacing;
|
|
float endX = startX + g_DefaultLargeFont->m_CharWidth[c];
|
|
float endY = startY + g_DefaultLargeFont->m_CharHeight;
|
|
|
|
float currentColor[] = {0.2f, 0.2, 0.2f, 1.f};
|
|
|
|
m_primRenderer->drawTexturedRect(startX, startY, endX, endY, currentColor, g_DefaultLargeFont->m_CharU0[c], g_DefaultLargeFont->m_CharV0[c], g_DefaultLargeFont->m_CharU1[c], g_DefaultLargeFont->m_CharV1[c]);
|
|
|
|
//DrawTexturedRect(0,r,g_DefaultNormalFont->m_CharU0[c],g_DefaultNormalFont->m_CharV0[c],g_DefaultNormalFont->m_CharU1[c],g_DefaultNormalFont->m_CharV1[c]);
|
|
// DrawFilledRect(r);
|
|
|
|
startX = endX;
|
|
//startY = endY;
|
|
|
|
pos++;
|
|
}
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
void SimpleOpenGL3App::drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0, float v0, float u1, float v1, int useRGBA)
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
m_primRenderer->drawTexturedRect(x0, y0, x1, y1, color, u0, v0, u1, v1, useRGBA);
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
int SimpleOpenGL3App::registerCubeShape(float halfExtentsX, float halfExtentsY, float halfExtentsZ, int textureIndex, float textureScaling)
|
|
{
|
|
int strideInBytes = 9 * sizeof(float);
|
|
int numVertices = sizeof(cube_vertices_textured) / strideInBytes;
|
|
int numIndices = sizeof(cube_indices) / sizeof(int);
|
|
|
|
b3AlignedObjectArray<GfxVertexFormat1> verts;
|
|
verts.resize(numVertices);
|
|
for (int i = 0; i < numVertices; i++)
|
|
{
|
|
verts[i].x = halfExtentsX * cube_vertices_textured[i * 9];
|
|
verts[i].y = halfExtentsY * cube_vertices_textured[i * 9 + 1];
|
|
verts[i].z = halfExtentsZ * cube_vertices_textured[i * 9 + 2];
|
|
verts[i].w = cube_vertices_textured[i * 9 + 3];
|
|
verts[i].nx = cube_vertices_textured[i * 9 + 4];
|
|
verts[i].ny = cube_vertices_textured[i * 9 + 5];
|
|
verts[i].nz = cube_vertices_textured[i * 9 + 6];
|
|
verts[i].u = cube_vertices_textured[i * 9 + 7] * textureScaling;
|
|
verts[i].v = cube_vertices_textured[i * 9 + 8] * textureScaling;
|
|
}
|
|
|
|
int shapeId = m_instancingRenderer->registerShape(&verts[0].x, numVertices, cube_indices, numIndices, B3_GL_TRIANGLES, textureIndex);
|
|
return shapeId;
|
|
}
|
|
|
|
void SimpleOpenGL3App::registerGrid(int cells_x, int cells_z, float color0[4], float color1[4])
|
|
{
|
|
b3Vector3 cubeExtents = b3MakeVector3(0.5, 0.5, 0.5);
|
|
double halfHeight = 0.1;
|
|
cubeExtents[m_data->m_upAxis] = halfHeight;
|
|
int cubeId = registerCubeShape(cubeExtents[0], cubeExtents[1], cubeExtents[2]);
|
|
b3Quaternion orn(0, 0, 0, 1);
|
|
b3Vector3 center = b3MakeVector3(0, 0, 0, 1);
|
|
b3Vector3 scaling = b3MakeVector3(1, 1, 1, 1);
|
|
|
|
for (int i = 0; i < cells_x; i++)
|
|
{
|
|
for (int j = 0; j < cells_z; j++)
|
|
{
|
|
float* color = 0;
|
|
if ((i + j) % 2 == 0)
|
|
{
|
|
color = (float*)color0;
|
|
}
|
|
else
|
|
{
|
|
color = (float*)color1;
|
|
}
|
|
if (this->m_data->m_upAxis == 1)
|
|
{
|
|
center = b3MakeVector3((i + 0.5f) - cells_x * 0.5f, -halfHeight, (j + 0.5f) - cells_z * 0.5f);
|
|
}
|
|
else
|
|
{
|
|
center = b3MakeVector3((i + 0.5f) - cells_x * 0.5f, (j + 0.5f) - cells_z * 0.5f, -halfHeight);
|
|
}
|
|
m_instancingRenderer->registerGraphicsInstance(cubeId, center, orn, color, scaling);
|
|
}
|
|
}
|
|
}
|
|
|
|
int SimpleOpenGL3App::registerGraphicsUnitSphereShape(EnumSphereLevelOfDetail lod, int textureId)
|
|
{
|
|
|
|
int red = 255;
|
|
int green = 0;
|
|
int blue = 128;
|
|
if (textureId<0)
|
|
{
|
|
if (m_data->m_textureId < 0)
|
|
{
|
|
int texWidth = 1024;
|
|
int texHeight = 1024;
|
|
b3AlignedObjectArray<unsigned char> texels;
|
|
texels.resize(texWidth * texHeight * 3);
|
|
for (int i = 0; i < texWidth * texHeight * 3; i++)
|
|
texels[i] = 255;
|
|
|
|
for (int i = 0; i < texWidth; i++)
|
|
{
|
|
for (int j = 0; j < texHeight; j++)
|
|
{
|
|
int a = i < texWidth / 2 ? 1 : 0;
|
|
int b = j < texWidth / 2 ? 1 : 0;
|
|
|
|
if (a == b)
|
|
{
|
|
texels[(i + j * texWidth) * 3 + 0] = red;
|
|
texels[(i + j * texWidth) * 3 + 1] = green;
|
|
texels[(i + j * texWidth) * 3 + 2] = blue;
|
|
// texels[(i+j*texWidth)*4+3] = 255;
|
|
}
|
|
/*else
|
|
{
|
|
texels[i*3+0+j*texWidth] = 255;
|
|
texels[i*3+1+j*texWidth] = 255;
|
|
texels[i*3+2+j*texWidth] = 255;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
m_data->m_textureId = m_instancingRenderer->registerTexture(&texels[0], texWidth, texHeight);
|
|
|
|
}
|
|
textureId = m_data->m_textureId;
|
|
}
|
|
|
|
int strideInBytes = 9 * sizeof(float);
|
|
|
|
int graphicsShapeIndex = -1;
|
|
|
|
switch (lod)
|
|
{
|
|
case SPHERE_LOD_POINT_SPRITE:
|
|
{
|
|
int numVertices = sizeof(point_sphere_vertices) / strideInBytes;
|
|
int numIndices = sizeof(point_sphere_indices) / sizeof(int);
|
|
graphicsShapeIndex = m_instancingRenderer->registerShape(&point_sphere_vertices[0], numVertices, point_sphere_indices, numIndices, B3_GL_POINTS, textureId);
|
|
break;
|
|
}
|
|
|
|
case SPHERE_LOD_LOW:
|
|
{
|
|
int numVertices = sizeof(low_sphere_vertices) / strideInBytes;
|
|
int numIndices = sizeof(low_sphere_indices) / sizeof(int);
|
|
graphicsShapeIndex = m_instancingRenderer->registerShape(&low_sphere_vertices[0], numVertices, low_sphere_indices, numIndices, B3_GL_TRIANGLES, textureId);
|
|
break;
|
|
}
|
|
case SPHERE_LOD_MEDIUM:
|
|
{
|
|
int numVertices = sizeof(textured_detailed_sphere_vertices) / strideInBytes;
|
|
int numIndices = sizeof(textured_detailed_sphere_indices) / sizeof(int);
|
|
graphicsShapeIndex = m_instancingRenderer->registerShape(&textured_detailed_sphere_vertices[0], numVertices, textured_detailed_sphere_indices, numIndices, B3_GL_TRIANGLES, textureId);
|
|
break;
|
|
}
|
|
case SPHERE_LOD_HIGH:
|
|
default:
|
|
{
|
|
int numVertices = sizeof(textured_detailed_sphere_vertices) / strideInBytes;
|
|
int numIndices = sizeof(textured_detailed_sphere_indices) / sizeof(int);
|
|
graphicsShapeIndex = m_instancingRenderer->registerShape(&textured_detailed_sphere_vertices[0], numVertices, textured_detailed_sphere_indices, numIndices, B3_GL_TRIANGLES, textureId);
|
|
break;
|
|
}
|
|
};
|
|
return graphicsShapeIndex;
|
|
}
|
|
|
|
void SimpleOpenGL3App::drawGrid(DrawGridData data)
|
|
{
|
|
int gridSize = data.gridSize;
|
|
float upOffset = data.upOffset;
|
|
int upAxis = data.upAxis;
|
|
float gridColor[4];
|
|
gridColor[0] = data.gridColor[0];
|
|
gridColor[1] = data.gridColor[1];
|
|
gridColor[2] = data.gridColor[2];
|
|
gridColor[3] = data.gridColor[3];
|
|
|
|
int sideAxis = -1;
|
|
int forwardAxis = -1;
|
|
|
|
switch (upAxis)
|
|
{
|
|
case 1:
|
|
forwardAxis = 2;
|
|
sideAxis = 0;
|
|
break;
|
|
case 2:
|
|
forwardAxis = 1;
|
|
sideAxis = 0;
|
|
break;
|
|
default:
|
|
b3Assert(0);
|
|
};
|
|
//b3Vector3 gridColor = b3MakeVector3(0.5,0.5,0.5);
|
|
|
|
b3AlignedObjectArray<unsigned int> indices;
|
|
b3AlignedObjectArray<b3Vector3> vertices;
|
|
int lineIndex = 0;
|
|
for (int i = -gridSize; i <= gridSize; i++)
|
|
{
|
|
{
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
b3Vector3 from = b3MakeVector3(0, 0, 0);
|
|
from[sideAxis] = float(i);
|
|
from[upAxis] = upOffset;
|
|
from[forwardAxis] = float(-gridSize);
|
|
b3Vector3 to = b3MakeVector3(0, 0, 0);
|
|
to[sideAxis] = float(i);
|
|
to[upAxis] = upOffset;
|
|
to[forwardAxis] = float(gridSize);
|
|
vertices.push_back(from);
|
|
indices.push_back(lineIndex++);
|
|
vertices.push_back(to);
|
|
indices.push_back(lineIndex++);
|
|
// m_instancingRenderer->drawLine(from,to,gridColor);
|
|
}
|
|
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
{
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
b3Vector3 from = b3MakeVector3(0, 0, 0);
|
|
from[sideAxis] = float(-gridSize);
|
|
from[upAxis] = upOffset;
|
|
from[forwardAxis] = float(i);
|
|
b3Vector3 to = b3MakeVector3(0, 0, 0);
|
|
to[sideAxis] = float(gridSize);
|
|
to[upAxis] = upOffset;
|
|
to[forwardAxis] = float(i);
|
|
vertices.push_back(from);
|
|
indices.push_back(lineIndex++);
|
|
vertices.push_back(to);
|
|
indices.push_back(lineIndex++);
|
|
// m_instancingRenderer->drawLine(from,to,gridColor);
|
|
}
|
|
}
|
|
|
|
m_instancingRenderer->drawLines(&vertices[0].x,
|
|
gridColor,
|
|
vertices.size(), sizeof(b3Vector3), &indices[0], indices.size(), 1);
|
|
|
|
m_instancingRenderer->drawLine(b3MakeVector3(0, 0, 0), b3MakeVector3(1, 0, 0), b3MakeVector3(1, 0, 0), 3);
|
|
m_instancingRenderer->drawLine(b3MakeVector3(0, 0, 0), b3MakeVector3(0, 1, 0), b3MakeVector3(0, 1, 0), 3);
|
|
m_instancingRenderer->drawLine(b3MakeVector3(0, 0, 0), b3MakeVector3(0, 0, 1), b3MakeVector3(0, 0, 1), 3);
|
|
|
|
// void GLInstancingRenderer::drawPoints(const float* positions, const float color[4], int numPoints, int pointStrideInBytes, float pointDrawSize)
|
|
|
|
//we don't use drawPoints because all points would have the same color
|
|
// b3Vector3 points[3] = { b3MakeVector3(1, 0, 0), b3MakeVector3(0, 1, 0), b3MakeVector3(0, 0, 1) };
|
|
// m_instancingRenderer->drawPoints(&points[0].x, b3MakeVector3(1, 0, 0), 3, sizeof(b3Vector3), 6);
|
|
|
|
m_instancingRenderer->drawPoint(b3MakeVector3(1, 0, 0), b3MakeVector3(1, 0, 0), 6);
|
|
m_instancingRenderer->drawPoint(b3MakeVector3(0, 1, 0), b3MakeVector3(0, 1, 0), 6);
|
|
m_instancingRenderer->drawPoint(b3MakeVector3(0, 0, 1), b3MakeVector3(0, 0, 1), 6);
|
|
}
|
|
|
|
void SimpleOpenGL3App::setBackgroundColor(float red, float green, float blue)
|
|
{
|
|
CommonGraphicsApp::setBackgroundColor(red, green, blue);
|
|
glClearColor(m_backgroundColorRGB[0], m_backgroundColorRGB[1], m_backgroundColorRGB[2], 1.f);
|
|
}
|
|
|
|
SimpleOpenGL3App::~SimpleOpenGL3App()
|
|
{
|
|
delete m_instancingRenderer;
|
|
delete m_primRenderer;
|
|
sth_delete(m_data->m_fontStash);
|
|
delete m_data->m_renderCallbacks;
|
|
|
|
sth_delete(m_data->m_fontStash2);
|
|
delete m_data->m_renderCallbacks2;
|
|
|
|
TwDeleteDefaultFonts();
|
|
m_window->closeWindow();
|
|
|
|
delete m_window;
|
|
delete m_data;
|
|
}
|
|
|
|
void SimpleOpenGL3App::setViewport(int width, int height)
|
|
{
|
|
m_data->m_customViewPortWidth = width;
|
|
m_data->m_customViewPortHeight = height;
|
|
if (width >= 0)
|
|
{
|
|
glViewport(0, 0, width, height);
|
|
}
|
|
else
|
|
{
|
|
glViewport(0, 0, m_window->getRetinaScale() * m_instancingRenderer->getScreenWidth(), m_window->getRetinaScale() * m_instancingRenderer->getScreenHeight());
|
|
}
|
|
}
|
|
|
|
void SimpleOpenGL3App::getScreenPixels(unsigned char* rgbaBuffer, int bufferSizeInBytes, float* depthBuffer, int depthBufferSizeInBytes)
|
|
{
|
|
int width = m_data->m_customViewPortWidth >= 0 ? m_data->m_customViewPortWidth : (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenWidth();
|
|
int height = m_data->m_customViewPortHeight >= 0 ? m_data->m_customViewPortHeight : (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenHeight();
|
|
|
|
b3Assert((width * height * 4) == bufferSizeInBytes);
|
|
if ((width * height * 4) == bufferSizeInBytes)
|
|
{
|
|
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgbaBuffer);
|
|
int glstat;
|
|
glstat = glGetError();
|
|
b3Assert(glstat == GL_NO_ERROR);
|
|
}
|
|
b3Assert((width * height * sizeof(float)) == depthBufferSizeInBytes);
|
|
if ((width * height * sizeof(float)) == depthBufferSizeInBytes)
|
|
{
|
|
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthBuffer);
|
|
int glstat;
|
|
glstat = glGetError();
|
|
b3Assert(glstat == GL_NO_ERROR);
|
|
}
|
|
}
|
|
|
|
//#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
#include "stb_image/stb_image_write.h"
|
|
static void writeTextureToFile(int textureWidth, int textureHeight, const char* fileName, FILE* ffmpegVideo)
|
|
{
|
|
int numComponents = 4;
|
|
//glPixelStorei(GL_PACK_ALIGNMENT,1);
|
|
|
|
b3Assert(glGetError() == GL_NO_ERROR);
|
|
//glReadBuffer(GL_BACK);//COLOR_ATTACHMENT0);
|
|
|
|
float* orgPixels = (float*)malloc(textureWidth * textureHeight * numComponents * 4);
|
|
glReadPixels(0, 0, textureWidth, textureHeight, GL_RGBA, GL_FLOAT, orgPixels);
|
|
//it is useful to have the actual float values for debugging purposes
|
|
|
|
//convert float->char
|
|
char* pixels = (char*)malloc(textureWidth * textureHeight * numComponents);
|
|
assert(glGetError() == GL_NO_ERROR);
|
|
|
|
for (int j = 0; j < textureHeight; j++)
|
|
{
|
|
for (int i = 0; i < textureWidth; i++)
|
|
{
|
|
pixels[(j * textureWidth + i) * numComponents] = char(orgPixels[(j * textureWidth + i) * numComponents] * 255.f);
|
|
pixels[(j * textureWidth + i) * numComponents + 1] = char(orgPixels[(j * textureWidth + i) * numComponents + 1] * 255.f);
|
|
pixels[(j * textureWidth + i) * numComponents + 2] = char(orgPixels[(j * textureWidth + i) * numComponents + 2] * 255.f);
|
|
pixels[(j * textureWidth + i) * numComponents + 3] = char(orgPixels[(j * textureWidth + i) * numComponents + 3] * 255.f);
|
|
}
|
|
}
|
|
|
|
if (ffmpegVideo)
|
|
{
|
|
fwrite(pixels, textureWidth * textureHeight * numComponents, 1, ffmpegVideo);
|
|
//fwrite(pixels, 100,1,ffmpegVideo);//textureWidth*textureHeight*numComponents, 1, ffmpegVideo);
|
|
}
|
|
else
|
|
{
|
|
if (1)
|
|
{
|
|
//swap the pixels
|
|
unsigned char tmp;
|
|
|
|
for (int j = 0; j < textureHeight / 2; j++)
|
|
{
|
|
for (int i = 0; i < textureWidth; i++)
|
|
{
|
|
for (int c = 0; c < numComponents; c++)
|
|
{
|
|
tmp = pixels[(j * textureWidth + i) * numComponents + c];
|
|
pixels[(j * textureWidth + i) * numComponents + c] =
|
|
pixels[((textureHeight - j - 1) * textureWidth + i) * numComponents + c];
|
|
pixels[((textureHeight - j - 1) * textureWidth + i) * numComponents + c] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
stbi_write_png(fileName, textureWidth, textureHeight, numComponents, pixels, textureWidth * numComponents);
|
|
}
|
|
|
|
free(pixels);
|
|
free(orgPixels);
|
|
}
|
|
|
|
void SimpleOpenGL3App::swapBuffer()
|
|
{
|
|
if (m_data->m_frameDumpPngFileName)
|
|
{
|
|
int width = (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenWidth();
|
|
int height = (int)m_window->getRetinaScale() * this->m_instancingRenderer->getScreenHeight();
|
|
writeTextureToFile(width,
|
|
height, m_data->m_frameDumpPngFileName,
|
|
m_data->m_ffmpegFile);
|
|
m_data->m_renderTexture->disable();
|
|
if (m_data->m_ffmpegFile == 0)
|
|
{
|
|
m_data->m_frameDumpPngFileName = 0;
|
|
}
|
|
}
|
|
m_window->endRendering();
|
|
m_window->startRendering();
|
|
}
|
|
|
|
// see also http://blog.mmacklin.com/2013/06/11/real-time-video-capture-with-ffmpeg/
|
|
void SimpleOpenGL3App::dumpFramesToVideo(const char* mp4FileName)
|
|
{
|
|
if (mp4FileName)
|
|
{
|
|
int width = (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenWidth();
|
|
int height = (int)m_window->getRetinaScale() * m_instancingRenderer->getScreenHeight();
|
|
char cmd[8192];
|
|
|
|
#ifdef _WIN32
|
|
sprintf(cmd,
|
|
"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - "
|
|
"-threads 0 -y -b:v 50000k -c:v libx264 -preset slow -crf 22 -an -pix_fmt yuv420p -vf vflip %s",
|
|
width, height, mp4FileName);
|
|
|
|
//sprintf(cmd, "ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - "
|
|
// "-y -crf 0 -b:v 1500000 -an -vcodec h264 -vf vflip %s", width, height, mp4FileName);
|
|
#else
|
|
|
|
sprintf(cmd,
|
|
"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - "
|
|
"-threads 0 -y -b 50000k -c:v libx264 -preset slow -crf 22 -an -pix_fmt yuv420p -vf vflip %s",
|
|
width, height, mp4FileName);
|
|
#endif
|
|
|
|
//sprintf(cmd,"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - "
|
|
// "-threads 0 -y -crf 0 -b 50000k -vf vflip %s",width,height,mp4FileName);
|
|
|
|
// sprintf(cmd,"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - "
|
|
// "-threads 0 -preset fast -y -crf 21 -vf vflip %s",width,height,mp4FileName);
|
|
|
|
if (m_data->m_ffmpegFile)
|
|
{
|
|
pclose(m_data->m_ffmpegFile);
|
|
}
|
|
if (mp4FileName)
|
|
{
|
|
m_data->m_ffmpegFile = popen(cmd, "w");
|
|
|
|
m_data->m_frameDumpPngFileName = mp4FileName;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_data->m_ffmpegFile)
|
|
{
|
|
fflush(m_data->m_ffmpegFile);
|
|
pclose(m_data->m_ffmpegFile);
|
|
m_data->m_frameDumpPngFileName = 0;
|
|
}
|
|
m_data->m_ffmpegFile = 0;
|
|
}
|
|
}
|
|
void SimpleOpenGL3App::dumpNextFrameToPng(const char* filename)
|
|
{
|
|
// open pipe to ffmpeg's stdin in binary write mode
|
|
|
|
m_data->m_frameDumpPngFileName = filename;
|
|
|
|
//you could use m_renderTexture to allow to render at higher resolutions, such as 4k or so
|
|
if (!m_data->m_renderTexture)
|
|
{
|
|
m_data->m_renderTexture = new GLRenderToTexture();
|
|
GLuint renderTextureId;
|
|
glGenTextures(1, &renderTextureId);
|
|
|
|
// "Bind" the newly created texture : all future texture functions will modify this texture
|
|
glBindTexture(GL_TEXTURE_2D, renderTextureId);
|
|
|
|
// Give an empty image to OpenGL ( the last "0" )
|
|
//glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, g_OpenGLWidth,g_OpenGLHeight, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
|
//glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F, g_OpenGLWidth,g_OpenGLHeight, 0,GL_RGBA, GL_FLOAT, 0);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F,
|
|
m_instancingRenderer->getScreenWidth() * m_window->getRetinaScale(), m_instancingRenderer->getScreenHeight() * m_window->getRetinaScale(), 0, GL_RGBA, GL_FLOAT, 0);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
m_data->m_renderTexture->init(m_instancingRenderer->getScreenWidth() * m_window->getRetinaScale(), this->m_instancingRenderer->getScreenHeight() * m_window->getRetinaScale(), renderTextureId, RENDERTEXTURE_COLOR);
|
|
}
|
|
|
|
m_data->m_renderTexture->enable();
|
|
}
|
|
|
|
void SimpleOpenGL3App::setUpAxis(int axis)
|
|
{
|
|
b3Assert((axis == 1) || (axis == 2)); //only Y or Z is supported at the moment
|
|
m_data->m_upAxis = axis;
|
|
}
|
|
int SimpleOpenGL3App::getUpAxis() const
|
|
{
|
|
return m_data->m_upAxis;
|
|
}
|
|
#endif //#ifndef NO_OPENGL3
|