omicron/src/cube.c

473 lines
15 KiB
C

#include <math.h>
#include "cube.h"
#include "item.h"
#include "matrix.h"
#include "util.h"
void make_cube_faces(
float *data, float ao[6][4], float light[6][4],
int left, int right, int top, int bottom, int front, int back,
int wleft, int wright, int wtop, int wbottom, int wfront, int wback,
float x, float y, float z, float scale, NonCubeType noncube)
{
/*static const float positions[6][4][3] = {
{{-1, -1, -1}, {-1, -1, +1}, {-1, +1, -1}, {-1, +1, +1}},
{{+1, -1, -1}, {+1, -1, +1}, {+1, +1, -1}, {+1, +1, +1}},
{{-1, +1, -1}, {-1, +1, +1}, {+1, +1, -1}, {+1, +1, +1}},
{{-1, -1, -1}, {-1, -1, +1}, {+1, -1, -1}, {+1, -1, +1}},
{{-1, -1, -1}, {-1, +1, -1}, {+1, -1, -1}, {+1, +1, -1}},
{{-1, -1, +1}, {-1, +1, +1}, {+1, -1, +1}, {+1, +1, +1}}
};*/
static const float positions[6][4][3] = {
{{-1, -1, -1}, {-1, -1, +1}, {-1, +1, -1}, {-1, +1, +1}},
{{+1, -1, -1}, {+1, -1, +1}, {+1, +1, -1}, {+1, +1, +1}},
{{-1, +1, -1}, {-1, +1, +1}, {+1, +1, -1}, {+1, +1, +1}},
{{-1, -1, -1}, {-1, -1, +1}, {+1, -1, -1}, {+1, -1, +1}},
{{-1, -1, -1}, {-1, +1, -1}, {+1, -1, -1}, {+1, +1, -1}},
{{-1, -1, +1}, {-1, +1, +1}, {+1, -1, +1}, {+1, +1, +1}}
};
static const float normals[6][3] = {
{-1, 0, 0},
{+1, 0, 0},
{0, +1, 0},
{0, -1, 0},
{0, 0, -1},
{0, 0, +1}
};
static const float uvs[6][4][2] = {
{{0, 0}, {1, 0}, {0, 1}, {1, 1}},
{{1, 0}, {0, 0}, {1, 1}, {0, 1}},
{{0, 1}, {0, 0}, {1, 1}, {1, 0}},
{{0, 0}, {0, 1}, {1, 0}, {1, 1}},
{{0, 0}, {0, 1}, {1, 0}, {1, 1}},
{{1, 0}, {1, 1}, {0, 0}, {0, 1}}
};
static const float indices[6][6] = {
{0, 3, 2, 0, 1, 3},
{0, 3, 1, 0, 2, 3},
{0, 3, 2, 0, 1, 3},
{0, 3, 1, 0, 2, 3},
{0, 3, 2, 0, 1, 3},
{0, 3, 1, 0, 2, 3}
};
static const float flipped[6][6] = {
{0, 1, 2, 1, 3, 2},
{0, 2, 1, 2, 3, 1},
{0, 1, 2, 1, 3, 2},
{0, 2, 1, 2, 3, 1},
{0, 1, 2, 1, 3, 2},
{0, 2, 1, 2, 3, 1}
};
float *d = data;
float s = 0.0625;
float a = 0 + 1 / 2048.0;
float b = s - 1 / 2048.0;
int faces[6] = {left, right, top, bottom, front, back};
int tiles[6] = {wleft, wright, wtop, wbottom, wfront, wback};
for (int i = 0; i < 6; i++) {
if (faces[i] == 0) {
continue;
}
float du = (tiles[i] % 16) * s;
float dv = (tiles[i] / 16) * s;
int flip = ao[i][0] + ao[i][3] > ao[i][1] + ao[i][2];
float y_multiplier = (noncube == NonCubeType_SLAB_LOWER) ? 0.0f : 1.0f;
for (int v = 0; v < 6; v++) {
int j = flip ? flipped[i][v] : indices[i][v];
*(d++) = x + scale * positions[i][j][0];
//The origin of the cube is its center.
//If we are rendering a slab, the top vertices of the cube are not multiplied by the offsets,
// so that the top of the slab is the origin, at the center. This makes slabs half-height.
//Only the vertices on the top should be 0, or the slab would be a paperlike
// horizontal billboard. If the y position is positive, we are above the XZ plane of the
// cube and are about to determine the top vertices.
if (noncube == NonCubeType_SLAB_LOWER && positions[i][j][1] > 0) {
*(d++) = y;
}
else {
*(d++) = y + scale * positions[i][j][1];
}
*(d++) = z + scale * positions[i][j][2];
*(d++) = normals[i][0];
*(d++) = normals[i][1];
*(d++) = normals[i][2];
*(d++) = du + (uvs[i][j][0] ? b : a);
//If we have have a slab, are rendering the top vertices, and are on the side --
// (i == 2) and (i == 3) are for the top and bottom, see faces and tiles arrays above --
// we must subtract half a texture tile to only use the lower half of the texture.
// Otherwise, the texture of a full block will be sqeezed onto the slab.
if (positions[i][j][1] > 0 && i != 2 && i != 3 && noncube == NonCubeType_SLAB_LOWER) {
*(d++) = (dv - (1.0f / 32.0f)) + (uvs[i][j][1] ? b : a);
}
else {
*(d++) = dv + (uvs[i][j][1] ? b : a);
}
*(d++) = ao[i][j];
*(d++) = light[i][j];
}
}
}
void make_cube(
float *data, float ao[6][4], float light[6][4],
int left, int right, int top, int bottom, int front, int back,
float x, float y, float z, float n, int w)
{
int wleft = blocks[w][0];
int wright = blocks[w][1];
int wtop = blocks[w][2];
int wbottom = blocks[w][3];
int wfront = blocks[w][4];
int wback = blocks[w][5];
make_cube_faces(
data, ao, light,
left, right, top, bottom, front, back,
wleft, wright, wtop, wbottom, wfront, wback,
//left, right, top, bottom, front, back,
x, y, z, n, noncube_type(w));
}
void make_plant(
float *data, float ao, float light,
float px, float py, float pz, float n, int w, float rotation)
{
static const float positions[4][4][3] = {
{{ 0, -1, -1}, { 0, -1, +1}, { 0, +1, -1}, { 0, +1, +1}},
{{ 0, -1, -1}, { 0, -1, +1}, { 0, +1, -1}, { 0, +1, +1}},
{{-1, -1, 0}, {-1, +1, 0}, {+1, -1, 0}, {+1, +1, 0}},
{{-1, -1, 0}, {-1, +1, 0}, {+1, -1, 0}, {+1, +1, 0}}
};
static const float normals[4][3] = {
{-1, 0, 0},
{+1, 0, 0},
{0, 0, -1},
{0, 0, +1}
};
static const float uvs[4][4][2] = {
{{0, 0}, {1, 0}, {0, 1}, {1, 1}},
{{1, 0}, {0, 0}, {1, 1}, {0, 1}},
{{0, 0}, {0, 1}, {1, 0}, {1, 1}},
{{1, 0}, {1, 1}, {0, 0}, {0, 1}}
};
static const float indices[4][6] = {
{0, 3, 2, 0, 1, 3},
{0, 3, 1, 0, 2, 3},
{0, 3, 2, 0, 1, 3},
{0, 3, 1, 0, 2, 3}
};
float *d = data;
float s = 0.0625;
float a = 0;
float b = s;
float du = (plants[w] % 16) * s;
float dv = (plants[w] / 16) * s;
for (int i = 0; i < 4; i++) {
for (int v = 0; v < 6; v++) {
int j = indices[i][v];
*(d++) = n * positions[i][j][0];
*(d++) = n * positions[i][j][1];
*(d++) = n * positions[i][j][2];
*(d++) = normals[i][0];
*(d++) = normals[i][1];
*(d++) = normals[i][2];
*(d++) = du + (uvs[i][j][0] ? b : a);
*(d++) = dv + (uvs[i][j][1] ? b : a);
*(d++) = ao;
*(d++) = light;
}
}
float ma[16];
float mb[16];
mat_identity(ma);
mat_rotate(mb, 0, 1, 0, RADIANS(rotation));
mat_multiply(ma, mb, ma);
mat_apply(data, ma, 24, 3, 10);
mat_translate(mb, px, py, pz);
mat_multiply(ma, mb, ma);
mat_apply(data, ma, 24, 0, 10);
}
// Player model
void make_player(
float *data,
float x, float y, float z, float rx, float ry)
{
float ao[6][4] = {0};
float light[6][4] = {
{0.8, 0.8, 0.8, 0.8},
{0.8, 0.8, 0.8, 0.8},
{0.8, 0.8, 0.8, 0.8},
{0.8, 0.8, 0.8, 0.8},
{0.8, 0.8, 0.8, 0.8},
{0.8, 0.8, 0.8, 0.8}
};
make_cube_faces(
data, ao, light,
1, 1, 1, 1, 1, 1,
226, 224, 241, 209, 225, 227,
0, 0, 0, 0.4, NonCubeType_NOT_NONCUBE);
float ma[16];
float mb[16];
mat_identity(ma);
mat_rotate(mb, 0, 1, 0, rx);
mat_multiply(ma, mb, ma);
mat_rotate(mb, cosf(rx), 0, sinf(rx), -ry);
mat_multiply(ma, mb, ma);
mat_apply(data, ma, 36, 3, 10);
mat_translate(mb, x, y, z);
mat_multiply(ma, mb, ma);
mat_apply(data, ma, 36, 0, 10);
}
void make_cube_wireframe(float *data, float x, float y, float z, float n) {
static const float positions[8][3] = {
{-1, -1, -1},
{-1, -1, +1},
{-1, +1, -1},
{-1, +1, +1},
{+1, -1, -1},
{+1, -1, +1},
{+1, +1, -1},
{+1, +1, +1}
};
static const int indices[24] = {
0, 1, 0, 2, 0, 4, 1, 3,
1, 5, 2, 3, 2, 6, 3, 7,
4, 5, 4, 6, 5, 7, 6, 7
};
float *d = data;
for (int i = 0; i < 24; i++) {
int j = indices[i];
*(d++) = x + n * positions[j][0];
*(d++) = y + n * positions[j][1];
*(d++) = z + n * positions[j][2];
}
}
void make_character(
float *data,
float x, float y, float n, float m, char c)
{
float *d = data;
float s = 0.0625;
float a = s;
float b = s * 2;
int w = c - 32;
float du = (w % 16) * a;
float dv = 1 - (w / 16) * b - b;
*(d++) = x - n; *(d++) = y - m;
*(d++) = du + 0; *(d++) = dv;
*(d++) = x + n; *(d++) = y - m;
*(d++) = du + a; *(d++) = dv;
*(d++) = x + n; *(d++) = y + m;
*(d++) = du + a; *(d++) = dv + b;
*(d++) = x - n; *(d++) = y - m;
*(d++) = du + 0; *(d++) = dv;
*(d++) = x + n; *(d++) = y + m;
*(d++) = du + a; *(d++) = dv + b;
*(d++) = x - n; *(d++) = y + m;
*(d++) = du + 0; *(d++) = dv + b;
}
void make_ui_quad(
float *data,
float x, float y, float n, float m, char spritesheet_index)
{
float *d = data;
float s = 0.0625;
float a = s;
float b = s;
int w = spritesheet_index - 32;
float du = (w % 16) * a;
float dv = 1 - (w / 16) * b - b;
*(d++) = x - n; *(d++) = y - m;
*(d++) = du + 0; *(d++) = dv;
*(d++) = x + n; *(d++) = y - m;
*(d++) = du + a; *(d++) = dv;
*(d++) = x + n; *(d++) = y + m;
*(d++) = du + a; *(d++) = dv + b;
*(d++) = x - n; *(d++) = y - m;
*(d++) = du + 0; *(d++) = dv;
*(d++) = x + n; *(d++) = y + m;
*(d++) = du + a; *(d++) = dv + b;
*(d++) = x - n; *(d++) = y + m;
*(d++) = du + 0; *(d++) = dv + b;
}
void make_logo_quad(
float *data,
float x, float y, float n, float m, char spritesheet_index)
{
float *d = data;
float s = 0.0625*16; // changes the size of pixel array
float a = s;
float b = s;
int w = spritesheet_index - 32;
float du = (w % 16) * a;
float dv = 1 - (w / 16) * b - b;
*(d++) = x - n; *(d++) = y - m;
*(d++) = du + 0; *(d++) = dv;
*(d++) = x + n; *(d++) = y - m;
*(d++) = du + a; *(d++) = dv;
*(d++) = x + n; *(d++) = y + m;
*(d++) = du + a; *(d++) = dv + b;
*(d++) = x - n; *(d++) = y - m;
*(d++) = du + 0; *(d++) = dv;
*(d++) = x + n; *(d++) = y + m;
*(d++) = du + a; *(d++) = dv + b;
*(d++) = x - n; *(d++) = y + m;
*(d++) = du + 0; *(d++) = dv + b;
}
void make_character_3d(
float *data, float x, float y, float z, float n, int face, char c)
{
static const float positions[8][6][3] = {
{{0, -2, -1}, {0, +2, +1}, {0, +2, -1},
{0, -2, -1}, {0, -2, +1}, {0, +2, +1}},
{{0, -2, -1}, {0, +2, +1}, {0, -2, +1},
{0, -2, -1}, {0, +2, -1}, {0, +2, +1}},
{{-1, -2, 0}, {+1, +2, 0}, {+1, -2, 0},
{-1, -2, 0}, {-1, +2, 0}, {+1, +2, 0}},
{{-1, -2, 0}, {+1, -2, 0}, {+1, +2, 0},
{-1, -2, 0}, {+1, +2, 0}, {-1, +2, 0}},
{{-1, 0, +2}, {+1, 0, +2}, {+1, 0, -2},
{-1, 0, +2}, {+1, 0, -2}, {-1, 0, -2}},
{{-2, 0, +1}, {+2, 0, -1}, {-2, 0, -1},
{-2, 0, +1}, {+2, 0, +1}, {+2, 0, -1}},
{{+1, 0, +2}, {-1, 0, -2}, {-1, 0, +2},
{+1, 0, +2}, {+1, 0, -2}, {-1, 0, -2}},
{{+2, 0, -1}, {-2, 0, +1}, {+2, 0, +1},
{+2, 0, -1}, {-2, 0, -1}, {-2, 0, +1}}
};
static const float uvs[8][6][2] = {
{{0, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}, {1, 1}},
{{1, 0}, {0, 1}, {0, 0}, {1, 0}, {1, 1}, {0, 1}},
{{1, 0}, {0, 1}, {0, 0}, {1, 0}, {1, 1}, {0, 1}},
{{0, 0}, {1, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 1}},
{{0, 0}, {1, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 1}},
{{0, 1}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}},
{{0, 1}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}},
{{0, 1}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}
};
static const float offsets[8][3] = {
{-1, 0, 0}, {+1, 0, 0}, {0, 0, -1}, {0, 0, +1},
{0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
};
float *d = data;
float s = 0.0625;
float pu = s / 5;
float pv = s / 2.5;
float u1 = pu;
float v1 = pv;
float u2 = s - pu;
float v2 = s * 2 - pv;
float p = 0.5;
int w = c - 32;
float du = (w % 16) * s;
float dv = 1 - (w / 16 + 1) * s * 2;
x += p * offsets[face][0];
y += p * offsets[face][1];
z += p * offsets[face][2];
for (int i = 0; i < 6; i++) {
*(d++) = x + n * positions[face][i][0];
*(d++) = y + n * positions[face][i][1];
*(d++) = z + n * positions[face][i][2];
*(d++) = du + (uvs[face][i][0] ? u2 : u1);
*(d++) = dv + (uvs[face][i][1] ? v2 : v1);
}
}
int _make_sphere(
float *data, float r, int detail,
float *a, float *b, float *c,
float *ta, float *tb, float *tc)
{
if (detail == 0) {
float *d = data;
*(d++) = a[0] * r; *(d++) = a[1] * r; *(d++) = a[2] * r;
*(d++) = a[0]; *(d++) = a[1]; *(d++) = a[2];
*(d++) = ta[0]; *(d++) = ta[1];
*(d++) = b[0] * r; *(d++) = b[1] * r; *(d++) = b[2] * r;
*(d++) = b[0]; *(d++) = b[1]; *(d++) = b[2];
*(d++) = tb[0]; *(d++) = tb[1];
*(d++) = c[0] * r; *(d++) = c[1] * r; *(d++) = c[2] * r;
*(d++) = c[0]; *(d++) = c[1]; *(d++) = c[2];
*(d++) = tc[0]; *(d++) = tc[1];
return 1;
}
else {
float ab[3], ac[3], bc[3];
for (int i = 0; i < 3; i++) {
ab[i] = (a[i] + b[i]) / 2;
ac[i] = (a[i] + c[i]) / 2;
bc[i] = (b[i] + c[i]) / 2;
}
normalize(ab + 0, ab + 1, ab + 2);
normalize(ac + 0, ac + 1, ac + 2);
normalize(bc + 0, bc + 1, bc + 2);
float tab[2], tac[2], tbc[2];
tab[0] = 0; tab[1] = 1 - acosf(ab[1]) / PI;
tac[0] = 0; tac[1] = 1 - acosf(ac[1]) / PI;
tbc[0] = 0; tbc[1] = 1 - acosf(bc[1]) / PI;
int total = 0;
int n;
n = _make_sphere(data, r, detail - 1, a, ab, ac, ta, tab, tac);
total += n; data += n * 24;
n = _make_sphere(data, r, detail - 1, b, bc, ab, tb, tbc, tab);
total += n; data += n * 24;
n = _make_sphere(data, r, detail - 1, c, ac, bc, tc, tac, tbc);
total += n; data += n * 24;
n = _make_sphere(data, r, detail - 1, ab, bc, ac, tab, tbc, tac);
total += n; data += n * 24;
return total;
}
}
void make_sphere(float *data, float r, int detail) {
// detail, triangles, floats
// 0, 8, 192
// 1, 32, 768
// 2, 128, 3072
// 3, 512, 12288
// 4, 2048, 49152
// 5, 8192, 196608
// 6, 32768, 786432
// 7, 131072, 3145728
static int indices[8][3] = {
{4, 3, 0}, {1, 4, 0},
{3, 4, 5}, {4, 1, 5},
{0, 3, 2}, {0, 2, 1},
{5, 2, 3}, {5, 1, 2}
};
static float positions[6][3] = {
{ 0, 0,-1}, { 1, 0, 0},
{ 0,-1, 0}, {-1, 0, 0},
{ 0, 1, 0}, { 0, 0, 1}
};
static float uvs[6][3] = {
{0, 0.5}, {0, 0.5},
{0, 0}, {0, 0.5},
{0, 1}, {0, 0.5}
};
int total = 0;
for (int i = 0; i < 8; i++) {
int n = _make_sphere(
data, r, detail,
positions[indices[i][0]],
positions[indices[i][1]],
positions[indices[i][2]],
uvs[indices[i][0]],
uvs[indices[i][1]],
uvs[indices[i][2]]);
total += n; data += n * 24;
}
}