#include "Model.h" #include #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]); }