add preliminary ray tracing test (ray-sphere placeholder on CPU)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#ifndef GPU_DEMO_H
|
#ifndef GPU_DEMO_H
|
||||||
#define GPU_DEMO_H
|
#define GPU_DEMO_H
|
||||||
class GLInstancingRenderer;
|
class GLInstancingRenderer;
|
||||||
|
class GLPrimitiveRenderer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -31,6 +32,8 @@ public:
|
|||||||
float gapY;
|
float gapY;
|
||||||
float gapZ;
|
float gapZ;
|
||||||
GLInstancingRenderer* m_instancingRenderer;
|
GLInstancingRenderer* m_instancingRenderer;
|
||||||
|
GLPrimitiveRenderer* m_primRenderer;
|
||||||
|
|
||||||
class b3gWindowInterface* m_window;
|
class b3gWindowInterface* m_window;
|
||||||
class GwenUserInterface* m_gui;
|
class GwenUserInterface* m_gui;
|
||||||
|
|
||||||
@@ -38,9 +41,9 @@ public:
|
|||||||
:useOpenCL(true),
|
:useOpenCL(true),
|
||||||
preferredOpenCLPlatformIndex(-1),
|
preferredOpenCLPlatformIndex(-1),
|
||||||
preferredOpenCLDeviceIndex(-1),
|
preferredOpenCLDeviceIndex(-1),
|
||||||
arraySizeX(30),
|
arraySizeX(2),
|
||||||
arraySizeY(30),
|
arraySizeY(2),
|
||||||
arraySizeZ(30),
|
arraySizeZ(2),
|
||||||
m_useConcaveMesh(false),
|
m_useConcaveMesh(false),
|
||||||
gapX(14.3),
|
gapX(14.3),
|
||||||
gapY(14.0),
|
gapY(14.0),
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ GpuDemo::CreateFunc* allDemos[]=
|
|||||||
// GpuConvexScene::MyCreateFunc,
|
// GpuConvexScene::MyCreateFunc,
|
||||||
|
|
||||||
//ConcaveSphereScene::MyCreateFunc,
|
//ConcaveSphereScene::MyCreateFunc,
|
||||||
|
GpuRaytraceScene::MyCreateFunc,
|
||||||
|
|
||||||
GpuBoxPlaneScene::MyCreateFunc,
|
GpuBoxPlaneScene::MyCreateFunc,
|
||||||
GpuConvexPlaneScene::MyCreateFunc,
|
GpuConvexPlaneScene::MyCreateFunc,
|
||||||
|
|
||||||
@@ -601,7 +603,7 @@ int main(int argc, char* argv[])
|
|||||||
ci.m_gui = gui;
|
ci.m_gui = gui;
|
||||||
ci.m_instancingRenderer->init();
|
ci.m_instancingRenderer->init();
|
||||||
ci.m_instancingRenderer->InitShaders();
|
ci.m_instancingRenderer->InitShaders();
|
||||||
|
ci.m_primRenderer = &prim;
|
||||||
// render.init();
|
// render.init();
|
||||||
|
|
||||||
demo->initPhysics(ci);
|
demo->initPhysics(ci);
|
||||||
|
|||||||
@@ -18,9 +18,11 @@
|
|||||||
#include "GpuRigidBodyDemoInternalData.h"
|
#include "GpuRigidBodyDemoInternalData.h"
|
||||||
#include "../gwenUserInterface.h"
|
#include "../gwenUserInterface.h"
|
||||||
#include "Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.h"
|
#include "Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.h"
|
||||||
|
#include "OpenGLWindow/GLPrimitiveRenderer.h"
|
||||||
|
|
||||||
void GpuConvexScene::setupScene(const ConstructionInfo& ci)
|
void GpuConvexScene::setupScene(const ConstructionInfo& ci)
|
||||||
{
|
{
|
||||||
|
m_primRenderer = ci.m_primRenderer;
|
||||||
|
|
||||||
int index=0;
|
int index=0;
|
||||||
createStaticEnvironment(ci);
|
createStaticEnvironment(ci);
|
||||||
@@ -30,11 +32,15 @@ void GpuConvexScene::setupScene(const ConstructionInfo& ci)
|
|||||||
m_data->m_rigidBodyPipeline->writeAllInstancesToGpu();
|
m_data->m_rigidBodyPipeline->writeAllInstancesToGpu();
|
||||||
|
|
||||||
|
|
||||||
float camPos[4]={ci.arraySizeX,ci.arraySizeY/2,ci.arraySizeZ,0};
|
float camPos[4]={0,0,0,0};//ci.arraySizeX,ci.arraySizeY/2,ci.arraySizeZ,0};
|
||||||
//float camPos[4]={1,12.5,1.5,0};
|
//float camPos[4]={1,12.5,1.5,0};
|
||||||
|
|
||||||
m_instancingRenderer->setCameraTargetPosition(camPos);
|
m_instancingRenderer->setCameraTargetPosition(camPos);
|
||||||
m_instancingRenderer->setCameraDistance(100);
|
m_instancingRenderer->setCameraDistance(30);
|
||||||
|
m_instancingRenderer->setCameraYaw(0);
|
||||||
|
m_instancingRenderer->setCameraPitch(0);
|
||||||
|
|
||||||
|
m_instancingRenderer->updateCamera();
|
||||||
|
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
int numInstances = index;
|
int numInstances = index;
|
||||||
@@ -174,3 +180,203 @@ void GpuConvexPlaneScene::createStaticEnvironment(const ConstructionInfo& ci)
|
|||||||
int pid = m_data->m_rigidBodyPipeline->registerPhysicsInstance(0.f,position,orn,colIndex,index,false);
|
int pid = m_data->m_rigidBodyPipeline->registerPhysicsInstance(0.f,position,orn,colIndex,index,false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GpuRaytraceInternalData
|
||||||
|
{
|
||||||
|
GLuint* m_texId;
|
||||||
|
unsigned char* m_texels;
|
||||||
|
int textureWidth;
|
||||||
|
int textureHeight;
|
||||||
|
};
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
GpuRaytraceScene::GpuRaytraceScene()
|
||||||
|
{
|
||||||
|
|
||||||
|
m_raytraceData = new GpuRaytraceInternalData;
|
||||||
|
|
||||||
|
m_raytraceData->m_texId = new GLuint;
|
||||||
|
m_raytraceData->textureWidth = 1024;
|
||||||
|
m_raytraceData->textureHeight = 768;
|
||||||
|
|
||||||
|
//create new texture
|
||||||
|
glGenTextures(1, m_raytraceData->m_texId);
|
||||||
|
GLenum err = glGetError();
|
||||||
|
assert(err==GL_NO_ERROR);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, *m_raytraceData->m_texId);
|
||||||
|
m_raytraceData->m_texels = (unsigned char*)malloc(m_raytraceData->textureWidth*m_raytraceData->textureHeight*3);
|
||||||
|
memset(m_raytraceData->m_texels,0,m_raytraceData->textureWidth*m_raytraceData->textureHeight*3);
|
||||||
|
for (int i=0;i<m_raytraceData->textureWidth;i++)
|
||||||
|
{
|
||||||
|
for (int y=0;y<m_raytraceData->textureHeight;y++)
|
||||||
|
{
|
||||||
|
int color = 0;
|
||||||
|
if (y<m_raytraceData->textureHeight-1 && (y>0) && (i>0 && i<m_raytraceData->textureWidth-1))
|
||||||
|
color = 255;
|
||||||
|
|
||||||
|
m_raytraceData->m_texels[(i+m_raytraceData->textureWidth*y)*3+0] = color;
|
||||||
|
m_raytraceData->m_texels[(i+m_raytraceData->textureWidth*y)*3+1] = color;
|
||||||
|
m_raytraceData->m_texels[(i+m_raytraceData->textureWidth*y)*3+2] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_raytraceData->textureWidth, m_raytraceData->textureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, m_raytraceData->m_texels);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
err = glGetError();
|
||||||
|
assert(err==GL_NO_ERROR);
|
||||||
|
|
||||||
|
}
|
||||||
|
GpuRaytraceScene::~GpuRaytraceScene()
|
||||||
|
{
|
||||||
|
glDeleteTextures(1,m_raytraceData->m_texId);
|
||||||
|
delete[] m_raytraceData->m_texels;
|
||||||
|
delete m_raytraceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool sphere_intersect(const b3Vector3& spherePos, b3Scalar radius, const b3Vector3& rayFrom, const b3Vector3& rayTo)
|
||||||
|
{
|
||||||
|
// rs = ray.org - sphere.center
|
||||||
|
const b3Vector3& rs = rayFrom - spherePos;
|
||||||
|
b3Vector3 rayDir = rayTo-rayFrom;//rayFrom-rayTo;
|
||||||
|
rayDir.normalize();
|
||||||
|
|
||||||
|
float B = b3Dot(rs, rayDir);
|
||||||
|
float C = b3Dot(rs, rs) - (radius * radius);
|
||||||
|
float D = B * B - C;
|
||||||
|
|
||||||
|
if (D > 0.0)
|
||||||
|
{
|
||||||
|
float t = -B - sqrt(D);
|
||||||
|
if ( (t > 0.0))// && (t < isect.t) )
|
||||||
|
{
|
||||||
|
return true;//isect.t = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuRaytraceScene::renderScene()
|
||||||
|
{
|
||||||
|
B3_PROFILE("raytrace");
|
||||||
|
//raytrace into the texels
|
||||||
|
m_instancingRenderer->updateCamera();
|
||||||
|
//generate primary rays
|
||||||
|
|
||||||
|
float top = 1.f;
|
||||||
|
float bottom = -1.f;
|
||||||
|
float nearPlane = 1.f;
|
||||||
|
|
||||||
|
float tanFov = (top-bottom)*0.5f / nearPlane;
|
||||||
|
|
||||||
|
float fov = 2.0 * atanf (tanFov);
|
||||||
|
|
||||||
|
b3Vector3 rayFrom, camTarget;
|
||||||
|
m_instancingRenderer->getCameraPosition(rayFrom);
|
||||||
|
m_instancingRenderer->getCameraTargetPosition(camTarget);
|
||||||
|
b3Vector3 rayForward = camTarget-rayFrom;
|
||||||
|
rayForward.normalize();
|
||||||
|
float farPlane = 500.f;
|
||||||
|
rayForward*= farPlane;
|
||||||
|
|
||||||
|
b3Vector3 rightOffset;
|
||||||
|
b3Vector3 vertical(0.f,1.f,0.f);
|
||||||
|
b3Vector3 hor;
|
||||||
|
hor = rayForward.cross(vertical);
|
||||||
|
hor.normalize();
|
||||||
|
vertical = hor.cross(rayForward);
|
||||||
|
vertical.normalize();
|
||||||
|
|
||||||
|
float tanfov = tanf(0.5f*fov);
|
||||||
|
|
||||||
|
hor *= 2.f * farPlane * tanfov;
|
||||||
|
vertical *= 2.f * farPlane * tanfov;
|
||||||
|
|
||||||
|
b3Vector3 rayToCenter = rayFrom + rayForward;
|
||||||
|
|
||||||
|
//should be screenwidth/height
|
||||||
|
b3Vector3 dHor = hor * 1.f/float(m_raytraceData->textureWidth);
|
||||||
|
b3Vector3 dVert = vertical * 1.f/float(m_raytraceData->textureHeight);
|
||||||
|
|
||||||
|
b3Transform rayFromTrans;
|
||||||
|
rayFromTrans.setIdentity();
|
||||||
|
rayFromTrans.setOrigin(rayFrom);
|
||||||
|
|
||||||
|
b3Transform rayFromLocal;
|
||||||
|
b3Transform rayToLocal;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//cast primary rays
|
||||||
|
|
||||||
|
m_data->m_np->readbackAllBodiesToCpu();
|
||||||
|
|
||||||
|
for (int x=0;x<m_raytraceData->textureWidth;x++)
|
||||||
|
{
|
||||||
|
for (int y=0;y<m_raytraceData->textureHeight;y++)
|
||||||
|
{
|
||||||
|
|
||||||
|
b3Vector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
|
||||||
|
rayTo += x * dHor;
|
||||||
|
rayTo -= y * dVert;
|
||||||
|
|
||||||
|
//if there is a hit, color the pixels
|
||||||
|
int numBodies = m_data->m_rigidBodyPipeline->getNumBodies();
|
||||||
|
bool hits = false;
|
||||||
|
|
||||||
|
for (int i=0;i<numBodies && !hits;i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
b3Vector3 pos;
|
||||||
|
b3Quaternion orn;
|
||||||
|
m_data->m_np->getObjectTransformFromCpu(pos,orn,i);
|
||||||
|
b3Scalar radius = 1;
|
||||||
|
|
||||||
|
hits = sphere_intersect(pos, radius, rayFrom, rayTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hits)
|
||||||
|
{
|
||||||
|
m_raytraceData->m_texels[(x+m_raytraceData->textureWidth*y)*3+0] = 255;
|
||||||
|
m_raytraceData->m_texels[(x+m_raytraceData->textureWidth*y)*3+1] = 0;
|
||||||
|
m_raytraceData->m_texels[(x+m_raytraceData->textureWidth*y)*3+2] = 0;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
m_raytraceData->m_texels[(x+m_raytraceData->textureWidth*y)*3+0] = 0;
|
||||||
|
m_raytraceData->m_texels[(x+m_raytraceData->textureWidth*y)*3+1] = 0;
|
||||||
|
m_raytraceData->m_texels[(x+m_raytraceData->textureWidth*y)*3+2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GLint err;
|
||||||
|
|
||||||
|
err = glGetError();
|
||||||
|
assert(err==GL_NO_ERROR);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, *m_raytraceData->m_texId);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_raytraceData->textureWidth, m_raytraceData->textureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, m_raytraceData->m_texels);
|
||||||
|
|
||||||
|
err = glGetError();
|
||||||
|
assert(err==GL_NO_ERROR);
|
||||||
|
b3Assert(m_primRenderer);
|
||||||
|
float color[4] = {1,1,1,1};
|
||||||
|
float rect[4] = {0,0,m_raytraceData->textureWidth,m_raytraceData->textureHeight};
|
||||||
|
float u[2] = {0,1};
|
||||||
|
float v[2] = {0,1};
|
||||||
|
int useRGBA = 1;
|
||||||
|
m_primRenderer->drawTexturedRect(rect[0],rect[1],rect[2],rect[3],color,u[0],v[0],u[1],v[1], useRGBA);
|
||||||
|
err = glGetError();
|
||||||
|
assert(err==GL_NO_ERROR);
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,9 +5,12 @@
|
|||||||
|
|
||||||
class GpuConvexScene : public GpuRigidBodyDemo
|
class GpuConvexScene : public GpuRigidBodyDemo
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
class GLPrimitiveRenderer* m_primRenderer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GpuConvexScene(){}
|
GpuConvexScene() :m_primRenderer(0) {}
|
||||||
virtual ~GpuConvexScene(){}
|
virtual ~GpuConvexScene(){}
|
||||||
virtual const char* getName()
|
virtual const char* getName()
|
||||||
{
|
{
|
||||||
@@ -72,7 +75,30 @@ public:
|
|||||||
|
|
||||||
virtual int createDynamicsObjects(const ConstructionInfo& ci);
|
virtual int createDynamicsObjects(const ConstructionInfo& ci);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GpuRaytraceScene : public GpuBoxPlaneScene
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
struct GpuRaytraceInternalData* m_raytraceData;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GpuRaytraceScene();
|
||||||
|
virtual ~GpuRaytraceScene();
|
||||||
|
virtual const char* getName()
|
||||||
|
{
|
||||||
|
return "GPURaytrace";
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpuDemo* MyCreateFunc()
|
||||||
|
{
|
||||||
|
GpuDemo* demo = new GpuRaytraceScene;
|
||||||
|
return demo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderScene();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif //GPU_CONVEX_SCENE_H
|
#endif //GPU_CONVEX_SCENE_H
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
static const char* vertexShader= \
|
static const char* vertexShader= \
|
||||||
"#version 150 \n"
|
"#version 150 \n"
|
||||||
"\n"
|
"\n"
|
||||||
"uniform vec2 p;\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
"in vec4 position;\n"
|
"in vec4 position;\n"
|
||||||
"in vec4 colour;\n"
|
"in vec4 colour;\n"
|
||||||
@@ -22,13 +21,14 @@ static const char* vertexShader= \
|
|||||||
"void main (void)\n"
|
"void main (void)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" colourV = colour;\n"
|
" colourV = colour;\n"
|
||||||
" gl_Position = vec4(p.x+position.x, p.y+position.y,0.f,1.f);\n"
|
" gl_Position = vec4(position.x, position.y,0.f,1.f);\n"
|
||||||
" texuvV=texuv;\n"
|
" texuvV=texuv;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
static const char* fragmentShader= \
|
static const char* fragmentShader= \
|
||||||
"#version 150\n"
|
"#version 150\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"uniform vec2 p;\n"
|
||||||
"in vec4 colourV;\n"
|
"in vec4 colourV;\n"
|
||||||
"out vec4 fragColour;\n"
|
"out vec4 fragColour;\n"
|
||||||
"in vec2 texuvV;\n"
|
"in vec2 texuvV;\n"
|
||||||
@@ -37,9 +37,11 @@ static const char* fragmentShader= \
|
|||||||
"\n"
|
"\n"
|
||||||
"void main(void)\n"
|
"void main(void)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" vec4 texcolorred = texture(Diffuse,texuvV);\n"
|
" vec4 texcolor = texture(Diffuse,texuvV);\n"
|
||||||
"// vec4 texcolor = vec4(texcolorred.x,texcolorred.x,texcolorred.x,1);\n"
|
" if (p.x==0.f)\n"
|
||||||
" vec4 texcolor = vec4(1,1,1,texcolorred.x);\n"
|
" {\n"
|
||||||
|
" texcolor = vec4(1,1,1,texcolor.x);\n"
|
||||||
|
" }\n"
|
||||||
"\n"
|
"\n"
|
||||||
" fragColour = colourV*texcolor;\n"
|
" fragColour = colourV*texcolor;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
@@ -89,6 +91,7 @@ m_screenHeight(screenHeight)
|
|||||||
m_data = new PrimInternalData;
|
m_data = new PrimInternalData;
|
||||||
|
|
||||||
m_data->m_shaderProg = gltLoadShaderPair(vertexShader,fragmentShader);
|
m_data->m_shaderProg = gltLoadShaderPair(vertexShader,fragmentShader);
|
||||||
|
|
||||||
|
|
||||||
m_data->m_positionUniform = glGetUniformLocation(m_data->m_shaderProg, "p");
|
m_data->m_positionUniform = glGetUniformLocation(m_data->m_shaderProg, "p");
|
||||||
if (m_data->m_positionUniform < 0) {
|
if (m_data->m_positionUniform < 0) {
|
||||||
@@ -231,7 +234,7 @@ void GLPrimitiveRenderer::drawRect(float x0, float y0, float x1, float y1, float
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLPrimitiveRenderer::drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1)//Line()//float from[4], float to[4], float color[4])
|
void GLPrimitiveRenderer::drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1, int useRGBA)
|
||||||
{
|
{
|
||||||
GLint err;
|
GLint err;
|
||||||
|
|
||||||
@@ -276,6 +279,12 @@ void GLPrimitiveRenderer::drawTexturedRect(float x0, float y0, float x1, float y
|
|||||||
assert(err==GL_NO_ERROR);
|
assert(err==GL_NO_ERROR);
|
||||||
|
|
||||||
vec2 p( 0.f,0.f);//?b?0.5f * sinf(timeValue), 0.5f * cosf(timeValue) );
|
vec2 p( 0.f,0.f);//?b?0.5f * sinf(timeValue), 0.5f * cosf(timeValue) );
|
||||||
|
if (useRGBA)
|
||||||
|
{
|
||||||
|
p.p[0] = 1.f;
|
||||||
|
p.p[1] = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
glUniform2fv(m_data->m_positionUniform, 1, (const GLfloat *)&p);
|
glUniform2fv(m_data->m_positionUniform, 1, (const GLfloat *)&p);
|
||||||
|
|
||||||
err = glGetError();
|
err = glGetError();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public:
|
|||||||
virtual ~GLPrimitiveRenderer();
|
virtual ~GLPrimitiveRenderer();
|
||||||
|
|
||||||
void drawRect(float x0, float y0, float x1, float y1, float color[4]);
|
void drawRect(float x0, float y0, float x1, float y1, float color[4]);
|
||||||
void drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1);
|
void drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1, int useRGBA=0);
|
||||||
void drawLine();//float from[4], float to[4], float color[4]);
|
void drawLine();//float from[4], float to[4], float color[4]);
|
||||||
void setScreenSize(int width, int height);
|
void setScreenSize(int width, int height);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user