예제 #1
0
void Transform::flush()
{
    if (m_needFlush)
    {
        m_needFlush=false;
        kmMat4Identity(&m_matrix);
        kmMat4 t_mat;
        
        //position
        kmMat4Identity(&t_mat);
        kmMat4Translation(&t_mat,m_x,m_y,0);
        kmMat4Multiply(&m_matrix, &m_matrix, &t_mat);
        
        //rotation
        kmMat4Identity(&t_mat);
        kmMat4RotationZ(&t_mat, m_rotationZ*PI/180.0f);
        kmMat4Multiply(&m_matrix, &m_matrix, &t_mat);
        
        //scale
        kmMat4Identity(&t_mat);
        kmMat4Scaling(&t_mat, m_scaleX, m_scaleY, 1);
        kmMat4Multiply(&m_matrix, &m_matrix, &t_mat);
        
        //anchorPoint
        kmMat4Identity(&t_mat);
        kmMat4Translation(&t_mat,(-m_anchorX*m_width),(-m_anchorY*m_height),0);
        kmMat4Multiply(&m_matrix, &m_matrix, &t_mat);
        
    }
}
예제 #2
0
Node::Node(void)
: _rotationX(0.0f)
, _rotationY(0.0f)
, _scaleX(1.0f)
, _scaleY(1.0f)
, _vertexZ(0.0f)
, _position(Point::ZERO)
, _skewX(0.0f)
, _skewY(0.0f)
, _anchorPointInPoints(Point::ZERO)
, _anchorPoint(Point::ZERO)
, _contentSize(Size::ZERO)
, _additionalTransformDirty(false)
, _transformDirty(true)
, _inverseDirty(true)
// children (lazy allocs)
// lazy alloc
, _ZOrder(0)
, _parent(nullptr)
// "whole screen" objects. like Scenes and Layers, should set _ignoreAnchorPointForPosition to true
, _tag(Node::INVALID_TAG)
// userData is always inited as nil
, _userData(nullptr)
, _userObject(nullptr)
, _shaderProgram(nullptr)
, _orderOfArrival(0)
, _running(false)
, _visible(true)
, _ignoreAnchorPointForPosition(false)
, _reorderChildDirty(false)
, _isTransitionFinished(false)
, _updateScriptHandler(0)
, _componentContainer(nullptr)
#if CC_USE_PHYSICS
, _physicsBody(nullptr)
#endif
, _displayedOpacity(255)
, _realOpacity(255)
, _displayedColor(Color3B::WHITE)
, _realColor(Color3B::WHITE)
, _cascadeColorEnabled(false)
, _cascadeOpacityEnabled(false)
{
    // set default scheduler and actionManager
    Director *director = Director::getInstance();
    _actionManager = director->getActionManager();
    _actionManager->retain();
    _scheduler = director->getScheduler();
    _scheduler->retain();
    _eventDispatcher = director->getEventDispatcher();
    _eventDispatcher->retain();
    
    ScriptEngineProtocol* engine = ScriptEngineManager::getInstance()->getScriptEngine();
    _scriptType = engine != nullptr ? engine->getScriptType() : kScriptTypeNone;

    kmMat4Identity(&_transform);
    kmMat4Identity(&_inverse);
    kmMat4Identity(&_additionalTransform);
}
예제 #3
0
파일: camera.cpp 프로젝트: chenbk85/KGLT
Camera::Camera(Scene *scene, CameraID id):
    Object(nullptr),
    generic::Identifiable<CameraID>(id),
    scene_(scene) {

    kmMat4Identity(&projection_matrix_); //Initialize the projection matrix
    kmMat4Identity(&view_matrix_);

    set_perspective_projection(45.0, 16.0 / 9.0);
}
예제 #4
0
Camera::Camera(CameraID id, WindowBase *window):
    generic::Identifiable<CameraID>(id),
    window_(window),
    proxy_(nullptr) {

    kmMat4Identity(&transform_);
    kmMat4Identity(&projection_matrix_); //Initialize the projection matrix
    kmMat4Identity(&view_matrix_);

    set_perspective_projection(45.0, float(window->width()) / float(window->height()));
}
예제 #5
0
/**
 * Creates a perspective projection matrix in the
 * same way as gluPerspective
 */
kmMat4* const kmMat4PerspectiveProjection(kmMat4* pOut, kmScalar fovY,
                                    kmScalar aspect, kmScalar zNear,
                                    kmScalar zFar)
{
	kmScalar r = kmDegreesToRadians(fovY / 2);
	kmScalar deltaZ = zFar - zNear;
	kmScalar s = sin(r);
    kmScalar cotangent = 0;

	if (deltaZ == 0 || s == 0 || aspect == 0) {
		return NULL;
	}

    //cos(r) / sin(r) = cot(r)
	cotangent = cos(r) / s;

	kmMat4Identity(pOut);
	pOut->mat[0] = cotangent / aspect;
	pOut->mat[5] = cotangent;
	pOut->mat[10] = -(zFar + zNear) / deltaZ;
	pOut->mat[11] = -1;
	pOut->mat[14] = -2 * zNear * zFar / deltaZ;
	pOut->mat[15] = 0;

	return pOut;
}
예제 #6
0
km_mat4_stack_context *lazyInitializeCurrentContext()
{
    km_mat4_stack_context *current_context = (km_mat4_stack_context *)pthread_getspecific(current_context_key);

    assert(current_context != NULL && "No context set");

	if (current_context && !current_context->initialized) {
		kmMat4 identity; /*Temporary identity matrix*/

		/*Initialize all 3 stacks*/
		/*modelview_matrix_stack = (km_mat4_stack*) malloc(sizeof(km_mat4_stack));*/
		km_mat4_stack_initialize(&current_context->modelview_matrix_stack);

		/*projection_matrix_stack = (km_mat4_stack*) malloc(sizeof(km_mat4_stack));*/
		km_mat4_stack_initialize(&current_context->projection_matrix_stack);

		/*texture_matrix_stack = (km_mat4_stack*) malloc(sizeof(km_mat4_stack));*/
		km_mat4_stack_initialize(&current_context->texture_matrix_stack);

		current_context->current_stack = &current_context->modelview_matrix_stack;
		current_context->initialized = 1;

		kmMat4Identity(&identity);

		/*Make sure that each stack has the identity matrix*/
		km_mat4_stack_push(&current_context->modelview_matrix_stack, &identity);
		km_mat4_stack_push(&current_context->projection_matrix_stack, &identity);
		km_mat4_stack_push(&current_context->texture_matrix_stack, &identity);
	}

    return current_context;
}
예제 #7
0
kmMat4* offsetRGB(kmMat4* m, float r, float g, float b) {
    kmMat4Identity(m);
    m->mat[12] = r;
    m->mat[13] = g;
    m->mat[14] = b;
    return m;
}
예제 #8
0
Skin::Skin()
    : _bone(nullptr)
    , _armature(nullptr)
    , _displayName("")
{
    kmMat4Identity(&_skinTransform);
}
예제 #9
0
/* \brief allocate new skin bone object */
GLHCKAPI glhckSkinBone* glhckSkinBoneNew(void)
{
   glhckSkinBone *object;
   TRACE(0);

   /* allocate object */
   if (!(object = _glhckCalloc(1, sizeof(glhckSkinBone))))
      goto fail;

   /* increase reference */
   object->refCounter++;

   /* identity matrices */
   kmMat4Identity(&object->offsetMatrix);

   /* insert to world */
   _glhckWorldInsert(skinBone, object, glhckSkinBone*);

   RET(0, "%p", object);
   return object;

fail:
   RET(0, "%p", NULL);
   return NULL;
}
void lazyInitialize()
{

	if (!initialized) {
		kmMat4 identity; //Temporary identity matrix

		//Initialize all 3 stacks
		//modelview_matrix_stack = (km_mat4_stack*) malloc(sizeof(km_mat4_stack));
		km_mat4_stack_initialize(&modelview_matrix_stack);

		//projection_matrix_stack = (km_mat4_stack*) malloc(sizeof(km_mat4_stack));
		km_mat4_stack_initialize(&projection_matrix_stack);

		//texture_matrix_stack = (km_mat4_stack*) malloc(sizeof(km_mat4_stack));
		km_mat4_stack_initialize(&texture_matrix_stack);

		current_stack = &modelview_matrix_stack;
		initialized = 1;

		kmMat4Identity(&identity);

		//Make sure that each stack has the identity matrix
		km_mat4_stack_push(&modelview_matrix_stack, &identity);
		km_mat4_stack_push(&projection_matrix_stack, &identity);
		km_mat4_stack_push(&texture_matrix_stack, &identity);
	}
}
예제 #11
0
파일: Player.cpp 프로젝트: wakqaz4/Bomber
bool Player::init()
{
	if (!Node::init())
		return false;
	_tank = Sprite3D::create("model/tank/tank_buttom.c3b");
	NavMeshAgentParam param;
	param.radius = 2.0f;
	param.height = 8.0f;
	param.maxSpeed = 8.0f;
	_agent = NavMeshAgent::create(param);
	AgentUserData *data = new AgentUserData{ 0.0f };
	_agent->setUserData(data);
	_tank->setScale(1.5f);
	_tank->addComponent(_agent);
	_tank->setPosition3D(Vec3(-40.0f, 1.0f, 30.0f));

	_barrel = Sprite3D::create("model/tank/barrel.c3b");
	_tank->addChild(_barrel);
	_barrel->setPosition3D(Vec3(0.30f, 2.0f, 1.6f));
	_barrel->setAnchorPoint(ccp(0.5, 0.5));
	_barrel->setScale(0.5f);
	float fRadSeed = 3.14159f / 180.0f;
	kmMat4 kMat;
	kmMat4Identity(&kMat);
	kmMat4RotationX(&kMat, 270 * fRadSeed);
	Quaternion quat(kMat);
	_barrel->setRotationQuat(quat);
	this->scheduleUpdate();

	this->addChild(_tank);
	this->setCameraMask((unsigned short)CameraFlag::USER1);
	return true;
}
void ParticlePrototype::draw(kmMat4& camMatrix)
{
    glBindVertexArray(vao);
    
    kmMat4 mvp;
    kmMat4Identity(&mvp);
    kmMat4Multiply(&mvp, &camMatrix, &_transform);
    
    glUseProgram(shader);
    glUniformMatrix4fv(mvpAttribute, 1, GL_FALSE, &mvp.mat[0]);
    
    glEnableVertexAttribArray(positionAttribute);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    
    glVertexAttribPointer(positionAttribute, 3, GL_FLOAT, GL_FALSE,
                          sizeof(GLfloat)*6, 0);
    
    glEnableVertexAttribArray(transformAttribute);
    glVertexAttribPointer(transformAttribute, 3, GL_FLOAT, GL_FALSE,
                          sizeof(GLfloat)*6, (void*)(sizeof(GLfloat)*3));
    
    glDrawArrays(GL_TRIANGLES, 0, vCount);
    
    glDisableVertexAttribArray(positionAttribute);
    glDisableVertexAttribArray(transformAttribute);
}
예제 #13
0
void Sprite::setBatchNode(SpriteBatchNode *spriteBatchNode)
{
    _batchNode = spriteBatchNode; // weak reference

    // self render
    if( ! _batchNode ) {
        _atlasIndex = INDEX_NOT_INITIALIZED;
        setTextureAtlas(nullptr);
        _recursiveDirty = false;
        setDirty(false);

        float x1 = _offsetPosition.x;
        float y1 = _offsetPosition.y;
        float x2 = x1 + _rect.size.width;
        float y2 = y1 + _rect.size.height;
        _quad.bl.vertices = Vertex3F( x1, y1, 0 );
        _quad.br.vertices = Vertex3F( x2, y1, 0 );
        _quad.tl.vertices = Vertex3F( x1, y2, 0 );
        _quad.tr.vertices = Vertex3F( x2, y2, 0 );

    } else {

        // using batch
        kmMat4Identity(&_transformToBatch);
        setTextureAtlas(_batchNode->getTextureAtlas()); // weak ref
    }
}
예제 #14
0
Skin::Skin()
    : _bone(nullptr)
    , _armature(nullptr)
    , _displayName("")
	, _effectType(SkinEffect_None)
{
    kmMat4Identity(&_skinTransform);
}
예제 #15
0
파일: Player.cpp 프로젝트: wakqaz4/Bomber
void Player::setPlayerAngle(int angle)
{
	float fRadSeed = 3.14159f / 180.0f;
	kmMat4 kMat;
	kmMat4Identity(&kMat);
	kmMat4RotationX(&kMat, (angleCount - angle) * fRadSeed);
	Quaternion quat(kMat);
	m_barrel->setRotationQuat(quat);
}
예제 #16
0
/* \brief set projection matrix, and identity view matrix */
GLHCKAPI void glhckRenderProjectionOnly(const kmMat4 *mat)
{
   kmMat4 identity;
   GLHCK_INITIALIZED();
   CALL(2, "%p", mat);
   kmMat4Identity(&identity);
   glhckRenderProjection(mat);
   glhckRenderView(&identity);
}
예제 #17
0
bool BaseRenderer::pre_visit(Object& obj) {
    modelview().push();

    kmMat4 trans;
    kmMat4Identity(&trans);
    kmMat4Translation(&trans, obj.absolute_position().x, obj.absolute_position().y, obj.absolute_position().z);
    kmMat4Multiply(&modelview().top(), &modelview().top(), &trans);

    return true;
}
예제 #18
0
NS_CC_BEGIN

ViewTransform::ViewTransform()
{
    kmVec3Fill(&_position,0,0,0);
    kmVec3Fill(&_focus,0,0,-1);
    kmVec3Fill(&_up,0,1,0);
    _dirty = true;
    kmMat4Identity(&_matrix);
}
예제 #19
0
slsTrackball *sls_trackball_init(slsTrackball *self, float radius,
                                 float rotation_speed) {
  self->radius = radius;
  self->rotation_speed = rotation_speed;
  kmQuaternionIdentity(&self->rotation);

  kmMat4Identity(&self->rotation_mat);

  return self;
}
예제 #20
0
void BaseRenderer::render(Scene& scene) {
    on_start_render(scene);

    //FIXME: This is ugly and inconsistent
    scene.active_camera().apply(&modelview().top());
    kmMat4Assign(&projection().top(), &scene.active_camera().projection_matrix());

    for(Scene::iterator it = scene.begin(); it != scene.end(); ++it) {
        Object& object = static_cast<Object&>(*it);
        if(pre_visit(object)) {
            (*this)(object);
            post_visit(object);
        }
    }

    //Reset the modelview and projection for the overlay
    kmMat4Identity(&modelview().top());
    kmMat4Identity(&projection().top());

    /*
      Once the entire scene has been rendered, it's time to handle the
      overlays.
    */
    for(uint32_t i = 0; i < scene.overlay_count(); ++i) {
        Overlay& overlay = scene.overlay_ordered_by_zindex(i);
        projection().push();

        for(Scene::iterator it = overlay.begin(); it != overlay.end(); ++it) {
            Object& object = static_cast<Object&>(*it);
            if(pre_visit(object)) {
                (*this)(object);
                post_visit(object);
            }
        }
        projection().pop();
    }

    on_finish_render(scene);
}
예제 #21
0
static void cxEngineLookAt(cxMatrix4f *matrix,const cxVec2f point)
{
    cxEngine engine = cxEngineInstance();
    cxFloat zeye = engine->winsize.h / 1.1566f;
    cxVec3f eye;
    cxVec3f center;
    cxVec3f up;
    kmVec3Fill(&eye, point.x, point.y, zeye);
    kmVec3Fill(&center, point.x, point.y, 0.0f);
    kmVec3Fill(&up, 0.0f, 1.0f, 0.0f);
    kmMat4Identity(matrix);
    kmMat4LookAt(matrix, &eye, &center, &up);
}
예제 #22
0
kmMat4* hueRotation(kmMat4* m, float r) {
    kmMat4 mat0;
    kmMat4 mat1;
    kmMat4 temp;

    // Make an identity matrix.
    kmMat4Identity(&mat0);

    // Rotate the grey vector into positive Z.
    // Sin = 1/sqrt(2).
    // Cos = 1/sqrt(2).
    kmMat4RotationX(&temp, M_PI_4);
    kmMat4Multiply(&mat1, &temp, &mat0);

    // Sin = -1/sqrt(3).
    // Cos = sqrt(2/3).
    kmMat4RotationY(&temp, -0.615479709);
    kmMat4Multiply(&mat0, &temp, &mat1);

    // Shear the space to make the luminance plane horizontal.
    float lx, ly, lz;
    xformRGB(&mat0, rwgt, gwgt, bwgt, &lx, &ly, &lz);

    float zsx = lx / lz;
    float zsy = ly / lz;
    shearZMatrix(&temp, zsx, zsy);
    kmMat4Multiply(&mat1, &temp, &mat0);

    // Rotate the hue.
    float rad = r * M_PI / 180;
    kmMat4RotationZ(&temp, rad);
    kmMat4Multiply(&mat0, &temp, &mat1);

    // Unshear the space to put the luminance plane back.
    shearZMatrix(&temp, -zsx, -zsy);
    kmMat4Multiply(&mat1, &temp, &mat0);

    // Rotate the grey vector back into place.
    // Sin = 1/sqrt(3).
    // Cos = sqrt(2/3);
    kmMat4RotationY(&temp, 0.615479709);
    kmMat4Multiply(&mat0, &temp, &mat1);

    // Sin = -1/sqrt(2).
    // Cos = 1/sqrt(2).
    kmMat4RotationX(&temp, -M_PI_4);
    kmMat4Multiply(&mat1, &temp, &mat0);

    kmMat4Fill(m, mat1.mat);
    return m;
}
예제 #23
0
lite3d_scene_node *lite3d_scene_node_init(lite3d_scene_node *node)
{
    SDL_assert(node);
    memset(node, 0, sizeof (lite3d_scene_node));
    lite3d_list_link_init(&node->nodeLink);
    kmMat4Identity(&node->localView);
    kmMat4Identity(&node->worldView);
    kmMat3Identity(&node->normalModel);
    kmQuaternionIdentity(&node->rotation);
    kmVec3Fill(&node->position, 0, 0, 0);
    kmVec3Fill(&node->scale, 1.0f, 1.0f, 1.0f);
    node->recalc = LITE3D_TRUE;
    node->invalidated = LITE3D_TRUE;
    node->rotationCentered = LITE3D_TRUE;
    node->isCamera = LITE3D_FALSE;
    node->renderable = LITE3D_TRUE;
    node->enabled = LITE3D_TRUE;
    node->visible = LITE3D_TRUE;
    node->frustumTest = LITE3D_TRUE;
    lite3d_list_init(&node->childNodes);

    return node;
}
예제 #24
0
파일: Player.cpp 프로젝트: wakqaz4/Bomber
bool Player::init()
{
	m_rotationAngle = 0.f;

	if (!Node::init())
		return false;
	if (m_sPlayerInfo.m_ID == 1)
	{
		m_tank = Sprite3D::create("model/boss.c3b");
	}
	else
	{
		m_tank = Sprite3D::create("model/WoT_IS7/tank_buttom.c3b");
	}	
	NavMeshAgentParam param;
	param.radius = 2.0f;
	param.height = 8.0f;
	param.maxSpeed = 8.0f;
	m_agent = NavMeshAgent::create(param);
	//	sprite->_agent->setOrientationRefAxes(Vec3(-1.0f, 0.0f, 1.0f));
	AgentUserData *data = new AgentUserData{ 0.0f };
	m_agent->setUserData(data);
	m_tank->setScale(1.5f);
	m_tank->addComponent(m_agent);
	//	_tank->setTag(1);
	this->scheduleUpdate();
	m_barrel = Sprite3D::create("model/WoT_IS7/barrel.c3b");
	m_tank->addChild(m_barrel);

	m_barrel->setPosition3D(Vec3(0.30f, 2.0f, 1.6f));
	m_barrel->setAnchorPoint(ccp(0.5, 0.5));
	m_barrel->setScale(0.5f);
	m_tank->setPosition3D(Vec3(-40.0f, 1.0f, 30.0f));
	float fRadSeed = 3.14159f / 180.0f;
	kmMat4 kMat;
	kmMat4Identity(&kMat);
	kmMat4RotationX(&kMat, 270 * fRadSeed);
	Quaternion quat(kMat);
	m_barrel->setRotationQuat(quat);
	//将坦克模型加载到Node节点
	float width = m_barrel->getContentSize().width;
	float height = m_barrel->getContentSize().height;
	log("barrel width = %f height = %f", width, height);
	//	this->addChild(_barrel);
	this->addChild(m_tank);
	//	this->setPosition3D(Vec3(-40.0f, 1.0f, 30.0f));
	this->setCameraMask((unsigned short)CameraFlag::USER1);

	return true;
}
예제 #25
0
/**
 * Calculates the inverse of pM and stores the result in
 * pOut.
 * @Return Returns NULL if there is no inverse, else pOut
 */
kmMat4* const kmMat4Inverse(kmMat4* pOut, const kmMat4* pM)
{
    kmMat4 inv;
    kmMat4Assign(&inv, pM);

    kmMat4 tmp;
    kmMat4Identity(&tmp);

    if(gaussj(&inv, &tmp) == KM_FALSE) {
        return NULL;
    }

    kmMat4Assign(pOut, &inv);
    return pOut;
}
예제 #26
0
void Transform::init()
{
    m_x = 0;
    m_y = 0;
    m_anchorX = 0;
    m_anchorY = 0;
    m_scaleX = 1;
    m_scaleY = 1;
    m_rotationX = 0;
    m_rotationY = 0;
    m_rotationZ = 0;
    m_width = 0;
    m_height = 0;
    kmMat4Identity(&m_matrix);
}
예제 #27
0
void window_size_callback(GLFWwindow* window, int w, int h)
{
	width=w;height=h;

    glViewport(0, 0, width, height);

    // projection matrix, as distance increases
    // the way the model is drawn is effected
    kmMat4Identity(&projection);
    kmMat4PerspectiveProjection(&projection, 45,
                                (float)width / height, 0.1, 1000);

	reProjectGlPrint(width,height); // updates the projection matrix used by glPrint
	reProjectSprites(width,height); // updates the projection matrix used by the sprites
	resizePointCloudSprites((float)width/24.0);

}
예제 #28
0
void
draw_sprite (mrb_state *mrb, mrb_value sprite, kmMat4* matrices)
{
  MCL_Sprite *spr = DATA_PTR (sprite);
  MCL_Bitmap *bmp;
  mrb_value shader;
  MCL_Shader *shaderid;
  if (!spr->visible)
    {
      return;
    }
  bmp = DATA_PTR (mrb_iv_get (mrb, sprite, mrb_intern_lit (mrb, "@bitmap")));
  if (lastVao != spr->vao)
    {
      glBindVertexArray (spr->vao);
      lastVao = spr->vao;
    }
  if (lastVbo != spr->vbo)
    {
      glBindBuffer (GL_ARRAY_BUFFER, spr->vbo);
      lastVbo = spr->vbo;
    }
  if (!eabbind)
    {
      glGenBuffers (1, &eab);
      glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, eab);
      glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices, GL_STATIC_DRAW);
      eabbind = TRUE;
    }
  glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, eab);
  if (lastTexture != bmp->glTexture)
    {
      glBindTexture (GL_TEXTURE_2D, bmp->glTexture);
      lastTexture = bmp->glTexture;
    }

  kmMat4Identity(&matrices[0]);


  shader = mrb_iv_get (mrb, sprite, mrb_intern_lit (mrb, "@shader"));
  shaderid = DATA_PTR (shader);
  bind_shader_attributes (shaderid->shaderId, matrices);

  glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
예제 #29
0
파일: mat4.c 프로젝트: korman/Temp
/** Creates an orthographic projection matrix like glOrtho */
kmMat4* const kmMat4OrthographicProjection(kmMat4* pOut, kmScalar left,
		kmScalar right, kmScalar bottom, kmScalar top, kmScalar nearVal,
		kmScalar farVal)
{
	kmScalar tx = -((right + left) / (right - left));
	kmScalar ty = -((top + bottom) / (top - bottom));
	kmScalar tz = -((farVal + nearVal) / (farVal - nearVal));

	kmMat4Identity(pOut);
	pOut->mat[0] = 2 / (right - left);
	pOut->mat[5] = 2 / (top - bottom);
	pOut->mat[10] = -2 / (farVal - nearVal);
	pOut->mat[12] = tx;
	pOut->mat[13] = ty;
	pOut->mat[14] = tz;

	return pOut;
}
예제 #30
0
파일: mat4.c 프로젝트: izikhuang/kazmath
kmMat4* kmMat4AssignMat3(kmMat4* pOut, const kmMat3* pIn) {
    kmMat4Identity(pOut);

    pOut->mat[0] = pIn->mat[0];
    pOut->mat[1] = pIn->mat[1];
    pOut->mat[2] = pIn->mat[2];
    pOut->mat[3] = 0.0;

    pOut->mat[4] = pIn->mat[3];
    pOut->mat[5] = pIn->mat[4];
    pOut->mat[6] = pIn->mat[5];
    pOut->mat[7] = 0.0;

    pOut->mat[8] = pIn->mat[6];
    pOut->mat[9] = pIn->mat[7];
    pOut->mat[10] = pIn->mat[8];
    pOut->mat[11] = 0.0;

    return pOut;
}