This commit is contained in:
koma 2022-05-03 14:51:36 +02:00
parent 831523aa10
commit 5f5c660190
9 changed files with 305 additions and 100 deletions

View File

@ -1,4 +1,4 @@
all:
gcc -Iinclude/ src/app.c src/camera.c src/main.c src/game.c src/utils.c src/noise.c src/chunk.c -lSDL2 -lGL -lm -lSDL2_image -lGLU -o test -Wall
debug:
gcc -Iinclude/ src/app.c src/camera.c src/main.c src/game.c src/utils.c src/noise.c src/chunk.c -lSDL2 -lGL -lm -lSDL2_image -o test -Wall -g
gcc -Iinclude/ src/app.c src/camera.c src/main.c src/game.c src/utils.c src/noise.c src/chunk.c -lSDL2 -lGL -lm -lSDL2_image -lGLU -o test -Wall -g

View File

@ -21,12 +21,6 @@ typedef unsigned int uint;
#define CHUNK_MAX_Y 16
#define CHUNK_MAX_Z 128
typedef struct {
GLuint tid;
SDL_Surface *surface;
int type;
} Type_surface;
typedef struct {
bool is_running;
SDL_Window *window;
@ -42,7 +36,7 @@ void app_generate_world(App *app, int a);
void app_load_textures(App *app);
SDL_Surface* app_get_surface(App *app, Block_type type);
GLuint app_get_texture(App *app, Block_type type);
int check_intersection_block(App *app, vec3i *retv, int *chunk_index);
void app_break_block(App *app);

53
include/chunk.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef CHUNK_H
#define CHUNK_H
#include <stdbool.h>
#include <GL/gl.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "utils.h"
typedef struct {
GLuint tid;
SDL_Surface *surface;
int type;
} Type_surface;
typedef enum {
BLOCKTYPE_AIR,
BLOCKTYPE_GRASS,
BLOCKTYPE_DIRT,
BLOCKTYPE_STONE,
BLOCKTYPE_COUNT,
} Block_type;
typedef struct
{
Block_type type;
bool visible;
} Block;
typedef struct {
vec3f start_pos;
Block blocks[CHUNK_MAX_X][CHUNK_MAX_Y][CHUNK_MAX_Z];
GLuint id;
} Chunk;
typedef struct
{
unsigned int chunk_count;
Chunk *chunks;
Type_surface *textures;
unsigned int texture_count;
} ChunkManager;
bool chunk_is_block_neighboring_block(Chunk* chunk, vec3i pos);
void chunk_set_blocks_visibility(Chunk* chunk);
void chunk_create_displayl(ChunkManager *cm, Chunk *chunk);
void chunk_render(Chunk* chunk);
void chunk_update(ChunkManager* cm, Chunk *chunk);
void draw_cube(ChunkManager *cm, Block_type type, float x, float y, float z);
bool is_block(Block b);
int chunk_get_current_chunk_index(ChunkManager *cm, vec3f pos);
#endif

View File

@ -51,7 +51,7 @@ double degree_to_radian(double degree);
bool is_oob(int i, int min, int max);
void mult_matrix(float m1[16], float m2[16], float mout[16]);
void mult_matrix(const float m1[16], const float m2[16], float mo[16]);
bool matrix_inverse(const float m[16], float invOut[16]);

View File

@ -40,6 +40,8 @@ void init_app(App *app, uint w, uint h)
app->surfaces = malloc(app->surface_count+1*sizeof(Type_surface));
app_load_textures(app);
app->cm->textures = app->surfaces;
app->cm->texture_count = app->surface_count;
app_generate_world(app, 10);
app->is_running = true;
@ -52,67 +54,36 @@ void app_load_textures(App *app)
app->surfaces[2].type = BLOCKTYPE_STONE;
app->surfaces[0].surface = IMG_Load("assets/block.png");
//app->surfaces[1].surface = IMG_Load("assets/block.png");
//app->surfaces[2].surface = IMG_Load("assets/block.png");
app->surfaces[1].surface = IMG_Load("assets/block.png");
app->surfaces[2].surface = IMG_Load("assets/block.png");
for (int i = 0; i < app->surface_count-2; i++) {
//app->surfaces[i].tid = i;
//if(app->surfaces[i].surface == NULL) {
// printf("error loading texture\n");
// exit(1);
//}
//glGenTextures(1, &app->surfaces[i].tid);
//glBindTexture(GL_TEXTURE_2D, app->surfaces[i].tid);
//
//int Mode = GL_RGB;
//if(app->surfaces[i].surface->format->BytesPerPixel == 4) {
// Mode = GL_RGBA;
//}
//
//glTexImage2D(GL_TEXTURE_2D, 0, Mode, app->surfaces[i].surface->w,
// app->surfaces[i].surface->h, 0, Mode, GL_UNSIGNED_BYTE,
// app->surfaces[i].surface->pixels);
//
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glBindTexture(GL_TEXTURE_2D, app->surfaces[i].tid);
}
app->surfaces[0].tid = 1;
if(app->surfaces[0].surface == NULL) {
if(app->surfaces[i].surface == NULL) {
printf("error loading texture\n");
exit(1);
}
glGenTextures(1, &app->surfaces[0].tid);
glBindTexture(GL_TEXTURE_2D, app->surfaces[0].tid);
glGenTextures(1, &app->surfaces[i].tid);
glBindTexture(GL_TEXTURE_2D, app->surfaces[i].tid);
int Mode = GL_RGB;
if(app->surfaces[0].surface->format->BytesPerPixel == 4) {
if(app->surfaces[i].surface->format->BytesPerPixel == 4) {
Mode = GL_RGBA;
}
glTexImage2D(GL_TEXTURE_2D, 0, Mode, app->surfaces[0].surface->w,
app->surfaces[0].surface->h, 0, Mode, GL_UNSIGNED_BYTE,
app->surfaces[0].surface->pixels);
glTexImage2D(GL_TEXTURE_2D, 0, Mode, app->surfaces[i].surface->w,
app->surfaces[i].surface->h, 0, Mode, GL_UNSIGNED_BYTE,
app->surfaces[i].surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, app->surfaces[0].tid);
}
SDL_Surface* app_get_surface(App *app, Block_type type)
{
for (int i = 0; i < app->surface_count; i++) {
if (app->surfaces[i].type == type)
return app->surfaces[i].surface;
glBindTexture(GL_TEXTURE_2D, app->surfaces[i].tid);
}
return NULL;
}
void update_app(App* app)
{
@ -122,7 +93,7 @@ void update_app(App* app)
void init_opengl()
{
// https://gitlab.com/imre-piller/me-courses/ alapjan.
glShadeModel(GL_SMOOTH);
/* glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);
glEnable(GL_AUTO_NORMAL);
@ -135,6 +106,7 @@ void init_opengl()
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0);
glEnable(GL_TEXTURE_2D);
*/
}
void reshape(GLsizei width, GLsizei height)
@ -284,7 +256,7 @@ void app_generate_world(App *app, int a)
}
}
chunk_set_blocks_visibility(&c);
chunk_create_displayl(&c);
chunk_create_displayl(app->cm, &c);
app->cm->chunks[i+(j*a)] = c;
}
@ -401,6 +373,6 @@ void app_break_block(App *app)
return;
app->cm->chunks[i].blocks[block.x][block.y][block.z].type = BLOCKTYPE_AIR;
chunk_update(&(app->cm->chunks[i]));
chunk_update(app->cm, &(app->cm->chunks[i]));
}

View File

@ -9,7 +9,7 @@ void init_camera(Camera* camera)
{
camera->position.x = 5.0;
camera->position.y = 5.0;
camera->position.z = 90.0;
camera->position.z = 40.0;
camera->rotation.x = 0.0;
camera->rotation.y = 0.0;
camera->rotation.z = 0.0;

148
src/chunk.c Normal file
View File

@ -0,0 +1,148 @@
#include "../include/chunk.h"
#include <GL/gl.h>
bool chunk_is_block_neighboring_block(Chunk* chunk, vec3i pos)
{
if (is_oob(pos.x-1, 0, CHUNK_MAX_X) || is_oob(pos.x+1, 0, CHUNK_MAX_X))
return false;
if (is_oob(pos.y-1, 0, CHUNK_MAX_Y) || is_oob(pos.y+1, 0, CHUNK_MAX_Y))
return false;
if (is_oob(pos.z-1, 0, CHUNK_MAX_Z) || is_oob(pos.z+1, 0, CHUNK_MAX_Z))
return false;
if (chunk->blocks[pos.x-1][pos.y][pos.z].type != BLOCKTYPE_AIR &&
chunk->blocks[pos.x+1][pos.y][pos.z].type != BLOCKTYPE_AIR &&
chunk->blocks[pos.x][pos.y-1][pos.z].type != BLOCKTYPE_AIR &&
chunk->blocks[pos.x][pos.y+1][pos.z].type != BLOCKTYPE_AIR &&
chunk->blocks[pos.x][pos.y][pos.z-1].type != BLOCKTYPE_AIR &&
chunk->blocks[pos.x][pos.y][pos.z+1].type != BLOCKTYPE_AIR)
return true;
return false;
}
void chunk_set_blocks_visibility(Chunk* chunk)
{
for (int x = 0; x < CHUNK_MAX_X; x++) {
for (int y = 0; y < CHUNK_MAX_Y; y++) {
for (int z = 0; z < CHUNK_MAX_Z; z++) {
vec3i v = {x, y, z};
if (chunk_is_block_neighboring_block(chunk, v))
chunk->blocks[x][y][z].visible = false;
else
chunk->blocks[x][y][z].visible = true;
if (chunk->blocks[x][y][z].type == BLOCKTYPE_AIR)
chunk->blocks[x][y][z].visible = false;
}
}
}
}
void chunk_update(ChunkManager *cm, Chunk *chunk)
{
chunk_set_blocks_visibility(chunk);
chunk_create_displayl(cm, chunk);
}
void draw_cube(ChunkManager *cm, Block_type type, float x, float y, float z)
{
/*x*=2;
y*=2;
z*=2;
*/
/*
for (int i = 0; i < cm->texture_count; i++) {
if (cm->textures[i].type == type)
glBindTexture(GL_TEXTURE_2D, cm->textures[i].tid);
}
*/
glBegin( GL_QUADS );
glColor3f(1, 0, 1);
glTexCoord2f(0, 0); glVertex3f(x+1.0, y, z-1.0 );
glTexCoord2f(0, 1); glVertex3f(x, y, z-1.0);
glTexCoord2f(1, 1); glVertex3f(x, y, z);
glTexCoord2f(1, 0); glVertex3f(x+1.0, y, z);
glColor3f(1, 0, 1);
glTexCoord2f(0, 0); glVertex3f(x+1.0, y-1.0, z-1.0);
glTexCoord2f(0, 1); glVertex3f(x, y-1.0, z-1.0);
glTexCoord2f(1, 1); glVertex3f(x, y-1.0, z);
glTexCoord2f(1, 0); glVertex3f(x+1.0, y-1.0, z);
glColor3f(1, 0, 1);
glTexCoord2f(0, 0); glVertex3f(x+1.0, y, z);
glTexCoord2f(0, 1); glVertex3f(x, y, z);
glTexCoord2f(1, 1); glVertex3f(x, y-1.0, z);
glTexCoord2f(1, 0); glVertex3f(x+1.0, y-1.0, z);
glColor3f(1, 0, 1);
glTexCoord2f(0, 0); glVertex3f(x, y, z-1.0); // Top-Right of back face
glTexCoord2f(0, 1); glVertex3f(x+1.0, y, z-1.0); // Top-Left of back face
glTexCoord2f(1, 1); glVertex3f(x+1.0, y-1.0, z-1.0); // Bottom-Left of back face
glTexCoord2f(1, 0); glVertex3f(x, y-1.0, z-1.0); // Bottom-Right of back face
glColor3f(1, 0, 1);
glTexCoord2f(0, 0); glVertex3f(x, y, z); // Top-Right of left face
glTexCoord2f(0, 1); glVertex3f(x, y, z-1.0); // Top-Left of left face
glTexCoord2f(1, 1); glVertex3f(x, y-1.0, z-1.0); // Bottom-Left of left face
glTexCoord2f(1, 0); glVertex3f(x, y-1.0, z); // Bottom-Right of left face
glColor3f(1, 0, 1);
glTexCoord2f(0, 0); glVertex3f(x+1.0, y, z); // Top-Right of left face
glTexCoord2f(0, 1); glVertex3f(x+1.0, y, z-1.0); // Top-Left of left face
glTexCoord2f(1, 1); glVertex3f(x+1.0, y-1.0, z-1.0); // Bottom-Left of left face
glTexCoord2f(1, 0); glVertex3f(x+1.0, y-1.0, z); // Bottom-Right of left face
glEnd();
glFlush();
}
void chunk_create_displayl(ChunkManager *cm, Chunk *chunk)
{
//glBindTexture(GL_TEXTURE_2D, 1);
chunk->id = glGenLists(1);
glBindTexture(GL_TEXTURE_2D, cm->textures[0].tid);
glNewList(chunk->id, GL_COMPILE);
for (int x = 0; x < CHUNK_MAX_X; x++) {
for (int y = 0; y < CHUNK_MAX_Y; y++) {
for (int z = 0; z < CHUNK_MAX_Z; z++) {
if (chunk->blocks[x][y][z].visible)
draw_cube(cm, chunk->blocks[x][y][z].type,
chunk->start_pos.x + x, chunk->start_pos.y + y, chunk->start_pos.z + z);
}
}
}
glEndList();
}
void chunk_render(Chunk* chunk)
{
glPushMatrix();
glCallList(chunk->id);
glPopMatrix();
}
int chunk_get_current_chunk_index(ChunkManager *cm, vec3f pos)
{
for (int i = 0; i < cm->chunk_count; i++) {
for (int x = 0; x < CHUNK_MAX_X; x++) {
for (int y = 0; y < CHUNK_MAX_Y; y++) {
for (int z = 0; z < CHUNK_MAX_Z; z++) {
if (pos.x < cm->chunks[i].start_pos.x + CHUNK_MAX_X &&
pos.x > cm->chunks[i].start_pos.x &&
pos.y < cm->chunks[i].start_pos.y + CHUNK_MAX_Y &&
pos.y > cm->chunks[i].start_pos.y) {
return i;
}
}
}
}
}
return -1;
}

View File

@ -4,7 +4,7 @@
#include <time.h>
#include <GL/glu.h>
#define SHADOWMAP_SIZE 1024
#define SHADOWMAP_SIZE 2048
int main()
{
struct timespec start;
@ -15,14 +15,20 @@ int main()
init_app(&app, 1600, 900);
/////
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
//glEnable(GL_CULL_FACE);
glEnable(GL_NORMALIZE);
GLuint shadowmap_texture;
@ -44,46 +50,47 @@ int main()
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
GLfloat materialColor[] = {0.5f, 0.5f, 0.5f, 0.0f};
glMaterialfv(GL_FRONT, GL_SPECULAR, materialColor);
glMaterialf(GL_FRONT, GL_SHININESS, 16.0f);
//GLfloat materialColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
//glMaterialfv(GL_FRONT, GL_SPECULAR, materialColor);
glMaterialf(GL_FRONT, GL_SHININESS, 64.0f);
//reshape(1600, 900);
glPushMatrix();
glLoadIdentity();
gluPerspective(45.0f, (float)1600/900, 1.0f, 10000.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, cam_proj_matrix);
glLoadIdentity();
gluPerspective(45.0, 1.0, 2.0, 10000.0);
glGetFloatv(GL_MODELVIEW_MATRIX, light_proj_matrix);
glLoadIdentity();
gluLookAt(80, 80, 90,
20.0, 20.0, 10.0,
0.0, 0.0, 1.0);
glGetFloatv(GL_MODELVIEW_MATRIX, light_view_matrix);
glPopMatrix();
/////
while(app.is_running) {
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
vec3f cd = get_camera_dir_vec3f(&app.camera);
vec3f cp = app.camera.position;
glPushMatrix();
glLoadIdentity();
gluPerspective(45.0f, (float)1600/900, 1.0f, 100.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, cam_proj_matrix);
glLoadIdentity();
gluLookAt(cp.x, cp.y, cp.z,
cp.x*cd.x, cp.y*cd.y, cp.z*cd.z,
0.0, 0.0, 1.0);
// glLoadIdentity();
// gluLookAt(cp.x, cp.y, cp.z,
// 10.0, 10.0, 30.0,
// 0.0, 0.0, 1.0);
set_view(&app.camera);
glGetFloatv(GL_MODELVIEW_MATRIX, cam_view_matrix);
glLoadIdentity();
gluPerspective(45.0, 1.0, 2.0, 1000.0);
glGetFloatv(GL_MODELVIEW_MATRIX, light_proj_matrix);
glLoadIdentity();
gluLookAt(30, 40, 30,
0.0, 0.0, 0.0,
0.0, 0.0, 1.0);
glGetFloatv(GL_MODELVIEW_MATRIX, light_view_matrix);
glPopMatrix();
///////////////
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -109,10 +116,11 @@ int main()
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, SHADOWMAP_SIZE, SHADOWMAP_SIZE);
glCullFace(GL_BACK);
glDisable(GL_CULL_FACE);
//glDisable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glColorMask(1, 1, 1, 1);
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(cam_proj_matrix);
glMatrixMode(GL_MODELVIEW);
@ -123,10 +131,10 @@ int main()
handle_events(&app);
update_app(&app);
float color1[4] = {0.2, 0.2, 0.2, 0.2};
float color1[4] = {0, 0, 0, 0};
float color2[4] = {0, 0, 0, 0};
float color3[4] = {1.0, 1.0, 1.0, 1.0};
float light_pos[5] = {0, 0, 50, 0};
float color3[4] = {1.0, 1.0, 1.0, 0.0};
float light_pos[4] = {80, 80, 90, 0};
glLightfv(GL_LIGHT1, GL_POSITION, light_pos);
glLightfv(GL_LIGHT1, GL_AMBIENT, color1);
glLightfv(GL_LIGHT1, GL_DIFFUSE, color1);
@ -148,28 +156,31 @@ int main()
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f};
float m1[16];
float tm[16];
for (int k = 0; k < 16; k++) {
tm[k] = bias[k]*light_proj_matrix[k]*light_view_matrix[k];
}
float v1[4] = {tm[0], tm[4], tm[8], tm[12]};
mult_matrix(bias, light_proj_matrix, m1);
mult_matrix(m1, light_view_matrix, tm);
float v1[4] = {tm[0], tm[1], tm[2], tm[3]};
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_S, GL_EYE_PLANE, v1);
glEnable(GL_TEXTURE_GEN_S);
float v2[4] = {tm[1], tm[5], tm[9], tm[13]};
float v2[4] = {tm[4], tm[5], tm[6], tm[7]};
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_T, GL_EYE_PLANE, v2);
glEnable(GL_TEXTURE_GEN_T);
float v3[4] = {tm[2], tm[6], tm[10], tm[14]};
float v3[4] = {tm[8], tm[9], tm[10], tm[11]};
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_R, GL_EYE_PLANE, v3);
glEnable(GL_TEXTURE_GEN_R);
float v4[4] = {tm[3], tm[7], tm[11], tm[15]};
float v4[4] = {tm[12], tm[13], tm[14], tm[15]};
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_Q, GL_EYE_PLANE, v4);
glEnable(GL_TEXTURE_GEN_Q);
glBindTexture(GL_TEXTURE_2D, shadowmap_texture);
glEnable(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
@ -188,12 +199,25 @@ int main()
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_GEN_Q);
glDisable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-1.0f, 1.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glFinish();
////////////
vec3f pos = app.camera.position;
// vec3f dir = get_camera_dir_vec3f(&app.camera);
@ -209,7 +233,7 @@ int main()
//printf("lkat pos x: %f y: %f z: %f\n", pos.x+5*dir.x, pos.y+5*dir.y, pos.z+5*dir.z);
printf("camera x: %f y: %f z: %f\n", pos.x, pos.y, pos.z);
//printf("dir x: %f y: %f z: %f\n", dir.x, dir.y, dir.z);
//printf("dird x: %f y: %f z: %f\n", app.camera.rotation.x, app.camera.rotation.y, app.camera.rotation.z);
printf("dird x: %f y: %f z: %f\n", app.camera.rotation.x, app.camera.rotation.y, app.camera.rotation.z);
}
return 0;

View File

@ -15,11 +15,25 @@ bool is_oob(int i, int min, int max)
return false;
}
void mult_matrix(float m1[16], float m2[16])
void mult_matrix(const float m1[16], const float m2[16], float mo[16])
{
mo[0] = m1[0]*m2[0]+m1[1]*m2[4]+m1[2]*m2[8]+m1[3]*m2[12];
mo[1] = m1[0]*m2[1]+m1[1]*m2[5]+m1[2]*m2[9]+m1[3]*m2[13];
mo[2] = m1[0]*m2[2]+m1[1]*m2[6]+m1[2]*m2[10]+m1[3]*m2[14];
mo[3] = m1[0]*m2[3]+m1[1]*m2[7]+m1[2]*m2[11]+m1[3]*m2[15];
mo[4] = m1[4]*m2[0]+m1[5]*m2[4]+m1[6]*m2[8]+m1[7]*m2[12];
mo[5] = m1[4]*m2[1]+m1[5]*m2[5]+m1[6]*m2[9]+m1[7]*m2[13];
mo[6] = m1[4]*m2[2]+m1[5]*m2[6]+m1[6]*m2[10]+m1[7]*m2[14];
mo[7] = m1[4]*m2[3]+m1[5]*m2[7]+m1[6]*m2[11]+m1[7]*m2[15];
mo[8] = m1[8]*m2[0]+m1[9]*m2[4]+m1[10]*m2[8]+m1[11]*m2[12];
mo[9] = m1[8]*m2[1]+m1[9]*m2[5]+m1[10]*m2[9]+m1[11]*m2[13];
mo[10] = m1[8]*m2[2]+m1[9]*m2[6]+m1[10]*m2[10]+m1[11]*m2[14];
mo[11] = m1[8]*m2[3]+m1[9]*m2[7]+m1[10]*m2[11]+m1[11]*m2[15];
mo[12] = m1[12]*m2[0]+m1[13]*m2[4]+m1[14]*m2[8]+m1[15]*m2[12];
mo[13] = m1[12]*m2[1]+m1[13]*m2[5]+m1[14]*m2[9]+m1[15]*m2[13];
mo[14] = m1[12]*m2[2]+m1[13]*m2[6]+m1[14]*m2[10]+m1[15]*m2[14];
mo[15] = m1[12]*m2[3]+m1[13]*m2[7]+m1[14]*m2[11]+m1[15]*m2[15];
}
bool matrix_inverse(const float m[16], float invOut[16])
{