Files
biomed/Model.cpp
2026-02-12 10:51:02 +01:00

616 lines
16 KiB
C++

#include "Model.h"
#include <SDL2/SDL_opengl.h>
#include "renderer.h"
#include "screen.h"
#include "Editor.h"
const float vb[8][3] = {{-0.5f, 0.5f, -0.5f},{-0.5f, 0.5f, 0.5f},{0.5f, 0.5f, 0.5f},{0.5f, 0.5f, -0.5f},{-0.5f, -0.5f, -0.5f},{-0.5f, -0.5f, 0.5f},{0.5f, -0.5f, 0.5f},{0.5f, -0.5f, -0.5f}};
const char fb[6][4] = {{1, 5, 6, 2},{3, 7, 4, 0},{0, 1, 2, 3},{7, 6, 5, 4},{2, 6, 7, 3},{0, 4, 5, 1}};
const char nb[6][3] = {{0, 0, 1},{0, 0, -1},{0, 1, 0},{0, -1, 0},{1, 0, 0},{-1, 0, 0}};
//const char t[5][2] = {{0, 1},{0, 3},{2, 3},{2, 1},{0, 1}};
Model model;
#pragma mark Model::File Ops
void Model::Save(const char* filename)
{
}
void Model::Load(const char* filename)
{
}
#pragma mark Model::Calculations
const Vector3 Model::GetCurrentValue(const int& cube, const AnimKey::Type& type)
{
int currentAnim = 0;
int i1 = -1;
int i2 = -1;
const Anim& anim = anims[currentAnim];
for (int i = 0; i < anim.numKeys; i++) {
const AnimKey& k = anim.keys[i];
if (k.cube == cube && k.type == type) {
if (k.t == Editor::t) {
i1 = i2 = i;
} else if (k.t < Editor::t) {
i1 = i;
} else if (k.t > Editor::t) {
if (i1 == -1) {
i1 = i2 = i;
break;
} else {
i2 = i;
break;
}
}
}
}
if (i1 == -1) {
if (type == AnimKey::Type::Rotation) {
return Vector3(0, 0, 0);
} else if (type == AnimKey::Type::Position) {
return cubes[cube].position;
} else {
return cubes[cube].size;
}
}
if (i1 == i2 or i2 == -1) return anim.keys[i1].value;
// MUCH OBFUSCATED, SO DEBUGGABLE
return anim.keys[i1].value + ((anim.keys[i2].value - anim.keys[i1].value) * (Editor::t - anim.keys[i1].t)/(anim.keys[i2].t - anim.keys[i1].t));
}
void Model::GetCurrentTransformation(const int& cube, Vector3& position, Vector3& rotation, Vector3& scale)
{
position = GetCurrentValue(cube, AnimKey::Type::Position);
rotation = GetCurrentValue(cube, AnimKey::Type::Rotation);
scale = GetCurrentValue(cube, AnimKey::Type::Scale);
}
void Model::Calculate()
{
for (int i = 0; i < numCubes; i++) {
Vector3 position, rotation, scale, pivot;
GetCurrentTransformation(i, position, rotation, scale);
pivot = cubes[i].pivot;
localMatrix[i].identity();
localMatrix[i].translate(pivot);
localMatrix[i].scale(scale.x, scale.y, scale.z);
localMatrix[i].rotateX(rotation.x);
localMatrix[i].rotateY(rotation.y);
localMatrix[i].rotateZ(rotation.z);
localMatrix[i].translate(position-pivot);
}
for (int i = 0; i < numCubes; i++) {
finalMatrix[i] = localMatrix[i];
int parent = cubes[i].parent;
while (parent != -1) {
finalMatrix[i] *= localMatrix[parent];
parent = cubes[parent].parent;
}
}
}
#pragma mark Model::Draw
void Model::DrawSolid()
{
glColor4ub(255, 255, 255, 255);
for (int c = 0; c < numCubes; c++) {
if (cubes[c].selected) continue;
const Cube& cube = cubes[c];
glPushMatrix();
glBegin(GL_QUADS);
for (int f = 0; f<6; f++) {
if (cube.faces[f].selected) continue;
for (int i = 0; i < 4; i++) {
glNormal3f(nb[f][0], nb[f][1], nb[f][2]);
glTexCoord2f(float(cube.faces[f].uv[i].x)/32.0f, float(cube.faces[f].uv[i].y)/32.0f);
glVertex3f(cube.position[0]+vb[fb[f][i]][0]*cube.size[0], cube.position[1]+vb[fb[f][i]][1]*cube.size[1], cube.position[2]+vb[fb[f][i]][2]*cube.size[2]);
}
}
glEnd();
glPopMatrix();
}
glColor4ub(255, 0, 0, 255);
for (int c = 0; c < numCubes; c++) {
const Cube& cube = cubes[c];
glPushMatrix();
//glRotatef(cube.rot[0], 1, 0, 0);
//glRotatef(cube.rot[1], 0, 1, 0);
//glRotatef(cube.rot[2], 0, 0, 1);
glBegin(GL_QUADS);
for (int f = 0; f<6; f++) {
if (!cube.selected and !cube.faces[f].selected) continue;
for (int i = 0; i < 4; i++) {
glNormal3f(nb[f][0], nb[f][1], nb[f][2]);
glTexCoord2f(float(cube.faces[f].uv[i].x)/32.0f, float(cube.faces[f].uv[i].y)/32.0f);
glVertex3f(cube.position[0]+vb[fb[f][i]][0]*cube.size[0], cube.position[1]+vb[fb[f][i]][1]*cube.size[1], cube.position[2]+vb[fb[f][i]][2]*cube.size[2]);
}
}
glEnd();
glPopMatrix();
}
}
void Model::DrawWire()
{
Renderer::SetState(RENDER_DEPTH);
glCullFace(GL_FRONT);
glDepthMask(GL_FALSE);
glColor4ub(128, 128, 128, 255);
for (int c = 0; c < numCubes; c++) {
if (cubes[c].selected) continue;
const Cube& cube = cubes[c];
glPushMatrix();
//glRotatef(cube.rot[0], 1, 0, 0);
//glRotatef(cube.rot[1], 0, 1, 0);
//glRotatef(cube.rot[2], 0, 0, 1);
glBegin(GL_QUADS);
for (int f = 0; f<6; f++) {
if (cube.faces[f].selected) continue;
for (int i = 0; i < 4; i++) {
glNormal3f(nb[f][0], nb[f][1], nb[f][2]);
glVertex3f(cube.position[0]+vb[fb[f][i]][0]*cube.size[0], cube.position[1]+vb[fb[f][i]][1]*cube.size[1], cube.position[2]+vb[fb[f][i]][2]*cube.size[2]);
}
}
glEnd();
glPopMatrix();
}
glColor4ub(128, 0, 0, 255);
for (int c = 0; c < numCubes; c++) {
const Cube& cube = cubes[c];
glPushMatrix();
//glRotatef(cube.rot[0], 1, 0, 0);
//glRotatef(cube.rot[1], 0, 1, 0);
//glRotatef(cube.rot[2], 0, 0, 1);
glBegin(GL_QUADS);
for (int f = 0; f<6; f++) {
if (!cube.selected and !cube.faces[f].selected) continue;
for (int i = 0; i < 4; i++) {
glNormal3f(nb[f][0], nb[f][1], nb[f][2]);
glVertex3f(cube.position[0]+vb[fb[f][i]][0]*cube.size[0], cube.position[1]+vb[fb[f][i]][1]*cube.size[1], cube.position[2]+vb[fb[f][i]][2]*cube.size[2]);
}
}
glEnd();
glPopMatrix();
}
glDepthMask(GL_TRUE);
glCullFace(GL_BACK);
glColor4ub(255, 255, 255, 255);
for (int c = 0; c < numCubes; c++) {
if (cubes[c].selected) continue;
const Cube& cube = cubes[c];
glPushMatrix();
//glRotatef(cube.rot[0], 1, 0, 0);
//glRotatef(cube.rot[1], 0, 1, 0);
//glRotatef(cube.rot[2], 0, 0, 1);
glBegin(GL_QUADS);
for (int f = 0; f<6; f++) {
if (cube.faces[f].selected) continue;
for (int i = 0; i < 4; i++) {
glNormal3f(nb[f][0], nb[f][1], nb[f][2]);
glVertex3f(cube.position[0]+vb[fb[f][i]][0]*cube.size[0], cube.position[1]+vb[fb[f][i]][1]*cube.size[1], cube.position[2]+vb[fb[f][i]][2]*cube.size[2]);
}
}
glEnd();
glPopMatrix();
}
glColor4f(1, 0, 0, 1);
for (int c = 0; c < numCubes; c++) {
const Cube& cube = cubes[c];
glPushMatrix();
//glRotatef(cube.rot[0], 1, 0, 0);
//glRotatef(cube.rot[1], 0, 1, 0);
//glRotatef(cube.rot[2], 0, 0, 1);
glBegin(GL_QUADS);
for (int f = 0; f<6; f++) {
if (!cube.selected and !cube.faces[f].selected) continue;
for (int i = 0; i < 4; i++) {
glNormal3f(nb[f][0], nb[f][1], nb[f][2]);
glVertex3f(cube.position[0]+vb[fb[f][i]][0]*cube.size[0], cube.position[1]+vb[fb[f][i]][1]*cube.size[1], cube.position[2]+vb[fb[f][i]][2]*cube.size[2]);
}
}
glEnd();
glPopMatrix();
}
}
void Model::DrawUV()
{
glColor4ub(255, 255, 255, 255);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-16.0f, -16.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-16.0f, 16.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(16.0f, 16.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(16.0f, -16.0f);
glEnd();
Renderer::SetState(RENDER_NONE);
glColor4ub(255, 255, 255, 255);
for (int c = 0; c < numCubes; c++) {
if (cubes[c].selected) continue;
const Cube& cube = cubes[c];
glBegin(GL_QUADS);
for (int f = 0; f<6; f++) {
if (cube.faces[f].selected) continue;
const CubeFace& face = cube.faces[f];
for (int i = 0; i < 4; i++) {
glVertex2f(-(16-face.uv[i].x), -(16-face.uv[i].y));
}
}
glEnd();
}
glColor4ub(255, 0, 0, 255);
for (int c = 0; c < numCubes; c++) {
const Cube& cube = cubes[c];
glBegin(GL_QUADS);
for (int f = 0; f<6; f++) {
if (!cube.selected and !cube.faces[f].selected) continue;
const CubeFace& face = cube.faces[f];
for (int i = 0; i < 4; i++) {
glVertex2f(-(16-face.uv[i].x), -(16-face.uv[i].y));
}
}
glEnd();
}
}
Color Model::Pick(const float x, const float y)
{
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int c = 0; c < numCubes; c++) {
const Cube& cube = cubes[c];
glPushMatrix();
glBegin(GL_QUADS);
for (int f = 0; f < 6; f++) {
for (int i = 0; i < 4; i++) {
glColor4ub(c, f, 0, 255);
//glNormal3f(nb[f][0], nb[f][1], nb[f][2]);
//glTexCoord2f(float(cube.faces[f].uv[i].x)/32.0f, float(cube.faces[f].uv[i].y)/32.0f);
glVertex3f(cube.position[0]+vb[fb[f][i]][0]*cube.size[0], cube.position[1]+vb[fb[f][i]][1]*cube.size[1], cube.position[2]+vb[fb[f][i]][2]*cube.size[2]);
}
}
glEnd();
glPopMatrix();
}
Color color;
glReadPixels(x, SCREEN_HEIGHT-y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color.r);
printf("PICK: %i, %i, %i, %i\n", color.r, color.g, color.b, color.a);
return color;
}
Color Model::PickPaint(const float x, const float y)
{
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int c = 0; c < numCubes; c++) {
const Cube& cube = cubes[c];
glPushMatrix();
glBegin(GL_QUADS);
for (int f = 0; f < 6; f++) {
for (int i = 0; i < 4; i++) {
uint8_t val = (c << 3) + f;
glColor4ub(val, cube.faces[f].uv[i].x*4, cube.faces[f].uv[i].y*4, 255);
//glNormal3f(nb[f][0], nb[f][1], nb[f][2]);
//glTexCoord2f(float(cube.faces[f].uv[i].x)/32.0f, float(cube.faces[f].uv[i].y)/32.0f);
glVertex3f(cube.position[0]+vb[fb[f][i]][0]*cube.size[0], cube.position[1]+vb[fb[f][i]][1]*cube.size[1], cube.position[2]+vb[fb[f][i]][2]*cube.size[2]);
}
}
glEnd();
glPopMatrix();
}
Color color;
glReadPixels(x, SCREEN_HEIGHT-y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color.r);
color /= 4;
printf("PICK: %i, %i, %i, %i\n", color.r, color.g, color.b, color.a);
return color;
}
Color Model::PickPixel(const float x, const float y)
{
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glColor4ub(0, 0, 255, 255);
glVertex2f(-16.0f, -16.0f);
glColor4ub(0, 128, 255, 255);
glVertex2f(-16.0f, 16.0f);
glColor4ub(128, 128, 255, 255);
glVertex2f(16.0f, 16.0f);
glColor4ub(128, 0, 255, 255);
glVertex2f(16.0f, -16.0f);
glEnd();
Color color;
glReadPixels(x, SCREEN_HEIGHT-y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color.r);
color /= 4;
printf("PICK: %i, %i, %i, %i\n", color.r, color.g, color.b, color.a);
return color;
}
#pragma mark Model::Cubes
int Model::GetSelectedCube()
{
int selected = -1;
for (int i = 0; i < numCubes; i++) {
if (cubes[i].selected) {
if (selected == -1) {
selected = i;
} else {
return -1;
}
}
}
return selected;
}
void Model::SelectCube(const uint8_t index, const bool inclusive)
{
if (not inclusive) SelectAllCubes(false);
if (index == 255) return;
assert(index < numCubes);
cubes[index].selected = not cubes[index].selected;
}
void Model::SelectAllCubes(const bool select)
{
for (int i = 0; i < numCubes; i++) {
cubes[i].selected = select;
}
}
void Model::NewCube()
{
if (numCubes == MAX_CUBES) return;
SelectAllCubes(false);
cubes[numCubes].name[0] = '\0';
cubes[numCubes].parent = -1;
cubes[numCubes].pivot = {0, 0, 0};
cubes[numCubes].position = {0, 0, 0};
cubes[numCubes].size = {8, 8, 8};
cubes[numCubes].selected = true;
for (int i = 0; i < 6; i++) {
cubes[numCubes].faces[i].selected = false;
cubes[numCubes].faces[i].uv[0] = {32, 32};
cubes[numCubes].faces[i].uv[1] = {32, 0};
cubes[numCubes].faces[i].uv[2] = {0, 0};
cubes[numCubes].faces[i].uv[3] = {0, 32};
}
numCubes++;
}
void Model::DeleteCube()
{
if (numCubes == 0) return;
int numCubesSelected = 0;
for (int i = 0; i < numCubes; i++) if (cubes[i].selected) numCubesSelected++;
if (numCubesSelected == 0) return;
for (int i = 0; i < numCubes; i++) {
if (cubes[i].selected) {
numCubes--;
if (numCubes > 1 and i != numCubes) {
cubes[i] = cubes[numCubes];
for (int c = 0; c < numCubes; c++) {
if (cubes[c].parent == i) {
cubes[c].parent = -1;
} else if (cubes[c].parent == numCubes) {
cubes[c].parent = i;
}
}
for (int a = 0; a < numAnims; a++) {
for (int k = 0; k < anims[a].numKeys; k++) {
if (anims[a].keys[k].cube == i) {
anims[a].numKeys--;
if (anims[a].numKeys > 1 and k != anims[a].numKeys) {
anims[a].keys[k] = anims[a].keys[anims[a].numKeys];
}
k--;
} else if (anims[a].keys[k].cube == anims[a].numKeys) {
anims[a].keys[k].cube = i;
}
}
}
i--;
}
}
}
}
void Model::DupCube()
{
int numCubesSelected = 0;
for (int i = 0; i < numCubes; i++) if (cubes[i].selected) numCubesSelected++;
if (numCubes+numCubesSelected > MAX_CUBES) return;
int numCubesBeforeEditing = numCubes;
for (int c = 0; c < numCubesBeforeEditing; c++) {
if (cubes[c].selected) {
cubes[c].selected = false;
cubes[numCubes].name[0] = '\0';
cubes[numCubes].parent = cubes[c].parent;
cubes[numCubes].pivot = cubes[c].pivot;
cubes[numCubes].position = cubes[c].position;
cubes[numCubes].size = cubes[c].size;
cubes[numCubes].selected = true;
for (int i = 0; i < 6; i++) {
cubes[numCubes].faces[i].selected = false;
cubes[numCubes].faces[i].uv[0] = cubes[c].faces[i].uv[0];
cubes[numCubes].faces[i].uv[1] = cubes[c].faces[i].uv[1];
cubes[numCubes].faces[i].uv[2] = cubes[c].faces[i].uv[2];
cubes[numCubes].faces[i].uv[3] = cubes[c].faces[i].uv[3];
}
numCubes++;
}
}
}
void Model::GrabCubes(const float x, const float y, const float z)
{
for (int i = 0; i < numCubes; i++) {
if (cubes[i].selected) {
cubes[i].position.x += x;
cubes[i].position.y += y;
cubes[i].position.z += z;
}
}
}
void Model::ScaleCubes(const float x, const float y, const float z)
{
for (int i = 0; i < numCubes; i++) {
if (cubes[i].selected) {
cubes[i].size.x += x;
cubes[i].size.y += y;
cubes[i].size.z += z;
}
}
}
#pragma mark Model::Faces
ivec2 Model::GetSelectedFace()
{
ivec2 selected {-1, -1};
for (int i = 0; i < numCubes; i++) {
for (int j = 0; j < 6; j++) {
if (cubes[i].faces[j].selected) {
if (selected.x == -1) {
selected = {i, j};
} else {
return {-1, -1};
}
}
}
}
return selected;
}
void Model::SelectFace(const uint8_t index, const uint8_t face, const bool inclusive)
{
if (not inclusive) SelectAllFaces(false);
if (index == 255) return;
assert(index < numCubes);
assert(face < 6);
cubes[index].faces[face].selected = not cubes[index].faces[face].selected;
}
void Model::SelectAllFaces(const bool select)
{
for (int i = 0; i < numCubes; i++) {
for (int j = 0; j < 6; j++) {
cubes[i].faces[j].selected = select;
}
}
}
void Model::ClearFaces()
{
for (int i = 0; i < numCubes; i++) {
for (int j = 0; j < 6; j++) {
if (cubes[i].faces[j].selected) cubes[i].faces[j].Clear();
}
}
}
void Model::RotateFaces()
{
for (int i = 0; i < numCubes; i++) {
for (int j = 0; j < 6; j++) {
if (cubes[i].faces[j].selected) cubes[i].faces[j].Rotate();
}
}
}
void Model::FlipHFaces()
{
for (int i = 0; i < numCubes; i++) {
for (int j = 0; j < 6; j++) {
if (cubes[i].faces[j].selected) cubes[i].faces[j].FlipH();
}
}
}
void Model::FlipVFaces()
{
for (int i = 0; i < numCubes; i++) {
for (int j = 0; j < 6; j++) {
if (cubes[i].faces[j].selected) cubes[i].faces[j].FlipV();
}
}
}
void Model::GrabFaces(const float x, const float y)
{
for (int i = 0; i < numCubes; i++) {
for (int j = 0; j < 6; j++) {
if (cubes[i].faces[j].selected) {
for (int k = 0; k < 4; k++) {
cubes[i].faces[j].uv[k].x += x;
cubes[i].faces[j].uv[k].y += y;
}
}
}
}
}
void Model::ScaleFaces(const float x, const float y)
{
for (int i = 0; i < numCubes; i++) {
for (int j = 0; j < 6; j++) {
if (cubes[i].faces[j].selected) {
cubes[i].faces[j].uv[0].x += x;
cubes[i].faces[j].uv[0].y += y;
cubes[i].faces[j].uv[1].x += x;
cubes[i].faces[j].uv[3].y += y;
}
}
}
}
#pragma mark CubeFace::Methods
void CubeFace::Clear()
{
uv[0] = uv[1] = {0,0};
uv[2] = uv[3] = {32,32};
}
void CubeFace::Rotate()
{
Swap(uv[0], uv[1]);
Swap(uv[1], uv[2]);
Swap(uv[2], uv[3]);
}
void CubeFace::FlipH()
{
Swap(uv[0], uv[3]);
Swap(uv[1], uv[2]);
}
void CubeFace::FlipV()
{
Swap(uv[0], uv[1]);
Swap(uv[2], uv[3]);
}