- First commit to gitea
This commit is contained in:
3
.gitignore
vendored
Executable file
3
.gitignore
vendored
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
build/*
|
||||||
|
biomed
|
||||||
|
biomed_debug
|
||||||
34
Editor.cpp
Normal file
34
Editor.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include "Editor.h"
|
||||||
|
#include "Model.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Editor
|
||||||
|
{
|
||||||
|
Mode mode {Mode::Cube};
|
||||||
|
State state {State::None};
|
||||||
|
char textureFilename[400] {"/<none>"};
|
||||||
|
unsigned texture {0};
|
||||||
|
char forcedAxis {-1};
|
||||||
|
float t {0.0f};
|
||||||
|
uint8_t bitmap[32*32*4] {255};
|
||||||
|
|
||||||
|
void SetMode(const Mode value)
|
||||||
|
{
|
||||||
|
mode = value;
|
||||||
|
if (mode == Mode::Cube) {
|
||||||
|
model.SelectAllFaces(false);
|
||||||
|
} else if (mode == Mode::Face) {
|
||||||
|
model.SelectAllCubes(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetState(const State value)
|
||||||
|
{
|
||||||
|
forcedAxis = -1;
|
||||||
|
if (state == value) {
|
||||||
|
state = State::None;
|
||||||
|
} else {
|
||||||
|
state = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Editor.h
Normal file
19
Editor.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Editor
|
||||||
|
{
|
||||||
|
enum class Mode { Face, Cube, Anim, Paint };
|
||||||
|
enum class State { None, Grab, Scale, Rotate, Pivot };
|
||||||
|
|
||||||
|
extern Mode mode;
|
||||||
|
extern State state;
|
||||||
|
extern char textureFilename[400];
|
||||||
|
extern unsigned texture;
|
||||||
|
extern char forcedAxis;
|
||||||
|
extern float t;
|
||||||
|
|
||||||
|
extern unsigned char bitmap[32*32*4];
|
||||||
|
|
||||||
|
void SetMode(const Mode value);
|
||||||
|
void SetState(const State value);
|
||||||
|
}
|
||||||
941
GUI.cpp
Normal file
941
GUI.cpp
Normal file
@@ -0,0 +1,941 @@
|
|||||||
|
#include "GUI.h"
|
||||||
|
|
||||||
|
#include "screen.h"
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
#include "GUIDraw.h"
|
||||||
|
#include "font.h"
|
||||||
|
#include "GUIMouse.h"
|
||||||
|
#include "GUIKeyboard.h"
|
||||||
|
#include "GUIViewport.h"
|
||||||
|
#include "Model.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "Editor.h"
|
||||||
|
//#include "GUIDialogs.h"
|
||||||
|
#include "texture.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
const Color winBack{30, 30, 30, 255};
|
||||||
|
const Color panelBack{53, 53, 60, 255};
|
||||||
|
const Color panel3DBack{40, 40, 43, 255};
|
||||||
|
const Color textBoxBack{61, 61, 66, 255};
|
||||||
|
const Color textBoxBorder{76, 77, 81, 255};
|
||||||
|
const Color buttonBack{63, 63, 70, 255};
|
||||||
|
const Color buttonPressed{62, 153, 247, 255};
|
||||||
|
|
||||||
|
namespace GUI
|
||||||
|
{
|
||||||
|
Font* font {nullptr};
|
||||||
|
float viewPos{0};
|
||||||
|
Vector4 viewSize{0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
||||||
|
Vector4 viewStack[10];
|
||||||
|
char viewStackPos{0};
|
||||||
|
int focus{-1};
|
||||||
|
int id{0};
|
||||||
|
bool dot{false};
|
||||||
|
bool empty{false};
|
||||||
|
|
||||||
|
bool menuVisible {false};
|
||||||
|
Vector2 menuPos {0, 0};
|
||||||
|
int subMenu{-1};
|
||||||
|
Vector2 subMenuPos {0, 0};
|
||||||
|
|
||||||
|
bool comboBoxVisible {false};
|
||||||
|
|
||||||
|
int selectedViewport {0};
|
||||||
|
bool zoomed {false};
|
||||||
|
|
||||||
|
Color currentColor {0, 0, 0, 255};
|
||||||
|
|
||||||
|
float a = 6.5f;
|
||||||
|
float b = 12.0f;
|
||||||
|
float c = 24.0f;
|
||||||
|
|
||||||
|
void ResetFocus()
|
||||||
|
{
|
||||||
|
focus = -1;
|
||||||
|
dot = false;
|
||||||
|
empty = false;
|
||||||
|
menuVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartSplitV(const float& value)
|
||||||
|
{
|
||||||
|
assert(viewStackPos < 10);
|
||||||
|
|
||||||
|
viewPos = 0;
|
||||||
|
viewStack[viewStackPos] = viewSize;
|
||||||
|
if (value > 0) {
|
||||||
|
viewStack[viewStackPos].w -= (value + 5);
|
||||||
|
viewSize.w = value;
|
||||||
|
} else {
|
||||||
|
viewStack[viewStackPos].w = -value;
|
||||||
|
viewSize.w -= (-value + 5);
|
||||||
|
}
|
||||||
|
viewStack[viewStackPos].y = viewSize.y + viewSize.w + 5;
|
||||||
|
viewStackPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartSplitH(const float& value)
|
||||||
|
{
|
||||||
|
assert(viewStackPos < 10);
|
||||||
|
|
||||||
|
viewPos = 0;
|
||||||
|
viewStack[viewStackPos] = viewSize;
|
||||||
|
if (value > 0) {
|
||||||
|
viewStack[viewStackPos].z -= (value + 5);
|
||||||
|
viewSize.z = value;
|
||||||
|
} else {
|
||||||
|
viewStack[viewStackPos].z = -value;
|
||||||
|
viewSize.z -= (-value + 5);
|
||||||
|
}
|
||||||
|
viewStack[viewStackPos].x = viewSize.x + viewSize.z + 5;
|
||||||
|
viewStackPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NextSplit()
|
||||||
|
{
|
||||||
|
assert(viewStackPos > 0);
|
||||||
|
viewPos = 0;
|
||||||
|
viewStackPos--;
|
||||||
|
viewSize = viewStack[viewStackPos];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawPanel()
|
||||||
|
{
|
||||||
|
viewPos = 0;
|
||||||
|
GUIDraw::FillRect(viewSize, panelBack);
|
||||||
|
viewSize.x += 10;
|
||||||
|
viewSize.y += 10;
|
||||||
|
viewSize.z -= 20;
|
||||||
|
viewSize.w -= 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Draw3DPanel(const int index)
|
||||||
|
{
|
||||||
|
if (not menuVisible and GUIMouse::position.inside(viewSize.GetPosition(), viewSize.GetSize())) {
|
||||||
|
selectedViewport = index;
|
||||||
|
if (GUIKeyboard::key == SDLK_z) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
zoomed = not zoomed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color color = (index == selectedViewport ? Color(128, 0, 0, 255) : panel3DBack);
|
||||||
|
viewPos = 0;
|
||||||
|
GUIDraw::FillRect(viewSize, color);
|
||||||
|
viewSize.x += 5;
|
||||||
|
viewSize.y += 5;
|
||||||
|
viewSize.z -= 10;
|
||||||
|
viewSize.w -= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTitle(const char* title)
|
||||||
|
{
|
||||||
|
viewPos = 0;
|
||||||
|
GUIDraw::FillRect({viewSize.x, viewSize.y, viewSize.z, 25}, winBack);
|
||||||
|
Vector2 textSize = font->GetSize(title);
|
||||||
|
const float pos = (viewSize.z-5) * 0.5f - textSize.x * 0.5f;
|
||||||
|
|
||||||
|
font->Print(viewSize.x+5+pos, viewSize.y+4, title);
|
||||||
|
|
||||||
|
viewSize.y += 30;
|
||||||
|
viewSize.w -= 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawCaption(const char* title)
|
||||||
|
{
|
||||||
|
viewPos = 0;
|
||||||
|
font->Print(viewSize.x, viewSize.y, title);
|
||||||
|
|
||||||
|
viewSize.y += 20;
|
||||||
|
viewSize.w -= 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool DrawComboBox(char* text)
|
||||||
|
{
|
||||||
|
bool retVal = false;
|
||||||
|
Vector4 rect {viewPos+viewSize.x, viewSize.y, viewSize.z, 22};
|
||||||
|
Color backColor = textBoxBack;
|
||||||
|
if (text != nullptr and GUIMouse::position.inside(rect.GetPosition(), rect.GetSize())) {
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
backColor = textBoxBorder;
|
||||||
|
}
|
||||||
|
GUIDraw::FillRect(rect, backColor);
|
||||||
|
GUIDraw::DrawRect(rect, textBoxBorder);
|
||||||
|
|
||||||
|
if (text != nullptr) font->Print(viewPos+viewSize.x+5, viewSize.y+2, text, 15);
|
||||||
|
|
||||||
|
viewPos = 0;
|
||||||
|
viewSize.y += 27;
|
||||||
|
viewSize.w -= 27;
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTextBox(char* text)
|
||||||
|
{
|
||||||
|
Vector4 rect {viewPos+viewSize.x, viewSize.y, viewSize.z, 22};
|
||||||
|
Color backColor = textBoxBack;
|
||||||
|
if (text != nullptr and GUIMouse::position.inside(rect.GetPosition(), rect.GetSize())) {
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
focus = id;
|
||||||
|
}
|
||||||
|
backColor = textBoxBorder;
|
||||||
|
}
|
||||||
|
GUIDraw::FillRect(rect, backColor);
|
||||||
|
GUIDraw::DrawRect(rect, textBoxBorder);
|
||||||
|
|
||||||
|
if (text != nullptr) {
|
||||||
|
char textColor = 15;
|
||||||
|
if (focus == id) {
|
||||||
|
textColor = 11;
|
||||||
|
if (GUIKeyboard::key >= SDLK_SPACE and GUIKeyboard::key <= SDLK_z) {
|
||||||
|
const size_t len = strlen(text);
|
||||||
|
if (len < 9) {
|
||||||
|
text[len] = GUIKeyboard::key;
|
||||||
|
text[len+1] = '\0';
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
}
|
||||||
|
} else if (GUIKeyboard::key == SDLK_BACKSPACE) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
const size_t len = strlen(text);
|
||||||
|
if (len > 0) text[len-1] = '\0';
|
||||||
|
} else if (GUIKeyboard::key == SDLK_RETURN) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
ResetFocus();
|
||||||
|
textColor = 15;
|
||||||
|
} else if (GUIKeyboard::key == SDLK_TAB) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
focus++;
|
||||||
|
textColor = 15;
|
||||||
|
}
|
||||||
|
if (focus == id) {
|
||||||
|
const Vector2 size = font->GetSize(text);
|
||||||
|
font->Print(size.x+viewPos+viewSize.x+5, viewSize.y+2, "_", textColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font->Print(viewPos+viewSize.x+5, viewSize.y+2, text, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
viewPos = 0;
|
||||||
|
viewSize.y += 27;
|
||||||
|
viewSize.w -= 27;
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawNumTextBox(float* number, const float size)
|
||||||
|
{
|
||||||
|
Vector4 rect {viewPos+viewSize.x, viewSize.y, size, 22};
|
||||||
|
Color backColor = textBoxBack;
|
||||||
|
|
||||||
|
if (number != nullptr and GUIMouse::position.inside(rect.GetPosition(), rect.GetSize())) {
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
dot = false;
|
||||||
|
empty = false;
|
||||||
|
focus = id;
|
||||||
|
}
|
||||||
|
backColor = textBoxBorder;
|
||||||
|
}
|
||||||
|
GUIDraw::FillRect(rect, backColor);
|
||||||
|
GUIDraw::DrawRect(rect, textBoxBorder);
|
||||||
|
|
||||||
|
if (number != nullptr) {
|
||||||
|
int i;
|
||||||
|
char s1[20];
|
||||||
|
char* s2;
|
||||||
|
//sprintf(text, "%.f", number);
|
||||||
|
|
||||||
|
sprintf(s1, "%f", *number);
|
||||||
|
s2 = strchr(s1, '.');
|
||||||
|
i = int(s2 - s1);
|
||||||
|
sprintf(s1, "%.*g", (i+2), *number);
|
||||||
|
|
||||||
|
char textColor = 15;
|
||||||
|
if (focus == id) {
|
||||||
|
textColor = 11;
|
||||||
|
if (dot) strcat(s1, ".");
|
||||||
|
if (empty) s1[0] = '\0';
|
||||||
|
const bool dotAlready = (strchr(s1, '.') != nullptr);
|
||||||
|
if (GUIKeyboard::key >= SDLK_0 and GUIKeyboard::key <= SDLK_9) {
|
||||||
|
if (not empty and s1[0] == '0' and not (strlen(s1)>1 and s1[1] == '.' )) s1[0] = '\0';
|
||||||
|
empty = false;
|
||||||
|
const size_t len = strlen(s1);
|
||||||
|
s1[len] = GUIKeyboard::key;
|
||||||
|
s1[len+1] = '\0';
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
} else if (not dotAlready and GUIKeyboard::key == SDLK_PERIOD) {
|
||||||
|
empty = false;
|
||||||
|
const size_t len = strlen(s1);
|
||||||
|
s1[len] = GUIKeyboard::key;
|
||||||
|
s1[len+1] = '\0';
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
} else if (GUIKeyboard::key == SDLK_BACKSPACE) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
const size_t len = strlen(s1);
|
||||||
|
if (len == 1) empty = true;
|
||||||
|
s1[len-1] = '\0';
|
||||||
|
} else if (GUIKeyboard::key == SDLK_RIGHT) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
(*number)++;
|
||||||
|
sprintf(s1, "%f", *number);
|
||||||
|
s2 = strchr(s1, '.');
|
||||||
|
i = int(s2 - s1);
|
||||||
|
sprintf(s1, "%.*g", (i+2), *number);
|
||||||
|
} else if (GUIKeyboard::key == SDLK_LEFT) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
(*number)--;
|
||||||
|
sprintf(s1, "%f", *number);
|
||||||
|
s2 = strchr(s1, '.');
|
||||||
|
i = int(s2 - s1);
|
||||||
|
sprintf(s1, "%.*g", (i+2), *number);
|
||||||
|
} else if (GUIKeyboard::key == SDLK_RETURN) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
ResetFocus();
|
||||||
|
textColor = 15;
|
||||||
|
const size_t len = strlen(s1);
|
||||||
|
if (s1[len-1] == '.') s1[len-1] = '\0';
|
||||||
|
} else if (GUIKeyboard::key == SDLK_TAB) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
focus++;
|
||||||
|
textColor = 15;
|
||||||
|
const size_t len = strlen(s1);
|
||||||
|
if (s1[len-1] == '.') s1[len-1] = '\0';
|
||||||
|
}
|
||||||
|
if (focus == id) {
|
||||||
|
const size_t len = strlen(s1);
|
||||||
|
dot = (s1[len-1] == '.');
|
||||||
|
*number = atof(s1);
|
||||||
|
|
||||||
|
const Vector2 size = font->GetSize(s1);
|
||||||
|
font->Print(size.x+viewPos+viewSize.x+5, viewSize.y+2, "_", textColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font->Print(viewPos+viewSize.x+5, viewSize.y+2, s1, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int numElements = viewSize.z / size;
|
||||||
|
float separation = (viewSize.z - (size*numElements)) / (numElements-1);
|
||||||
|
viewPos += size+separation;
|
||||||
|
|
||||||
|
if (viewPos > viewSize.z) {
|
||||||
|
viewPos = 0;
|
||||||
|
viewSize.y += 27;
|
||||||
|
viewSize.w -= 27;
|
||||||
|
}
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawViewport(const int index)
|
||||||
|
{
|
||||||
|
glViewport(viewSize.x, SCREEN_HEIGHT-(viewSize.y+viewSize.w), viewSize.z, viewSize.w);
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
glScissor(viewSize.x, SCREEN_HEIGHT-(viewSize.y+viewSize.w), viewSize.z, viewSize.w);
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
float zoom = viewports[index].zoom;
|
||||||
|
if (zoom < 0) zoom = 1.0f/-zoom;
|
||||||
|
const float x = (viewSize.z * 0.5f) / zoom;
|
||||||
|
const float y = (viewSize.w * 0.5f) / zoom;
|
||||||
|
glOrtho(-x, x, y, -y, 1000, -1000);
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
glTranslatef(viewports[index].offset.x, viewports[index].offset.y, 0);
|
||||||
|
glRotatef(viewports[index].rotation.x, 1, 0, 0);
|
||||||
|
glRotatef(viewports[index].rotation.y, 0, 1, 0);
|
||||||
|
|
||||||
|
|
||||||
|
if (not menuVisible and GUIMouse::position.inside(viewSize.GetPosition(), viewSize.GetSize())) {
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Right] == GUIMouse::ButtonState::Down) {
|
||||||
|
menuVisible = true;
|
||||||
|
menuPos = GUIMouse::position;
|
||||||
|
}
|
||||||
|
if (not GUIKeyboard::alt and GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
if (Editor::state == Editor::State::None) {
|
||||||
|
if (Editor::mode == Editor::Mode::Paint) {
|
||||||
|
if (viewports[index].renderMode == Viewport::RenderMode::UV) {
|
||||||
|
Renderer::SetState(RENDER_FILL);
|
||||||
|
Color color = model.PickPixel(GUIMouse::position.x, GUIMouse::position.y);
|
||||||
|
Editor::bitmap[(color.x*4)+color.y*128] = currentColor.r;
|
||||||
|
Editor::bitmap[(color.x*4)+1+color.y*128] = currentColor.g;
|
||||||
|
Editor::bitmap[(color.x*4)+2+color.y*128] = currentColor.b;
|
||||||
|
Editor::bitmap[(color.x*4)+3+color.y*128] = currentColor.a;
|
||||||
|
Texture::Update(Editor::texture, 32, 32, Editor::bitmap);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Renderer::SetState(RENDER_DEPTH | RENDER_FILL);
|
||||||
|
Color color = model.PickPaint(GUIMouse::position.x, GUIMouse::position.y);
|
||||||
|
Editor::bitmap[(color.y*4)+color.z*128] = currentColor.r;
|
||||||
|
Editor::bitmap[(color.y*4)+1+color.z*128] = currentColor.g;
|
||||||
|
Editor::bitmap[(color.y*4)+2+color.z*128] = currentColor.b;
|
||||||
|
Editor::bitmap[(color.y*4)+3+color.z*128] = currentColor.a;
|
||||||
|
Texture::Update(Editor::texture, 32, 32, Editor::bitmap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Renderer::SetState(RENDER_DEPTH | RENDER_FILL);
|
||||||
|
Color color = model.Pick(GUIMouse::position.x, GUIMouse::position.y);
|
||||||
|
if (Editor::mode == Editor::Mode::Cube) {
|
||||||
|
model.SelectCube(color.r, GUIKeyboard::shift);
|
||||||
|
} else if (Editor::mode == Editor::Mode::Face) {
|
||||||
|
model.SelectFace(color.r, color.g, GUIKeyboard::shift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResetFocus();
|
||||||
|
}
|
||||||
|
if (GUIMouse::delta.x != 0 or GUIMouse::delta.y != 0) {
|
||||||
|
if (GUIKeyboard::alt or GUIMouse::buttons[GUIMouse::Button::Middle] == GUIMouse::ButtonState::Pressed) {
|
||||||
|
if (GUIKeyboard::shift) {
|
||||||
|
viewports[index].offset += GUIMouse::delta / viewports[index].zoom;
|
||||||
|
} else {
|
||||||
|
viewports[index].rotation += Vector2(GUIMouse::delta.y, -GUIMouse::delta.x)*1;
|
||||||
|
if (viewports[index].rotation.x < -90) viewports[index].rotation.x = -90;
|
||||||
|
if (viewports[index].rotation.x > 90) viewports[index].rotation.x = 90;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GUIMouse::wheel.x != 0 or GUIMouse::wheel.y != 0) {
|
||||||
|
if (GUIKeyboard::shift) {
|
||||||
|
viewports[index].offset += GUIMouse::wheel / viewports[index].zoom;
|
||||||
|
} else {
|
||||||
|
viewports[index].zoom -= GUIMouse::wheel.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glClearColor(float(panel3DBack.r)/255.0f, float(panel3DBack.g)/255.0f, float(panel3DBack.b)/255.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
if (viewports[index].renderMode == Viewport::RenderMode::Solid) {
|
||||||
|
Renderer::SetState(RENDER_DEPTH | RENDER_FILL);
|
||||||
|
if (viewports[index].light) Renderer::Light(ON);
|
||||||
|
model.DrawSolid();
|
||||||
|
} else if (viewports[index].renderMode == Viewport::RenderMode::Textured) {
|
||||||
|
Renderer::SetState(RENDER_DEPTH | RENDER_FILL | RENDER_TEXTURE);
|
||||||
|
if (viewports[index].light) Renderer::Light(ON);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, Editor::texture);
|
||||||
|
model.DrawSolid();
|
||||||
|
} else if (viewports[index].renderMode == Viewport::RenderMode::Wire) {
|
||||||
|
Renderer::SetState(RENDER_DEPTH);
|
||||||
|
model.DrawWire();
|
||||||
|
} else if (viewports[index].renderMode == Viewport::RenderMode::UV) {
|
||||||
|
Renderer::SetState(RENDER_FILL | RENDER_TEXTURE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, Editor::texture);
|
||||||
|
model.DrawUV();
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPopMatrix();
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool DrawButton(const char* text, const SDL_Keycode key, const bool state, const float size = 85)
|
||||||
|
{
|
||||||
|
Vector4 rect {viewPos+viewSize.x, viewSize.y, size, 22};
|
||||||
|
Color backColor = buttonBack;
|
||||||
|
Color borders[4] = {textBoxBorder, winBack, winBack, textBoxBorder};
|
||||||
|
bool retVal {false};
|
||||||
|
ivec2 textPadding {5,2};
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
backColor = textBoxBorder;
|
||||||
|
borders[0] = borders[3] = winBack;
|
||||||
|
borders[1] = borders[2] = textBoxBorder;
|
||||||
|
textPadding += {1,1};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUIMouse::position.inside(rect.GetPosition(), rect.GetSize())) {
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Pressed) {
|
||||||
|
borders[0] = borders[3] = winBack;
|
||||||
|
borders[1] = borders[2] = textBoxBorder;
|
||||||
|
textPadding += {1,1};
|
||||||
|
}
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Up) {
|
||||||
|
borders[0] = borders[3] = winBack;
|
||||||
|
borders[1] = borders[2] = textBoxBorder;
|
||||||
|
textPadding += {1,1};
|
||||||
|
ResetFocus();
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
backColor = textBoxBorder;
|
||||||
|
}
|
||||||
|
if (focus == -1 and key != SDLK_UNKNOWN and GUIKeyboard::key == key) {
|
||||||
|
ResetFocus();
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUIDraw::FillRect({viewPos+viewSize.x, viewSize.y, size, 22}, backColor);
|
||||||
|
GUIDraw::DrawRect({viewPos+viewSize.x, viewSize.y, size, 22}, borders);
|
||||||
|
font->Print(viewPos+viewSize.x+textPadding.x, viewSize.y+textPadding.y, text, 15);
|
||||||
|
|
||||||
|
int numElements = viewSize.z / size;
|
||||||
|
float separation = (viewSize.z - (size*numElements)) / (numElements-1);
|
||||||
|
viewPos += size+separation;
|
||||||
|
|
||||||
|
if (viewPos > viewSize.z) {
|
||||||
|
viewPos = 0;
|
||||||
|
viewSize.y += 27;
|
||||||
|
viewSize.w -= 27;
|
||||||
|
}
|
||||||
|
//id++;
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawStaticTextBox(const char* text, const float size = 85)
|
||||||
|
{
|
||||||
|
Vector4 rect {viewPos+viewSize.x, viewSize.y, size, 22};
|
||||||
|
GUIDraw::FillRect(rect, textBoxBack);
|
||||||
|
GUIDraw::DrawRect(rect, textBoxBorder);
|
||||||
|
font->Print(viewPos+viewSize.x+5, viewSize.y+2, text, 7);
|
||||||
|
|
||||||
|
viewPos += size+10;
|
||||||
|
|
||||||
|
if (viewPos > viewSize.z) {
|
||||||
|
viewPos = 0;
|
||||||
|
viewSize.y += 27;
|
||||||
|
viewSize.w -= 27;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawSpace(const int space)
|
||||||
|
{
|
||||||
|
viewPos = 0;
|
||||||
|
viewSize.y += space;
|
||||||
|
viewSize.w -= space;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
if (font == nullptr) {
|
||||||
|
font = new Font();
|
||||||
|
font->Load("font");
|
||||||
|
}
|
||||||
|
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 100, -100);
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
viewStackPos = 0;
|
||||||
|
viewPos = 0;
|
||||||
|
viewSize = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
||||||
|
id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawMenu(const int numItems, const float size)
|
||||||
|
{
|
||||||
|
viewSize = Vector4(menuPos.x, menuPos.y, size, 25*numItems);
|
||||||
|
if (menuPos.x+size > SCREEN_WIDTH) viewSize.x = SCREEN_WIDTH - size;
|
||||||
|
if (menuPos.y+25*numItems > SCREEN_HEIGHT) viewSize.y = SCREEN_HEIGHT - 25*numItems;
|
||||||
|
|
||||||
|
GUIDraw::FillRect(viewSize, panelBack);
|
||||||
|
GUIDraw::DrawRect(viewSize, winBack);
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
if (not GUIMouse::position.inside(viewSize.GetPosition(), viewSize.GetSize())) {
|
||||||
|
ResetFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawSubMenu(const int numItems, const float size)
|
||||||
|
{
|
||||||
|
viewSize = Vector4(subMenuPos.x, subMenuPos.y, size, 25*numItems);
|
||||||
|
if (subMenuPos.x+size > SCREEN_WIDTH) viewSize.x = subMenuPos.x - (size*2);
|
||||||
|
if (subMenuPos.y+25*numItems > SCREEN_HEIGHT) viewSize.y = SCREEN_HEIGHT - 25*numItems;
|
||||||
|
|
||||||
|
GUIDraw::FillRect(viewSize, panelBack);
|
||||||
|
GUIDraw::DrawRect(viewSize, winBack);
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
if (not GUIMouse::position.inside(viewSize.GetPosition(), viewSize.GetSize())) {
|
||||||
|
ResetFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool DrawMenuItem(const char* text, const bool state)
|
||||||
|
{
|
||||||
|
bool retVal = false;
|
||||||
|
Vector4 rect {viewSize.x, viewSize.y, viewSize.z, 25};
|
||||||
|
if (GUIMouse::position.inside(rect.GetPosition(), rect.GetSize())) {
|
||||||
|
subMenu = -1;
|
||||||
|
GUIDraw::FillRect(rect, textBoxBack);
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
retVal = true;
|
||||||
|
menuVisible = false;
|
||||||
|
comboBoxVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state) font->Print(viewSize.x+3, viewSize.y+2, "+", 15);
|
||||||
|
font->Print(viewSize.x+13, viewSize.y+2, text, 15);
|
||||||
|
|
||||||
|
viewSize.y += 25;
|
||||||
|
viewSize.w -= 25;
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawMenuSubItem(const char* text, const int subMenuIndex)
|
||||||
|
{
|
||||||
|
Vector4 rect {viewSize.x, viewSize.y, viewSize.z, 25};
|
||||||
|
if (GUIMouse::position.inside(rect.GetPosition(), rect.GetSize())) {
|
||||||
|
GUIDraw::FillRect(rect, textBoxBack);
|
||||||
|
subMenu = subMenuIndex;
|
||||||
|
subMenuPos = Vector2(viewSize.x+viewSize.z, viewSize.y);
|
||||||
|
} else if (subMenu == subMenuIndex) {
|
||||||
|
GUIDraw::FillRect(rect, textBoxBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
font->Print(viewSize.x+viewSize.z-13, viewSize.y+2, ">", 15);
|
||||||
|
font->Print(viewSize.x+13, viewSize.y+2, text, 15);
|
||||||
|
|
||||||
|
viewSize.y += 25;
|
||||||
|
viewSize.w -= 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool DrawSubMenuItem(const char* text, const bool state)
|
||||||
|
{
|
||||||
|
bool retVal = false;
|
||||||
|
Vector4 rect {viewSize.x, viewSize.y, viewSize.z, 25};
|
||||||
|
if (GUIMouse::position.inside(rect.GetPosition(), rect.GetSize())) {
|
||||||
|
GUIDraw::FillRect(rect, textBoxBack);
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
retVal = true;
|
||||||
|
menuVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state) font->Print(viewSize.x+3, viewSize.y+2, "+", 15);
|
||||||
|
font->Print(viewSize.x+13, viewSize.y+2, text, 15);
|
||||||
|
|
||||||
|
viewSize.y += 25;
|
||||||
|
viewSize.w -= 25;
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Vector2 GetTransformedAxesUV(const float x, const float y)
|
||||||
|
{
|
||||||
|
Vector2 result {x, y};
|
||||||
|
if (Editor::forcedAxis == 0) result.y = 0;
|
||||||
|
else if (Editor::forcedAxis == 1) result.x = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 GetTransformedAxes(const float x, const float y)
|
||||||
|
{
|
||||||
|
Vector3 result {0, 0, 0};
|
||||||
|
|
||||||
|
if (Editor::forcedAxis == 0) {
|
||||||
|
result.x = x + y;
|
||||||
|
result.y = 0;
|
||||||
|
result.z = 0;
|
||||||
|
} else if (Editor::forcedAxis == 1) {
|
||||||
|
result.x = 0;
|
||||||
|
result.y = x + y;
|
||||||
|
result.z = 0;
|
||||||
|
} else if (Editor::forcedAxis == 2) {
|
||||||
|
result.x = 0;
|
||||||
|
result.y = 0;
|
||||||
|
result.z = x + y;
|
||||||
|
} else {
|
||||||
|
float rx = viewports[selectedViewport].rotation.x; while (rx >= 360) rx -= 360; while (rx < 0) rx += 360;
|
||||||
|
float ry = viewports[selectedViewport].rotation.y; while (ry >= 360) ry -= 360; while (ry < 0) ry += 360;
|
||||||
|
if (rx <= 45 or rx >= 315 ) {
|
||||||
|
if (ry <= 45 or ry >= 315) {
|
||||||
|
// x, y
|
||||||
|
result.x = x;
|
||||||
|
result.y = y;
|
||||||
|
} else if (ry > 45 and ry < 135) {
|
||||||
|
// z, y
|
||||||
|
result.z = x;
|
||||||
|
result.y = y;
|
||||||
|
} else if (ry >= 135 and ry < 225) {
|
||||||
|
// -x, y
|
||||||
|
result.x = -x;
|
||||||
|
result.y = y;
|
||||||
|
} else {
|
||||||
|
// -z, y
|
||||||
|
result.z = -x;
|
||||||
|
result.y = y;
|
||||||
|
}
|
||||||
|
} else if (rx > 45 and rx < 180) {
|
||||||
|
if (ry <= 45 or ry >= 315) {
|
||||||
|
// x, -z
|
||||||
|
result.x = x;
|
||||||
|
result.z = -y;
|
||||||
|
} else if (ry > 45 and ry < 135) {
|
||||||
|
// z, x
|
||||||
|
result.z = x;
|
||||||
|
result.x = y;
|
||||||
|
} else if (ry >= 135 and ry < 225) {
|
||||||
|
// -x, z
|
||||||
|
result.x = -x;
|
||||||
|
result.z = y;
|
||||||
|
} else {
|
||||||
|
// -z, -x
|
||||||
|
result.z = -x;
|
||||||
|
result.x = -y;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ry <= 45 or ry >= 315) {
|
||||||
|
// x, z
|
||||||
|
result.x = x;
|
||||||
|
result.z = y;
|
||||||
|
} else if (ry > 45 and ry < 135) {
|
||||||
|
// -z, x
|
||||||
|
result.z = x;
|
||||||
|
result.x = -y;
|
||||||
|
} else if (ry >= 135 and ry < 225) {
|
||||||
|
// -x, -z
|
||||||
|
result.x = -x;
|
||||||
|
result.z = -y;
|
||||||
|
} else {
|
||||||
|
// z, -x
|
||||||
|
result.z = -x;
|
||||||
|
result.x = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Draw()
|
||||||
|
{
|
||||||
|
if (Editor::state != Editor::State::None) {
|
||||||
|
if (Editor::mode == Editor::Mode::Face) {
|
||||||
|
if (GUIKeyboard::key == SDLK_x) { Editor::forcedAxis = 0; GUIKeyboard::key = SDLK_UNKNOWN; }
|
||||||
|
if (GUIKeyboard::key == SDLK_y) { Editor::forcedAxis = 1; GUIKeyboard::key = SDLK_UNKNOWN; }
|
||||||
|
if (GUIMouse::slowDelta.x != 0 or GUIMouse::slowDelta.y != 0) {
|
||||||
|
Vector2 axes = GetTransformedAxesUV(GUIMouse::slowDelta.x, GUIMouse::slowDelta.y);
|
||||||
|
if (Editor::state == Editor::State::Grab) model.GrabFaces(axes.x, axes.y);
|
||||||
|
if (Editor::state == Editor::State::Scale) model.ScaleFaces(axes.x, axes.y);
|
||||||
|
}
|
||||||
|
} else if (Editor::mode == Editor::Mode::Cube) {
|
||||||
|
if (GUIKeyboard::key == SDLK_x) { Editor::forcedAxis = 0; GUIKeyboard::key = SDLK_UNKNOWN; }
|
||||||
|
if (GUIKeyboard::key == SDLK_y) { Editor::forcedAxis = 1; GUIKeyboard::key = SDLK_UNKNOWN; }
|
||||||
|
if (GUIKeyboard::key == SDLK_z) { Editor::forcedAxis = 2; GUIKeyboard::key = SDLK_UNKNOWN; }
|
||||||
|
if (GUIMouse::slowDelta.x != 0 or GUIMouse::slowDelta.y != 0) {
|
||||||
|
Vector3 axes = GetTransformedAxes(GUIMouse::slowDelta.x, GUIMouse::slowDelta.y);
|
||||||
|
if (Editor::state == Editor::State::Grab) model.GrabCubes(axes.x, axes.y, axes.z);
|
||||||
|
if (Editor::state == Editor::State::Scale) model.ScaleCubes(axes.x, axes.y, axes.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
//model.cubes[0].selected = true;
|
||||||
|
|
||||||
|
StartSplitV(30); //TOOLBAR
|
||||||
|
|
||||||
|
DrawPanel();
|
||||||
|
|
||||||
|
NextSplit();
|
||||||
|
StartSplitV(-30);
|
||||||
|
StartSplitH(200);
|
||||||
|
// INFO PANEL
|
||||||
|
DrawPanel();
|
||||||
|
DrawTitle("State");
|
||||||
|
if (DrawButton("Cubes", SDLK_1, Editor::mode == Editor::Mode::Cube)) Editor::SetMode(Editor::Mode::Cube);
|
||||||
|
if (DrawButton("Faces", SDLK_2, Editor::mode == Editor::Mode::Face)) Editor::SetMode(Editor::Mode::Face);
|
||||||
|
if (DrawButton("Paint", SDLK_3, Editor::mode == Editor::Mode::Paint)) Editor::SetMode(Editor::Mode::Paint);
|
||||||
|
if (DrawButton("Anim", SDLK_4, Editor::mode == Editor::Mode::Anim)) Editor::SetMode(Editor::Mode::Anim);
|
||||||
|
|
||||||
|
DrawSpace(20);
|
||||||
|
if (Editor::mode == Editor::Mode::Cube) {
|
||||||
|
int index = model.GetSelectedCube();
|
||||||
|
DrawTitle("Cube Info");
|
||||||
|
DrawCaption("Name:");
|
||||||
|
DrawTextBox(index != -1 ? model.cubes[index].name : nullptr);
|
||||||
|
|
||||||
|
float* v[9] = {nullptr};
|
||||||
|
if (index != -1) {
|
||||||
|
v[0] = &model.cubes[index].position.x;
|
||||||
|
v[1] = &model.cubes[index].position.y;
|
||||||
|
v[2] = &model.cubes[index].position.z;
|
||||||
|
v[3] = &model.cubes[index].size.x;
|
||||||
|
v[4] = &model.cubes[index].size.y;
|
||||||
|
v[5] = &model.cubes[index].size.z;
|
||||||
|
v[6] = &model.cubes[index].pivot.x;
|
||||||
|
v[7] = &model.cubes[index].pivot.y;
|
||||||
|
v[8] = &model.cubes[index].pivot.z;
|
||||||
|
}
|
||||||
|
DrawCaption("Position:");
|
||||||
|
DrawNumTextBox(v[0], 50);
|
||||||
|
DrawNumTextBox(v[1], 50);
|
||||||
|
DrawNumTextBox(v[2], 50);
|
||||||
|
DrawCaption("Size:");
|
||||||
|
DrawNumTextBox(v[3], 50);
|
||||||
|
DrawNumTextBox(v[4], 50);
|
||||||
|
DrawNumTextBox(v[5], 50);
|
||||||
|
DrawCaption("Pivot:");
|
||||||
|
DrawNumTextBox(v[6], 50);
|
||||||
|
DrawNumTextBox(v[7], 50);
|
||||||
|
DrawNumTextBox(v[8], 50);
|
||||||
|
DrawCaption("Parent:");
|
||||||
|
char parent[10] = "<none>";
|
||||||
|
if (index != -1 and model.cubes[index].parent != -1) strcpy(parent, model.cubes[model.cubes[index].parent].name);
|
||||||
|
if (DrawComboBox(index != -1 ? parent : nullptr)) {
|
||||||
|
comboBoxVisible = not comboBoxVisible;
|
||||||
|
if (comboBoxVisible) {
|
||||||
|
subMenuPos.x = viewSize.z;
|
||||||
|
menuPos = {viewSize.x, viewSize.y};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawSpace(20);
|
||||||
|
DrawTitle("Cube Ops");
|
||||||
|
if (DrawButton("New", SDLK_n, false)) model.NewCube();
|
||||||
|
if (DrawButton("Delete", SDLK_BACKSPACE, false)) model.DeleteCube();
|
||||||
|
if (DrawButton("Dup", SDLK_d, false)) {
|
||||||
|
model.DupCube();
|
||||||
|
Editor::SetState(Editor::State::Grab);
|
||||||
|
}
|
||||||
|
if (DrawButton("Grab", SDLK_g, Editor::state == Editor::State::Grab)) Editor::SetState(Editor::State::Grab);
|
||||||
|
if (DrawButton("Scale", SDLK_s, Editor::state == Editor::State::Scale)) Editor::SetState(Editor::State::Scale);
|
||||||
|
if (DrawButton("Pivot", SDLK_p, Editor::state == Editor::State::Pivot)) Editor::SetState(Editor::State::Pivot);
|
||||||
|
|
||||||
|
} else if (Editor::mode == Editor::Mode::Face) {
|
||||||
|
DrawTitle("Face Info");
|
||||||
|
float* v[8] = {nullptr};
|
||||||
|
ivec2 index = model.GetSelectedFace();
|
||||||
|
if (index.x != -1) {
|
||||||
|
v[0] = &model.cubes[index.x].faces[index.y].uv[2].x;
|
||||||
|
v[1] = &model.cubes[index.x].faces[index.y].uv[2].y;
|
||||||
|
v[2] = &model.cubes[index.x].faces[index.y].uv[1].x;
|
||||||
|
v[3] = &model.cubes[index.x].faces[index.y].uv[1].y;
|
||||||
|
v[4] = &model.cubes[index.x].faces[index.y].uv[3].x;
|
||||||
|
v[5] = &model.cubes[index.x].faces[index.y].uv[3].y;
|
||||||
|
v[6] = &model.cubes[index.x].faces[index.y].uv[0].x;
|
||||||
|
v[7] = &model.cubes[index.x].faces[index.y].uv[0].y;
|
||||||
|
}
|
||||||
|
DrawCaption("UV:");
|
||||||
|
DrawNumTextBox(v[0], 42);
|
||||||
|
DrawNumTextBox(v[1], 42);
|
||||||
|
DrawNumTextBox(v[2], 42);
|
||||||
|
DrawNumTextBox(v[3], 42);
|
||||||
|
DrawNumTextBox(v[4], 42);
|
||||||
|
DrawNumTextBox(v[5], 42);
|
||||||
|
DrawNumTextBox(v[6], 42);
|
||||||
|
DrawNumTextBox(v[7], 42);
|
||||||
|
|
||||||
|
DrawSpace(20);
|
||||||
|
DrawTitle("Face Ops");
|
||||||
|
if (DrawButton("Clear", SDLK_c, false)) model.ClearFaces();
|
||||||
|
if (DrawButton("Rotate", SDLK_r, false)) model.RotateFaces();
|
||||||
|
if (DrawButton("FlipH", SDLK_h, false)) model.FlipHFaces();
|
||||||
|
if (DrawButton("FlipV", SDLK_v, false)) model.FlipVFaces();
|
||||||
|
if (DrawButton("Grab", SDLK_g, Editor::state == Editor::State::Grab)) Editor::SetState(Editor::State::Grab);
|
||||||
|
if (DrawButton("Scale", SDLK_s, Editor::state == Editor::State::Scale)) Editor::SetState(Editor::State::Scale);
|
||||||
|
|
||||||
|
}
|
||||||
|
DrawSpace(20);
|
||||||
|
DrawTitle("Texture");
|
||||||
|
char* shortPath = strrchr(Editor::textureFilename, '/')+1;
|
||||||
|
DrawStaticTextBox(shortPath, 145);
|
||||||
|
if (DrawButton("...", SDLK_UNKNOWN, false, 25)) {
|
||||||
|
char oldPath[400];
|
||||||
|
strcpy(oldPath, Editor::textureFilename);
|
||||||
|
const char* path = nullptr;//GUIDialogs::ChooseFile();
|
||||||
|
if (path != nullptr) {
|
||||||
|
strcpy(Editor::textureFilename, path);
|
||||||
|
//free(path);
|
||||||
|
uint8_t* data = Texture::Load(Editor::textureFilename);
|
||||||
|
if (data == nullptr) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "File is not a correct PNG!", nullptr);
|
||||||
|
strcpy(Editor::textureFilename, oldPath);
|
||||||
|
} else {
|
||||||
|
memcpy(Editor::bitmap, data, 32*32*4);
|
||||||
|
free(data);
|
||||||
|
Texture::Update(Editor::texture, 32, 32, Editor::bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NextSplit();
|
||||||
|
// 3D VIEWS
|
||||||
|
if (zoomed) {
|
||||||
|
Draw3DPanel(selectedViewport);
|
||||||
|
DrawViewport(selectedViewport);
|
||||||
|
} else {
|
||||||
|
StartSplitH(2.0f*viewSize.z/3.0f);
|
||||||
|
Draw3DPanel(0);
|
||||||
|
DrawViewport(0);
|
||||||
|
NextSplit();
|
||||||
|
StartSplitV(viewSize.w/2.0f);
|
||||||
|
Draw3DPanel(1);
|
||||||
|
DrawViewport(1);
|
||||||
|
NextSplit();
|
||||||
|
Draw3DPanel(2);
|
||||||
|
DrawViewport(2);
|
||||||
|
}
|
||||||
|
NextSplit();
|
||||||
|
// STATUS BAR
|
||||||
|
DrawPanel();
|
||||||
|
|
||||||
|
if (comboBoxVisible) {
|
||||||
|
int numItems = model.numCubes;
|
||||||
|
DrawMenu(numItems, subMenuPos.x);
|
||||||
|
int sel = model.GetSelectedCube();
|
||||||
|
for (int i = 0; i < model.numCubes; i++) {
|
||||||
|
if (i != sel and DrawMenuItem(model.cubes[i].name, model.cubes[sel].parent == i)) model.cubes[sel].parent = i;
|
||||||
|
}
|
||||||
|
if (DrawMenuItem("<none>", model.cubes[sel].parent == -1)) model.cubes[sel].parent = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menuVisible) {
|
||||||
|
DrawMenu(6, 120);
|
||||||
|
DrawMenuSubItem("Render", 0);
|
||||||
|
DrawMenuSubItem("View", 1);
|
||||||
|
DrawMenuSubItem("Projection", 2);
|
||||||
|
if (DrawMenuItem("Light", viewports[selectedViewport].light)) viewports[selectedViewport].light = not viewports[selectedViewport].light;
|
||||||
|
if (DrawMenuItem("Grid", viewports[selectedViewport].grid)) viewports[selectedViewport].grid = not viewports[selectedViewport].grid;
|
||||||
|
if (DrawMenuItem("Zoomed", zoomed)) zoomed = not zoomed;
|
||||||
|
|
||||||
|
if (subMenu == 0) {
|
||||||
|
DrawSubMenu(4, 120);
|
||||||
|
if (DrawSubMenuItem("Wire", viewports[selectedViewport].renderMode == Viewport::RenderMode::Wire)) viewports[selectedViewport].renderMode = Viewport::RenderMode::Wire;
|
||||||
|
if (DrawSubMenuItem("Solid", viewports[selectedViewport].renderMode == Viewport::RenderMode::Solid)) viewports[selectedViewport].renderMode = Viewport::RenderMode::Solid;
|
||||||
|
if (DrawSubMenuItem("Textured", viewports[selectedViewport].renderMode == Viewport::RenderMode::Textured)) viewports[selectedViewport].renderMode = Viewport::RenderMode::Textured;
|
||||||
|
if (DrawSubMenuItem("UV", viewports[selectedViewport].renderMode == Viewport::RenderMode::UV)) viewports[selectedViewport].renderMode = Viewport::RenderMode::UV;
|
||||||
|
} else if (subMenu == 1) {
|
||||||
|
DrawSubMenu(6, 120);
|
||||||
|
if (DrawSubMenuItem("Front", viewports[selectedViewport].rotation.x == 0 and viewports[selectedViewport].rotation.y == 0)) {
|
||||||
|
viewports[selectedViewport].rotation.x = 0;
|
||||||
|
viewports[selectedViewport].rotation.y = 0;
|
||||||
|
}
|
||||||
|
DrawSubMenuItem("Left", false);
|
||||||
|
DrawSubMenuItem("Top", false);
|
||||||
|
DrawSubMenuItem("Back", false);
|
||||||
|
DrawSubMenuItem("Right", false);
|
||||||
|
DrawSubMenuItem("Bottom", false);
|
||||||
|
} else if (subMenu == 2) {
|
||||||
|
DrawSubMenu(2, 120);
|
||||||
|
DrawSubMenuItem("Orthogonal", true);
|
||||||
|
DrawSubMenuItem("Perspective", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Editor::state != Editor::State::None) {
|
||||||
|
if (GUIKeyboard::key == SDLK_RETURN) {
|
||||||
|
GUIKeyboard::key = SDLK_UNKNOWN;
|
||||||
|
Editor::SetState(Editor::State::None);
|
||||||
|
}
|
||||||
|
if (GUIMouse::buttons[GUIMouse::Button::Left] == GUIMouse::ButtonState::Down) {
|
||||||
|
Editor::SetState(Editor::State::None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
6
GUIDialogs.h
Normal file
6
GUIDialogs.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace GUIDialogs
|
||||||
|
{
|
||||||
|
char* ChooseFile();
|
||||||
|
}
|
||||||
29
GUIDialogs.mm
Normal file
29
GUIDialogs.mm
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include "GUIDialogs.h"
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
namespace GUIDialogs
|
||||||
|
{
|
||||||
|
char* ChooseFile()
|
||||||
|
{
|
||||||
|
NSWindow *keyWindow = [NSApp keyWindow];
|
||||||
|
char* path = nullptr;
|
||||||
|
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||||
|
[panel setCanChooseFiles:YES];
|
||||||
|
[panel setCanChooseDirectories:NO];
|
||||||
|
[panel setAllowsMultipleSelection:NO];
|
||||||
|
|
||||||
|
NSInteger clicked = [panel runModal];
|
||||||
|
|
||||||
|
if (clicked == NSFileHandlingPanelOKButton) {
|
||||||
|
for (NSURL *url in [panel URLs]) {
|
||||||
|
path = strdup([url fileSystemRepresentation]);
|
||||||
|
//const char* urlPath = [url fileSystemRepresentation];
|
||||||
|
//path = (char*)malloc(strlen(urlPath));
|
||||||
|
//strcpy(path, urlPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[keyWindow makeKeyWindow];
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
75
GUIDraw.cpp
Normal file
75
GUIDraw.cpp
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#include "GUIDraw.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
namespace GUIDraw
|
||||||
|
{
|
||||||
|
void DrawLine(const Vector2& a, const Vector2& b, const Color& color)
|
||||||
|
{
|
||||||
|
Renderer::SetState(RENDER_BLEND);
|
||||||
|
glColor4ub(color.r, color.g, color.b, color.a);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glVertex2i(a.x, a.y);
|
||||||
|
glVertex2i(b.x, b.y);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawRect(const Vector4& rect, const Color& color)
|
||||||
|
{
|
||||||
|
Renderer::SetState(RENDER_BLEND);
|
||||||
|
glColor4ub(color.r, color.g, color.b, color.a);
|
||||||
|
glBegin(GL_LINE_LOOP);
|
||||||
|
glVertex2i(rect.x, rect.y);
|
||||||
|
glVertex2i(rect.x, rect.y+rect.w);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y+rect.w);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawRect(const Vector4& rect, const Color* colors)
|
||||||
|
{
|
||||||
|
Renderer::SetState(RENDER_BLEND);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glColor4ub(colors[0].r, colors[0].g, colors[0].b, colors[0].a);
|
||||||
|
glVertex2i(rect.x, rect.y);
|
||||||
|
glVertex2i(rect.x, rect.y+rect.w);
|
||||||
|
glColor4ub(colors[1].r, colors[1].g, colors[1].b, colors[1].a);
|
||||||
|
glVertex2i(rect.x, rect.y+rect.w);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y+rect.w);
|
||||||
|
glColor4ub(colors[2].r, colors[2].g, colors[2].b, colors[2].a);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y+rect.w);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y);
|
||||||
|
glColor4ub(colors[3].r, colors[3].g, colors[3].b, colors[3].a);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y);
|
||||||
|
glVertex2i(rect.x, rect.y);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FillRect(const Vector4& rect, const Color& color)
|
||||||
|
{
|
||||||
|
Renderer::SetState(RENDER_BLEND | RENDER_FILL);
|
||||||
|
glColor4ub(color.r, color.g, color.b, color.a);
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glVertex2i(rect.x, rect.y);
|
||||||
|
glVertex2i(rect.x, rect.y+rect.w);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y+rect.w);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FillRect(const Vector4& rect, const Color* colors)
|
||||||
|
{
|
||||||
|
Renderer::SetState(RENDER_BLEND | RENDER_FILL);
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glColor4ub(colors[0].r, colors[0].g, colors[0].b, colors[0].a);
|
||||||
|
glVertex2i(rect.x, rect.y);
|
||||||
|
glColor4ub(colors[1].r, colors[1].g, colors[1].b, colors[1].a);
|
||||||
|
glVertex2i(rect.x, rect.y+rect.w);
|
||||||
|
glColor4ub(colors[2].r, colors[2].g, colors[2].b, colors[2].a);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y+rect.w);
|
||||||
|
glColor4ub(colors[3].r, colors[3].g, colors[3].b, colors[3].a);
|
||||||
|
glVertex2i(rect.x+rect.z, rect.y);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
14
GUIDraw.h
Normal file
14
GUIDraw.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
namespace GUIDraw
|
||||||
|
{
|
||||||
|
void DrawLine(const Vector2& a, const Vector2& b, const Color& color);
|
||||||
|
void DrawRect(const Vector4& rect, const Color& color);
|
||||||
|
void DrawRect(const Vector4& rect, const Color* colors);
|
||||||
|
void FillRect(const Vector4& rect, const Color& color);
|
||||||
|
void FillRect(const Vector4& rect, const Color* colors);
|
||||||
|
|
||||||
|
//void DrawNumTextBox(const Vector4& rect, float& num);
|
||||||
|
}
|
||||||
27
GUIKeyboard.cpp
Normal file
27
GUIKeyboard.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include "GUIKeyboard.h"
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
namespace GUIKeyboard
|
||||||
|
{
|
||||||
|
SDL_Keycode key {SDLK_UNKNOWN};
|
||||||
|
bool shift {false};
|
||||||
|
bool alt {false};
|
||||||
|
bool cmd {false};
|
||||||
|
|
||||||
|
void ReceiveKeyboardEvent(const SDL_Keycode key)
|
||||||
|
{
|
||||||
|
GUIKeyboard::key = key;
|
||||||
|
SDL_Keymod mod = SDL_GetModState();
|
||||||
|
shift = ((mod & KMOD_SHIFT) != KMOD_NONE);
|
||||||
|
alt = ((mod & KMOD_ALT ) != KMOD_NONE);
|
||||||
|
cmd = ((mod & KMOD_GUI ) != KMOD_NONE);
|
||||||
|
Application::NeedsUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
key = SDLK_UNKNOWN;
|
||||||
|
//shift = alt = cmd = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
GUIKeyboard.h
Normal file
15
GUIKeyboard.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
namespace GUIKeyboard
|
||||||
|
{
|
||||||
|
extern SDL_Keycode key;
|
||||||
|
extern bool shift;
|
||||||
|
extern bool alt;
|
||||||
|
extern bool cmd;
|
||||||
|
|
||||||
|
void ReceiveKeyboardEvent(const SDL_Keycode key);
|
||||||
|
void Reset();
|
||||||
|
}
|
||||||
72
GUIMouse.cpp
Normal file
72
GUIMouse.cpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#include "GUIMouse.h"
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
namespace GUIMouse
|
||||||
|
{
|
||||||
|
Vector2 position {0, 0};
|
||||||
|
Vector2 delta {0, 0};
|
||||||
|
Vector2 slowDelta {0, 0};
|
||||||
|
Vector2 wheel {0, 0};
|
||||||
|
ButtonState buttons[3] {ButtonState::Released, ButtonState::Released, ButtonState::Released};
|
||||||
|
Gesture gesture {};
|
||||||
|
|
||||||
|
Vector2 slowAccum {0, 0};
|
||||||
|
|
||||||
|
void ReceiveMouseUpEvent(const Button button)
|
||||||
|
{
|
||||||
|
buttons[button] = ButtonState::Up;
|
||||||
|
Application::NeedsUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReceiveMouseDownEvent(const Button button)
|
||||||
|
{
|
||||||
|
buttons[button] = ButtonState::Down;
|
||||||
|
Application::NeedsUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReceiveMouseMoveEvent(const float x, const float y)
|
||||||
|
{
|
||||||
|
delta = {x-position.x, y-position.y};
|
||||||
|
slowAccum += delta * 0.2f;
|
||||||
|
if (slowAccum.x >= 1 or slowAccum.x <= -1) {
|
||||||
|
slowDelta.x = int(slowAccum.x);
|
||||||
|
slowAccum.x = slowAccum.x - int(slowAccum.x);
|
||||||
|
}
|
||||||
|
if (slowAccum.y >= 1 or slowAccum.y <= -1) {
|
||||||
|
slowDelta.y = int(slowAccum.y);
|
||||||
|
slowAccum.y = slowAccum.y - int(slowAccum.y);
|
||||||
|
}
|
||||||
|
position = Vector2(x, y);
|
||||||
|
Application::NeedsUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReceiveMouseWheelEvent(const float x, const float y)
|
||||||
|
{
|
||||||
|
wheel = Vector2(x, y);
|
||||||
|
Application::NeedsUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReceiveMultigestureEvent(const float theta, const float dist, const int numFingers)
|
||||||
|
{
|
||||||
|
gesture.theta = theta;
|
||||||
|
gesture.dist = dist;
|
||||||
|
gesture.numFingers = numFingers;
|
||||||
|
Application::NeedsUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (buttons[i] == ButtonState::Down) {
|
||||||
|
buttons[i] = ButtonState::Pressed;
|
||||||
|
} else if (buttons[i] == ButtonState::Up) {
|
||||||
|
buttons[i] = ButtonState::Released;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wheel = {0,0};
|
||||||
|
delta = {0,0};
|
||||||
|
slowDelta = {0,0};
|
||||||
|
gesture.theta = gesture.dist = gesture.numFingers = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
GUIMouse.h
Normal file
30
GUIMouse.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
namespace GUIMouse
|
||||||
|
{
|
||||||
|
enum class ButtonState { Released, Down, Pressed, Up };
|
||||||
|
enum Button : char { Left = 0, Right = 1, Middle = 2 };
|
||||||
|
|
||||||
|
struct Gesture
|
||||||
|
{
|
||||||
|
float theta {0};
|
||||||
|
float dist {0};
|
||||||
|
int numFingers {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Vector2 position;
|
||||||
|
extern Vector2 delta;
|
||||||
|
extern Vector2 slowDelta;
|
||||||
|
extern Vector2 wheel;
|
||||||
|
extern ButtonState buttons[3];
|
||||||
|
extern Gesture gesture;
|
||||||
|
|
||||||
|
void ReceiveMouseUpEvent(const Button button);
|
||||||
|
void ReceiveMouseDownEvent(const Button button);
|
||||||
|
void ReceiveMouseMoveEvent(const float x, const float y);
|
||||||
|
void ReceiveMouseWheelEvent(const float x, const float y);
|
||||||
|
void ReceiveMultigestureEvent(const float theta, const float dist, const int numFingers);
|
||||||
|
void Reset();
|
||||||
|
}
|
||||||
3
GUIViewport.cpp
Normal file
3
GUIViewport.cpp
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include "GUIViewport.h"
|
||||||
|
|
||||||
|
Viewport viewports[3];
|
||||||
18
GUIViewport.h
Normal file
18
GUIViewport.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct Viewport
|
||||||
|
{
|
||||||
|
enum RenderMode { Wire, Solid, Textured, UV };
|
||||||
|
|
||||||
|
Vector4 bounds {};
|
||||||
|
RenderMode renderMode {Solid};
|
||||||
|
Vector2 offset {0, 0};
|
||||||
|
Vector2 rotation {10, 20};
|
||||||
|
float zoom {10.0f};
|
||||||
|
bool light {true};
|
||||||
|
bool grid {true};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Viewport viewports[3];
|
||||||
777
Matrices.cpp
Executable file
777
Matrices.cpp
Executable file
@@ -0,0 +1,777 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Matrice.cpp
|
||||||
|
// ===========
|
||||||
|
// NxN Matrix Math classes
|
||||||
|
//
|
||||||
|
// The elements of the matrix are stored as column major order.
|
||||||
|
// | 0 2 | | 0 3 6 | | 0 4 8 12 |
|
||||||
|
// | 1 3 | | 1 4 7 | | 1 5 9 13 |
|
||||||
|
// | 2 5 8 | | 2 6 10 14 |
|
||||||
|
// | 3 7 11 15 |
|
||||||
|
//
|
||||||
|
// AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
|
||||||
|
// CREATED: 2005-06-24
|
||||||
|
// UPDATED: 2014-09-21
|
||||||
|
//
|
||||||
|
// Copyright (C) 2005 Song Ho Ahn
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "Matrices.h"
|
||||||
|
|
||||||
|
const float DEG2RAD = 3.141593f / 180;
|
||||||
|
const float EPSILON = 0.00001f;
|
||||||
|
|
||||||
|
bool closeEnough(const float& a, const float& b, const float& epsilon = std::numeric_limits<float>::epsilon()) {
|
||||||
|
return (epsilon > std::abs(a - b));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// transpose 2x2 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix2& Matrix2::transpose()
|
||||||
|
{
|
||||||
|
std::swap(m[1], m[2]);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// return the determinant of 2x2 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
float Matrix2::getDeterminant()
|
||||||
|
{
|
||||||
|
return m[0] * m[3] - m[1] * m[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// inverse of 2x2 matrix
|
||||||
|
// If cannot find inverse, set identity matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix2& Matrix2::invert()
|
||||||
|
{
|
||||||
|
float determinant = getDeterminant();
|
||||||
|
if(fabs(determinant) <= EPSILON)
|
||||||
|
{
|
||||||
|
return identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
float tmp = m[0]; // copy the first element
|
||||||
|
float invDeterminant = 1.0f / determinant;
|
||||||
|
m[0] = invDeterminant * m[3];
|
||||||
|
m[1] = -invDeterminant * m[1];
|
||||||
|
m[2] = -invDeterminant * m[2];
|
||||||
|
m[3] = invDeterminant * tmp;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// transpose 3x3 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix3& Matrix3::transpose()
|
||||||
|
{
|
||||||
|
std::swap(m[1], m[3]);
|
||||||
|
std::swap(m[2], m[6]);
|
||||||
|
std::swap(m[5], m[7]);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// return determinant of 3x3 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
float Matrix3::getDeterminant()
|
||||||
|
{
|
||||||
|
return m[0] * (m[4] * m[8] - m[5] * m[7]) -
|
||||||
|
m[1] * (m[3] * m[8] - m[5] * m[6]) +
|
||||||
|
m[2] * (m[3] * m[7] - m[4] * m[6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// inverse 3x3 matrix
|
||||||
|
// If cannot find inverse, set identity matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix3& Matrix3::invert()
|
||||||
|
{
|
||||||
|
float determinant, invDeterminant;
|
||||||
|
float tmp[9];
|
||||||
|
|
||||||
|
tmp[0] = m[4] * m[8] - m[5] * m[7];
|
||||||
|
tmp[1] = m[2] * m[7] - m[1] * m[8];
|
||||||
|
tmp[2] = m[1] * m[5] - m[2] * m[4];
|
||||||
|
tmp[3] = m[5] * m[6] - m[3] * m[8];
|
||||||
|
tmp[4] = m[0] * m[8] - m[2] * m[6];
|
||||||
|
tmp[5] = m[2] * m[3] - m[0] * m[5];
|
||||||
|
tmp[6] = m[3] * m[7] - m[4] * m[6];
|
||||||
|
tmp[7] = m[1] * m[6] - m[0] * m[7];
|
||||||
|
tmp[8] = m[0] * m[4] - m[1] * m[3];
|
||||||
|
|
||||||
|
// check determinant if it is 0
|
||||||
|
determinant = m[0] * tmp[0] + m[1] * tmp[3] + m[2] * tmp[6];
|
||||||
|
if(fabs(determinant) <= EPSILON)
|
||||||
|
{
|
||||||
|
return identity(); // cannot inverse, make it idenety matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
// divide by the determinant
|
||||||
|
invDeterminant = 1.0f / determinant;
|
||||||
|
m[0] = invDeterminant * tmp[0];
|
||||||
|
m[1] = invDeterminant * tmp[1];
|
||||||
|
m[2] = invDeterminant * tmp[2];
|
||||||
|
m[3] = invDeterminant * tmp[3];
|
||||||
|
m[4] = invDeterminant * tmp[4];
|
||||||
|
m[5] = invDeterminant * tmp[5];
|
||||||
|
m[6] = invDeterminant * tmp[6];
|
||||||
|
m[7] = invDeterminant * tmp[7];
|
||||||
|
m[8] = invDeterminant * tmp[8];
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RAD2DEG 57.2957795f
|
||||||
|
|
||||||
|
const Vector3 Matrix4::eulerAngles() {
|
||||||
|
|
||||||
|
//check for gimbal lock
|
||||||
|
if (closeEnough(m[0+2*4], -1.0f)) {
|
||||||
|
float x = 0; //gimbal lock, value of x doesn't matter
|
||||||
|
float y = M_PI / 2;
|
||||||
|
float z = x + atan2(m[1+0*4], m[2+0*4]);
|
||||||
|
return { -x*RAD2DEG, -y*RAD2DEG, -z*RAD2DEG };
|
||||||
|
} else if (closeEnough(m[0+2*4], 1.0f)) {
|
||||||
|
float x = 0;
|
||||||
|
float y = -M_PI / 2;
|
||||||
|
float z = -x + atan2(-m[1+0*4], -m[2+0*4]);
|
||||||
|
return { -x*RAD2DEG, -y*RAD2DEG, -z*RAD2DEG };
|
||||||
|
} else { //two solutions exist
|
||||||
|
float x1 = -asin(m[0+2*4]);
|
||||||
|
float x2 = M_PI - x1;
|
||||||
|
|
||||||
|
float y1 = atan2(m[1+2*4] / cos(x1), m[2+2*4] / cos(x1));
|
||||||
|
float y2 = atan2(m[1+2*4] / cos(x2), m[2+2*4] / cos(x2));
|
||||||
|
|
||||||
|
float z1 = atan2(m[0+1*4] / cos(x1), m[0+0*4] / cos(x1));
|
||||||
|
float z2 = atan2(m[0+1*4] / cos(x2), m[0+0*4] / cos(x2));
|
||||||
|
|
||||||
|
//choose one solution to return
|
||||||
|
//for example the "shortest" rotation
|
||||||
|
if ((std::abs(x1) + std::abs(y1) + std::abs(z1)) <= (std::abs(x2) + std::abs(y2) + std::abs(z2))) {
|
||||||
|
return { -x1*RAD2DEG, -y1*RAD2DEG, -z1*RAD2DEG };
|
||||||
|
} else {
|
||||||
|
return { -x2*RAD2DEG, -y2*RAD2DEG, -z2*RAD2DEG };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// transpose 4x4 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::transpose()
|
||||||
|
{
|
||||||
|
std::swap(m[1], m[4]);
|
||||||
|
std::swap(m[2], m[8]);
|
||||||
|
std::swap(m[3], m[12]);
|
||||||
|
std::swap(m[6], m[9]);
|
||||||
|
std::swap(m[7], m[13]);
|
||||||
|
std::swap(m[11], m[14]);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// inverse 4x4 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::invert()
|
||||||
|
{
|
||||||
|
// If the 4th row is [0,0,0,1] then it is affine matrix and
|
||||||
|
// it has no projective transformation.
|
||||||
|
if(m[3] == 0 && m[7] == 0 && m[11] == 0 && m[15] == 1)
|
||||||
|
this->invertAffine();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->invertGeneral();
|
||||||
|
/*@@ invertProjective() is not optimized (slower than generic one)
|
||||||
|
if(fabs(m[0]*m[5] - m[1]*m[4]) > EPSILON)
|
||||||
|
this->invertProjective(); // inverse using matrix partition
|
||||||
|
else
|
||||||
|
this->invertGeneral(); // generalized inverse
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// compute the inverse of 4x4 Euclidean transformation matrix
|
||||||
|
//
|
||||||
|
// Euclidean transformation is translation, rotation, and reflection.
|
||||||
|
// With Euclidean transform, only the position and orientation of the object
|
||||||
|
// will be changed. Euclidean transform does not change the shape of an object
|
||||||
|
// (no scaling). Length and angle are reserved.
|
||||||
|
//
|
||||||
|
// Use inverseAffine() if the matrix has scale and shear transformation.
|
||||||
|
//
|
||||||
|
// M = [ R | T ]
|
||||||
|
// [ --+-- ] (R denotes 3x3 rotation/reflection matrix)
|
||||||
|
// [ 0 | 1 ] (T denotes 1x3 translation matrix)
|
||||||
|
//
|
||||||
|
// y = M*x -> y = R*x + T -> x = R^-1*(y - T) -> x = R^T*y - R^T*T
|
||||||
|
// (R is orthogonal, R^-1 = R^T)
|
||||||
|
//
|
||||||
|
// [ R | T ]-1 [ R^T | -R^T * T ] (R denotes 3x3 rotation matrix)
|
||||||
|
// [ --+-- ] = [ ----+--------- ] (T denotes 1x3 translation)
|
||||||
|
// [ 0 | 1 ] [ 0 | 1 ] (R^T denotes R-transpose)
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::invertEuclidean()
|
||||||
|
{
|
||||||
|
// transpose 3x3 rotation matrix part
|
||||||
|
// | R^T | 0 |
|
||||||
|
// | ----+-- |
|
||||||
|
// | 0 | 1 |
|
||||||
|
float tmp;
|
||||||
|
tmp = m[1]; m[1] = m[4]; m[4] = tmp;
|
||||||
|
tmp = m[2]; m[2] = m[8]; m[8] = tmp;
|
||||||
|
tmp = m[6]; m[6] = m[9]; m[9] = tmp;
|
||||||
|
|
||||||
|
// compute translation part -R^T * T
|
||||||
|
// | 0 | -R^T x |
|
||||||
|
// | --+------- |
|
||||||
|
// | 0 | 0 |
|
||||||
|
float x = m[12];
|
||||||
|
float y = m[13];
|
||||||
|
float z = m[14];
|
||||||
|
m[12] = -(m[0] * x + m[4] * y + m[8] * z);
|
||||||
|
m[13] = -(m[1] * x + m[5] * y + m[9] * z);
|
||||||
|
m[14] = -(m[2] * x + m[6] * y + m[10]* z);
|
||||||
|
|
||||||
|
// last row should be unchanged (0,0,0,1)
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// compute the inverse of a 4x4 affine transformation matrix
|
||||||
|
//
|
||||||
|
// Affine transformations are generalizations of Euclidean transformations.
|
||||||
|
// Affine transformation includes translation, rotation, reflection, scaling,
|
||||||
|
// and shearing. Length and angle are NOT preserved.
|
||||||
|
// M = [ R | T ]
|
||||||
|
// [ --+-- ] (R denotes 3x3 rotation/scale/shear matrix)
|
||||||
|
// [ 0 | 1 ] (T denotes 1x3 translation matrix)
|
||||||
|
//
|
||||||
|
// y = M*x -> y = R*x + T -> x = R^-1*(y - T) -> x = R^-1*y - R^-1*T
|
||||||
|
//
|
||||||
|
// [ R | T ]-1 [ R^-1 | -R^-1 * T ]
|
||||||
|
// [ --+-- ] = [ -----+---------- ]
|
||||||
|
// [ 0 | 1 ] [ 0 + 1 ]
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::invertAffine()
|
||||||
|
{
|
||||||
|
// R^-1
|
||||||
|
Matrix3 r(m[0],m[1],m[2], m[4],m[5],m[6], m[8],m[9],m[10]);
|
||||||
|
r.invert();
|
||||||
|
m[0] = r[0]; m[1] = r[1]; m[2] = r[2];
|
||||||
|
m[4] = r[3]; m[5] = r[4]; m[6] = r[5];
|
||||||
|
m[8] = r[6]; m[9] = r[7]; m[10]= r[8];
|
||||||
|
|
||||||
|
// -R^-1 * T
|
||||||
|
float x = m[12];
|
||||||
|
float y = m[13];
|
||||||
|
float z = m[14];
|
||||||
|
m[12] = -(r[0] * x + r[3] * y + r[6] * z);
|
||||||
|
m[13] = -(r[1] * x + r[4] * y + r[7] * z);
|
||||||
|
m[14] = -(r[2] * x + r[5] * y + r[8] * z);
|
||||||
|
|
||||||
|
// last row should be unchanged (0,0,0,1)
|
||||||
|
//m[3] = m[7] = m[11] = 0.0f;
|
||||||
|
//m[15] = 1.0f;
|
||||||
|
|
||||||
|
return * this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// inverse matrix using matrix partitioning (blockwise inverse)
|
||||||
|
// It devides a 4x4 matrix into 4 of 2x2 matrices. It works in case of where
|
||||||
|
// det(A) != 0. If not, use the generic inverse method
|
||||||
|
// inverse formula.
|
||||||
|
// M = [ A | B ] A, B, C, D are 2x2 matrix blocks
|
||||||
|
// [ --+-- ] det(M) = |A| * |D - ((C * A^-1) * B)|
|
||||||
|
// [ C | D ]
|
||||||
|
//
|
||||||
|
// M^-1 = [ A' | B' ] A' = A^-1 - (A^-1 * B) * C'
|
||||||
|
// [ ---+--- ] B' = (A^-1 * B) * -D'
|
||||||
|
// [ C' | D' ] C' = -D' * (C * A^-1)
|
||||||
|
// D' = (D - ((C * A^-1) * B))^-1
|
||||||
|
//
|
||||||
|
// NOTE: I wrap with () if it it used more than once.
|
||||||
|
// The matrix is invertable even if det(A)=0, so must check det(A) before
|
||||||
|
// calling this function, and use invertGeneric() instead.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::invertProjective()
|
||||||
|
{
|
||||||
|
// partition
|
||||||
|
Matrix2 a(m[0], m[1], m[4], m[5]);
|
||||||
|
Matrix2 b(m[8], m[9], m[12], m[13]);
|
||||||
|
Matrix2 c(m[2], m[3], m[6], m[7]);
|
||||||
|
Matrix2 d(m[10], m[11], m[14], m[15]);
|
||||||
|
|
||||||
|
// pre-compute repeated parts
|
||||||
|
a.invert(); // A^-1
|
||||||
|
Matrix2 ab = a * b; // A^-1 * B
|
||||||
|
Matrix2 ca = c * a; // C * A^-1
|
||||||
|
Matrix2 cab = ca * b; // C * A^-1 * B
|
||||||
|
Matrix2 dcab = d - cab; // D - C * A^-1 * B
|
||||||
|
|
||||||
|
// check determinant if |D - C * A^-1 * B| = 0
|
||||||
|
//NOTE: this function assumes det(A) is already checked. if |A|=0 then,
|
||||||
|
// cannot use this function.
|
||||||
|
float determinant = dcab[0] * dcab[3] - dcab[1] * dcab[2];
|
||||||
|
if(fabs(determinant) <= EPSILON)
|
||||||
|
{
|
||||||
|
return identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute D' and -D'
|
||||||
|
Matrix2 d1 = dcab; // (D - C * A^-1 * B)
|
||||||
|
d1.invert(); // (D - C * A^-1 * B)^-1
|
||||||
|
Matrix2 d2 = -d1; // -(D - C * A^-1 * B)^-1
|
||||||
|
|
||||||
|
// compute C'
|
||||||
|
Matrix2 c1 = d2 * ca; // -D' * (C * A^-1)
|
||||||
|
|
||||||
|
// compute B'
|
||||||
|
Matrix2 b1 = ab * d2; // (A^-1 * B) * -D'
|
||||||
|
|
||||||
|
// compute A'
|
||||||
|
Matrix2 a1 = a - (ab * c1); // A^-1 - (A^-1 * B) * C'
|
||||||
|
|
||||||
|
// assemble inverse matrix
|
||||||
|
m[0] = a1[0]; m[4] = a1[2]; /*|*/ m[8] = b1[0]; m[12]= b1[2];
|
||||||
|
m[1] = a1[1]; m[5] = a1[3]; /*|*/ m[9] = b1[1]; m[13]= b1[3];
|
||||||
|
/*-----------------------------+-----------------------------*/
|
||||||
|
m[2] = c1[0]; m[6] = c1[2]; /*|*/ m[10]= d1[0]; m[14]= d1[2];
|
||||||
|
m[3] = c1[1]; m[7] = c1[3]; /*|*/ m[11]= d1[1]; m[15]= d1[3];
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// compute the inverse of a general 4x4 matrix using Cramer's Rule
|
||||||
|
// If cannot find inverse, return indentity matrix
|
||||||
|
// M^-1 = adj(M) / det(M)
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::invertGeneral()
|
||||||
|
{
|
||||||
|
// get cofactors of minor matrices
|
||||||
|
float cofactor0 = getCofactor(m[5],m[6],m[7], m[9],m[10],m[11], m[13],m[14],m[15]);
|
||||||
|
float cofactor1 = getCofactor(m[4],m[6],m[7], m[8],m[10],m[11], m[12],m[14],m[15]);
|
||||||
|
float cofactor2 = getCofactor(m[4],m[5],m[7], m[8],m[9], m[11], m[12],m[13],m[15]);
|
||||||
|
float cofactor3 = getCofactor(m[4],m[5],m[6], m[8],m[9], m[10], m[12],m[13],m[14]);
|
||||||
|
|
||||||
|
// get determinant
|
||||||
|
float determinant = m[0] * cofactor0 - m[1] * cofactor1 + m[2] * cofactor2 - m[3] * cofactor3;
|
||||||
|
if(fabs(determinant) <= EPSILON)
|
||||||
|
{
|
||||||
|
return identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get rest of cofactors for adj(M)
|
||||||
|
float cofactor4 = getCofactor(m[1],m[2],m[3], m[9],m[10],m[11], m[13],m[14],m[15]);
|
||||||
|
float cofactor5 = getCofactor(m[0],m[2],m[3], m[8],m[10],m[11], m[12],m[14],m[15]);
|
||||||
|
float cofactor6 = getCofactor(m[0],m[1],m[3], m[8],m[9], m[11], m[12],m[13],m[15]);
|
||||||
|
float cofactor7 = getCofactor(m[0],m[1],m[2], m[8],m[9], m[10], m[12],m[13],m[14]);
|
||||||
|
|
||||||
|
float cofactor8 = getCofactor(m[1],m[2],m[3], m[5],m[6], m[7], m[13],m[14],m[15]);
|
||||||
|
float cofactor9 = getCofactor(m[0],m[2],m[3], m[4],m[6], m[7], m[12],m[14],m[15]);
|
||||||
|
float cofactor10= getCofactor(m[0],m[1],m[3], m[4],m[5], m[7], m[12],m[13],m[15]);
|
||||||
|
float cofactor11= getCofactor(m[0],m[1],m[2], m[4],m[5], m[6], m[12],m[13],m[14]);
|
||||||
|
|
||||||
|
float cofactor12= getCofactor(m[1],m[2],m[3], m[5],m[6], m[7], m[9], m[10],m[11]);
|
||||||
|
float cofactor13= getCofactor(m[0],m[2],m[3], m[4],m[6], m[7], m[8], m[10],m[11]);
|
||||||
|
float cofactor14= getCofactor(m[0],m[1],m[3], m[4],m[5], m[7], m[8], m[9], m[11]);
|
||||||
|
float cofactor15= getCofactor(m[0],m[1],m[2], m[4],m[5], m[6], m[8], m[9], m[10]);
|
||||||
|
|
||||||
|
// build inverse matrix = adj(M) / det(M)
|
||||||
|
// adjugate of M is the transpose of the cofactor matrix of M
|
||||||
|
float invDeterminant = 1.0f / determinant;
|
||||||
|
m[0] = invDeterminant * cofactor0;
|
||||||
|
m[1] = -invDeterminant * cofactor4;
|
||||||
|
m[2] = invDeterminant * cofactor8;
|
||||||
|
m[3] = -invDeterminant * cofactor12;
|
||||||
|
|
||||||
|
m[4] = -invDeterminant * cofactor1;
|
||||||
|
m[5] = invDeterminant * cofactor5;
|
||||||
|
m[6] = -invDeterminant * cofactor9;
|
||||||
|
m[7] = invDeterminant * cofactor13;
|
||||||
|
|
||||||
|
m[8] = invDeterminant * cofactor2;
|
||||||
|
m[9] = -invDeterminant * cofactor6;
|
||||||
|
m[10]= invDeterminant * cofactor10;
|
||||||
|
m[11]= -invDeterminant * cofactor14;
|
||||||
|
|
||||||
|
m[12]= -invDeterminant * cofactor3;
|
||||||
|
m[13]= invDeterminant * cofactor7;
|
||||||
|
m[14]= -invDeterminant * cofactor11;
|
||||||
|
m[15]= invDeterminant * cofactor15;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// return determinant of 4x4 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
float Matrix4::getDeterminant()
|
||||||
|
{
|
||||||
|
return m[0] * getCofactor(m[5],m[6],m[7], m[9],m[10],m[11], m[13],m[14],m[15]) -
|
||||||
|
m[1] * getCofactor(m[4],m[6],m[7], m[8],m[10],m[11], m[12],m[14],m[15]) +
|
||||||
|
m[2] * getCofactor(m[4],m[5],m[7], m[8],m[9], m[11], m[12],m[13],m[15]) -
|
||||||
|
m[3] * getCofactor(m[4],m[5],m[6], m[8],m[9], m[10], m[12],m[13],m[14]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// compute cofactor of 3x3 minor matrix without sign
|
||||||
|
// input params are 9 elements of the minor matrix
|
||||||
|
// NOTE: The caller must know its sign.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
float Matrix4::getCofactor(float m0, float m1, float m2,
|
||||||
|
float m3, float m4, float m5,
|
||||||
|
float m6, float m7, float m8)
|
||||||
|
{
|
||||||
|
return m0 * (m4 * m8 - m5 * m7) -
|
||||||
|
m1 * (m3 * m8 - m5 * m6) +
|
||||||
|
m2 * (m3 * m7 - m4 * m6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// translate this matrix by (x, y, z)
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::translate(const Vector3& v)
|
||||||
|
{
|
||||||
|
return translate(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4& Matrix4::translate(float x, float y, float z)
|
||||||
|
{
|
||||||
|
m[0] += m[3] * x; m[4] += m[7] * x; m[8] += m[11]* x; m[12]+= m[15]* x;
|
||||||
|
m[1] += m[3] * y; m[5] += m[7] * y; m[9] += m[11]* y; m[13]+= m[15]* y;
|
||||||
|
m[2] += m[3] * z; m[6] += m[7] * z; m[10]+= m[11]* z; m[14]+= m[15]* z;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// uniform scale
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::scale(float s)
|
||||||
|
{
|
||||||
|
return scale(s, s, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4& Matrix4::scale(float x, float y, float z)
|
||||||
|
{
|
||||||
|
m[0] *= x; m[4] *= x; m[8] *= x; m[12] *= x;
|
||||||
|
m[1] *= y; m[5] *= y; m[9] *= y; m[13] *= y;
|
||||||
|
m[2] *= z; m[6] *= z; m[10]*= z; m[14] *= z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// build a rotation matrix with given angle(degree) and rotation axis, then
|
||||||
|
// multiply it with this object
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4& Matrix4::rotate(float angle, const Vector3& axis)
|
||||||
|
{
|
||||||
|
return rotate(angle, axis.x, axis.y, axis.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4& Matrix4::rotate(float angle, float x, float y, float z)
|
||||||
|
{
|
||||||
|
float c = cosf(angle * DEG2RAD); // cosine
|
||||||
|
float s = sinf(angle * DEG2RAD); // sine
|
||||||
|
float c1 = 1.0f - c; // 1 - c
|
||||||
|
float m0 = m[0], m4 = m[4], m8 = m[8], m12= m[12],
|
||||||
|
m1 = m[1], m5 = m[5], m9 = m[9], m13= m[13],
|
||||||
|
m2 = m[2], m6 = m[6], m10= m[10], m14= m[14];
|
||||||
|
|
||||||
|
// build rotation matrix
|
||||||
|
float r0 = x * x * c1 + c;
|
||||||
|
float r1 = x * y * c1 + z * s;
|
||||||
|
float r2 = x * z * c1 - y * s;
|
||||||
|
float r4 = x * y * c1 - z * s;
|
||||||
|
float r5 = y * y * c1 + c;
|
||||||
|
float r6 = y * z * c1 + x * s;
|
||||||
|
float r8 = x * z * c1 + y * s;
|
||||||
|
float r9 = y * z * c1 - x * s;
|
||||||
|
float r10= z * z * c1 + c;
|
||||||
|
|
||||||
|
// multiply rotation matrix
|
||||||
|
m[0] = r0 * m0 + r4 * m1 + r8 * m2;
|
||||||
|
m[1] = r1 * m0 + r5 * m1 + r9 * m2;
|
||||||
|
m[2] = r2 * m0 + r6 * m1 + r10* m2;
|
||||||
|
m[4] = r0 * m4 + r4 * m5 + r8 * m6;
|
||||||
|
m[5] = r1 * m4 + r5 * m5 + r9 * m6;
|
||||||
|
m[6] = r2 * m4 + r6 * m5 + r10* m6;
|
||||||
|
m[8] = r0 * m8 + r4 * m9 + r8 * m10;
|
||||||
|
m[9] = r1 * m8 + r5 * m9 + r9 * m10;
|
||||||
|
m[10]= r2 * m8 + r6 * m9 + r10* m10;
|
||||||
|
m[12]= r0 * m12+ r4 * m13+ r8 * m14;
|
||||||
|
m[13]= r1 * m12+ r5 * m13+ r9 * m14;
|
||||||
|
m[14]= r2 * m12+ r6 * m13+ r10* m14;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4& Matrix4::rotateX(float angle)
|
||||||
|
{
|
||||||
|
float c = cosf(angle * DEG2RAD);
|
||||||
|
float s = sinf(angle * DEG2RAD);
|
||||||
|
float m1 = m[1], m2 = m[2],
|
||||||
|
m5 = m[5], m6 = m[6],
|
||||||
|
m9 = m[9], m10= m[10],
|
||||||
|
m13= m[13], m14= m[14];
|
||||||
|
|
||||||
|
m[1] = m1 * c + m2 *-s;
|
||||||
|
m[2] = m1 * s + m2 * c;
|
||||||
|
m[5] = m5 * c + m6 *-s;
|
||||||
|
m[6] = m5 * s + m6 * c;
|
||||||
|
m[9] = m9 * c + m10*-s;
|
||||||
|
m[10]= m9 * s + m10* c;
|
||||||
|
m[13]= m13* c + m14*-s;
|
||||||
|
m[14]= m13* s + m14* c;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4& Matrix4::rotateY(float angle)
|
||||||
|
{
|
||||||
|
float c = cosf(angle * DEG2RAD);
|
||||||
|
float s = sinf(angle * DEG2RAD);
|
||||||
|
float m0 = m[0], m2 = m[2],
|
||||||
|
m4 = m[4], m6 = m[6],
|
||||||
|
m8 = m[8], m10= m[10],
|
||||||
|
m12= m[12], m14= m[14];
|
||||||
|
|
||||||
|
m[0] = m0 * c + m2 * s;
|
||||||
|
m[2] = m0 *-s + m2 * c;
|
||||||
|
m[4] = m4 * c + m6 * s;
|
||||||
|
m[6] = m4 *-s + m6 * c;
|
||||||
|
m[8] = m8 * c + m10* s;
|
||||||
|
m[10]= m8 *-s + m10* c;
|
||||||
|
m[12]= m12* c + m14* s;
|
||||||
|
m[14]= m12*-s + m14* c;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4& Matrix4::rotateZ(float angle)
|
||||||
|
{
|
||||||
|
float c = cosf(angle * DEG2RAD);
|
||||||
|
float s = sinf(angle * DEG2RAD);
|
||||||
|
float m0 = m[0], m1 = m[1],
|
||||||
|
m4 = m[4], m5 = m[5],
|
||||||
|
m8 = m[8], m9 = m[9],
|
||||||
|
m12= m[12], m13= m[13];
|
||||||
|
|
||||||
|
m[0] = m0 * c + m1 *-s;
|
||||||
|
m[1] = m0 * s + m1 * c;
|
||||||
|
m[4] = m4 * c + m5 *-s;
|
||||||
|
m[5] = m4 * s + m5 * c;
|
||||||
|
m[8] = m8 * c + m9 *-s;
|
||||||
|
m[9] = m8 * s + m9 * c;
|
||||||
|
m[12]= m12* c + m13*-s;
|
||||||
|
m[13]= m12* s + m13* c;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// glFrustum()
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4 setFrustum(float l, float r, float b, float t, float n, float f)
|
||||||
|
{
|
||||||
|
Matrix4 mat;
|
||||||
|
mat[0] = 2 * n / (r - l);
|
||||||
|
mat[5] = 2 * n / (t - b);
|
||||||
|
mat[8] = (r + l) / (r - l);
|
||||||
|
mat[9] = (t + b) / (t - b);
|
||||||
|
mat[10] = -(f + n) / (f - n);
|
||||||
|
mat[11] = -1;
|
||||||
|
mat[14] = -(2 * f * n) / (f - n);
|
||||||
|
mat[15] = 0;
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// gluPerspective()
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4 setFrustum(float fovY, float aspect, float front, float back)
|
||||||
|
{
|
||||||
|
float tangent = tanf(fovY/2 * DEG2RAD); // tangent of half fovY
|
||||||
|
float height = front * tangent; // half height of near plane
|
||||||
|
float width = height * aspect; // half width of near plane
|
||||||
|
|
||||||
|
// params: left, right, bottom, top, near, far
|
||||||
|
return setFrustum(-width, width, -height, height, front, back);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// glOrtho()
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Matrix4 setOrthoFrustum(float l, float r, float b, float t, float n, float f)
|
||||||
|
{
|
||||||
|
Matrix4 mat;
|
||||||
|
mat[0] = 2 / (r - l);
|
||||||
|
mat[5] = 2 / (t - b);
|
||||||
|
mat[10] = -2 / (f - n);
|
||||||
|
mat[12] = -(r + l) / (r - l);
|
||||||
|
mat[13] = -(t + b) / (t - b);
|
||||||
|
mat[14] = -(f + n) / (f - n);
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4 lookAt(const Vector3& eye, const Vector3& center, const Vector3& up)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Matrix4 mat;
|
||||||
|
Vector3 forward = (center - eye);
|
||||||
|
forward.normalize();
|
||||||
|
Vector3 side = (up.cross(forward));
|
||||||
|
side.normalize();
|
||||||
|
|
||||||
|
// Recompute up as: up = side x forward
|
||||||
|
const Vector3 up2 = forward.cross(side);
|
||||||
|
|
||||||
|
mat.identity();
|
||||||
|
mat[0] = side.x;
|
||||||
|
mat[4] = side.y;
|
||||||
|
mat[8] = side.z;
|
||||||
|
|
||||||
|
mat[1] = up2.x;
|
||||||
|
mat[5] = up2.y;
|
||||||
|
mat[9] = up2.z;
|
||||||
|
|
||||||
|
mat[2] = forward.x;
|
||||||
|
mat[6] = forward.y;
|
||||||
|
mat[10] = forward.z;
|
||||||
|
|
||||||
|
//mat[3] = -side.dot(eye);
|
||||||
|
//mat[7] = -up2.dot(eye);
|
||||||
|
//mat[11] = forward.dot(eye);
|
||||||
|
//mat[15] = 1.0f;
|
||||||
|
Matrix4 trans;
|
||||||
|
trans.identity();
|
||||||
|
trans.translate(-eye.x, -eye.y, eye.z);
|
||||||
|
mat = mat * trans;
|
||||||
|
*/
|
||||||
|
|
||||||
|
float m[16];
|
||||||
|
float x[3], y[3], z[3];
|
||||||
|
float mag;
|
||||||
|
|
||||||
|
// Make rotation matrix
|
||||||
|
|
||||||
|
// Z vector
|
||||||
|
z[0] = eye.x - center.x;
|
||||||
|
z[1] = eye.y - center.y;
|
||||||
|
z[2] = eye.z - center.z;
|
||||||
|
mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
|
||||||
|
if (mag) { // mpichler, 19950515
|
||||||
|
z[0] /= mag;
|
||||||
|
z[1] /= mag;
|
||||||
|
z[2] /= mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Y vector
|
||||||
|
y[0] = up.x;
|
||||||
|
y[1] = up.y;
|
||||||
|
y[2] = up.z;
|
||||||
|
|
||||||
|
// X vector = Y cross Z
|
||||||
|
x[0] = y[1] * z[2] - y[2] * z[1];
|
||||||
|
x[1] = -y[0] * z[2] + y[2] * z[0];
|
||||||
|
x[2] = y[0] * z[1] - y[1] * z[0];
|
||||||
|
|
||||||
|
// Recompute Y = Z cross X
|
||||||
|
y[0] = z[1] * x[2] - z[2] * x[1];
|
||||||
|
y[1] = -z[0] * x[2] + z[2] * x[0];
|
||||||
|
y[2] = z[0] * x[1] - z[1] * x[0];
|
||||||
|
|
||||||
|
// mpichler, 19950515
|
||||||
|
// cross product gives area of parallelogram, which is < 1.0 for
|
||||||
|
//non-perpendicular unit-length vectors; so normalize x, y here
|
||||||
|
|
||||||
|
mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
|
||||||
|
if (mag) {
|
||||||
|
x[0] /= mag;
|
||||||
|
x[1] /= mag;
|
||||||
|
x[2] /= mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
|
||||||
|
if (mag) {
|
||||||
|
y[0] /= mag;
|
||||||
|
y[1] /= mag;
|
||||||
|
y[2] /= mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define M(row,col) m[col*4+row]
|
||||||
|
M(0, 0) = x[0];
|
||||||
|
M(0, 1) = x[1];
|
||||||
|
M(0, 2) = x[2];
|
||||||
|
M(0, 3) = 0.0;
|
||||||
|
M(1, 0) = y[0];
|
||||||
|
M(1, 1) = y[1];
|
||||||
|
M(1, 2) = y[2];
|
||||||
|
M(1, 3) = 0.0;
|
||||||
|
M(2, 0) = z[0];
|
||||||
|
M(2, 1) = z[1];
|
||||||
|
M(2, 2) = z[2];
|
||||||
|
M(2, 3) = 0.0;
|
||||||
|
M(3, 0) = 0.0;
|
||||||
|
M(3, 1) = 0.0;
|
||||||
|
M(3, 2) = 0.0;
|
||||||
|
M(3, 3) = 1.0;
|
||||||
|
#undef M
|
||||||
|
|
||||||
|
Matrix4 mat(m);
|
||||||
|
|
||||||
|
// Translate Eye to Origin
|
||||||
|
Matrix4 trans;
|
||||||
|
trans.identity();
|
||||||
|
trans.translate(-eye.x, -eye.y, -eye.z);
|
||||||
|
mat = mat * trans;
|
||||||
|
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
914
Matrices.h
Executable file
914
Matrices.h
Executable file
@@ -0,0 +1,914 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Matrice.h
|
||||||
|
// =========
|
||||||
|
// NxN Matrix Math classes
|
||||||
|
//
|
||||||
|
// The elements of the matrix are stored as column major order.
|
||||||
|
// | 0 2 | | 0 3 6 | | 0 4 8 12 |
|
||||||
|
// | 1 3 | | 1 4 7 | | 1 5 9 13 |
|
||||||
|
// | 2 5 8 | | 2 6 10 14 |
|
||||||
|
// | 3 7 11 15 |
|
||||||
|
//
|
||||||
|
// AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
|
||||||
|
// CREATED: 2005-06-24
|
||||||
|
// UPDATED: 2013-09-30
|
||||||
|
//
|
||||||
|
// Copyright (C) 2005 Song Ho Ahn
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef MATH_MATRICES_H
|
||||||
|
#define MATH_MATRICES_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include "Vectors.h"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// 2x2 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
class Matrix2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// constructors
|
||||||
|
Matrix2(); // init with identity
|
||||||
|
Matrix2(const float src[4]);
|
||||||
|
Matrix2(float m0, float m1, float m2, float m3);
|
||||||
|
|
||||||
|
void set(const float src[4]);
|
||||||
|
void set(float m0, float m1, float m2, float m3);
|
||||||
|
void setRow(int index, const float row[2]);
|
||||||
|
void setRow(int index, const Vector2& v);
|
||||||
|
void setColumn(int index, const float col[2]);
|
||||||
|
void setColumn(int index, const Vector2& v);
|
||||||
|
|
||||||
|
const float* get() const;
|
||||||
|
float getDeterminant();
|
||||||
|
|
||||||
|
Matrix2& identity();
|
||||||
|
Matrix2& transpose(); // transpose itself and return reference
|
||||||
|
Matrix2& invert();
|
||||||
|
|
||||||
|
// operators
|
||||||
|
Matrix2 operator+(const Matrix2& rhs) const; // add rhs
|
||||||
|
Matrix2 operator-(const Matrix2& rhs) const; // subtract rhs
|
||||||
|
Matrix2& operator+=(const Matrix2& rhs); // add rhs and update this object
|
||||||
|
Matrix2& operator-=(const Matrix2& rhs); // subtract rhs and update this object
|
||||||
|
Vector2 operator*(const Vector2& rhs) const; // multiplication: v' = M * v
|
||||||
|
Matrix2 operator*(const Matrix2& rhs) const; // multiplication: M3 = M1 * M2
|
||||||
|
Matrix2& operator*=(const Matrix2& rhs); // multiplication: M1' = M1 * M2
|
||||||
|
bool operator==(const Matrix2& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator!=(const Matrix2& rhs) const; // exact compare, no epsilon
|
||||||
|
float operator[](int index) const; // subscript operator v[0], v[1]
|
||||||
|
float& operator[](int index); // subscript operator v[0], v[1]
|
||||||
|
|
||||||
|
friend Matrix2 operator-(const Matrix2& m); // unary operator (-)
|
||||||
|
friend Matrix2 operator*(float scalar, const Matrix2& m); // pre-multiplication
|
||||||
|
friend Vector2 operator*(const Vector2& vec, const Matrix2& m); // pre-multiplication
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const Matrix2& m);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m[4];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// 3x3 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
class Matrix3
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// constructors
|
||||||
|
Matrix3(); // init with identity
|
||||||
|
Matrix3(const float src[9]);
|
||||||
|
Matrix3(float m0, float m1, float m2, // 1st column
|
||||||
|
float m3, float m4, float m5, // 2nd column
|
||||||
|
float m6, float m7, float m8); // 3rd column
|
||||||
|
|
||||||
|
void set(const float src[9]);
|
||||||
|
void set(float m0, float m1, float m2, // 1st column
|
||||||
|
float m3, float m4, float m5, // 2nd column
|
||||||
|
float m6, float m7, float m8); // 3rd column
|
||||||
|
void setRow(int index, const float row[3]);
|
||||||
|
void setRow(int index, const Vector3& v);
|
||||||
|
void setColumn(int index, const float col[3]);
|
||||||
|
void setColumn(int index, const Vector3& v);
|
||||||
|
|
||||||
|
const float* get() const;
|
||||||
|
float getDeterminant();
|
||||||
|
|
||||||
|
Matrix3& identity();
|
||||||
|
Matrix3& transpose(); // transpose itself and return reference
|
||||||
|
Matrix3& invert();
|
||||||
|
|
||||||
|
// operators
|
||||||
|
Matrix3 operator+(const Matrix3& rhs) const; // add rhs
|
||||||
|
Matrix3 operator-(const Matrix3& rhs) const; // subtract rhs
|
||||||
|
Matrix3& operator+=(const Matrix3& rhs); // add rhs and update this object
|
||||||
|
Matrix3& operator-=(const Matrix3& rhs); // subtract rhs and update this object
|
||||||
|
Vector3 operator*(const Vector3& rhs) const; // multiplication: v' = M * v
|
||||||
|
Matrix3 operator*(const Matrix3& rhs) const; // multiplication: M3 = M1 * M2
|
||||||
|
Matrix3& operator*=(const Matrix3& rhs); // multiplication: M1' = M1 * M2
|
||||||
|
bool operator==(const Matrix3& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator!=(const Matrix3& rhs) const; // exact compare, no epsilon
|
||||||
|
float operator[](int index) const; // subscript operator v[0], v[1]
|
||||||
|
float& operator[](int index); // subscript operator v[0], v[1]
|
||||||
|
|
||||||
|
friend Matrix3 operator-(const Matrix3& m); // unary operator (-)
|
||||||
|
friend Matrix3 operator*(float scalar, const Matrix3& m); // pre-multiplication
|
||||||
|
friend Vector3 operator*(const Vector3& vec, const Matrix3& m); // pre-multiplication
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const Matrix3& m);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m[9];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// 4x4 matrix
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
class Matrix4
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// constructors
|
||||||
|
Matrix4(); // init with identity
|
||||||
|
Matrix4(const float src[16]);
|
||||||
|
Matrix4(float m00, float m01, float m02, float m03, // 1st column
|
||||||
|
float m04, float m05, float m06, float m07, // 2nd column
|
||||||
|
float m08, float m09, float m10, float m11, // 3rd column
|
||||||
|
float m12, float m13, float m14, float m15);// 4th column
|
||||||
|
|
||||||
|
void set(const float src[16]);
|
||||||
|
void set(float m00, float m01, float m02, float m03, // 1st column
|
||||||
|
float m04, float m05, float m06, float m07, // 2nd column
|
||||||
|
float m08, float m09, float m10, float m11, // 3rd column
|
||||||
|
float m12, float m13, float m14, float m15);// 4th column
|
||||||
|
void setRow(int index, const float row[4]);
|
||||||
|
void setRow(int index, const Vector4& v);
|
||||||
|
void setRow(int index, const Vector3& v);
|
||||||
|
void setColumn(int index, const float col[4]);
|
||||||
|
void setColumn(int index, const Vector4& v);
|
||||||
|
void setColumn(int index, const Vector3& v);
|
||||||
|
|
||||||
|
const float* get() const;
|
||||||
|
const float* getTranspose(); // return transposed matrix
|
||||||
|
float getDeterminant();
|
||||||
|
|
||||||
|
const Vector3 eulerAngles();
|
||||||
|
Matrix4& identity();
|
||||||
|
Matrix4& transpose(); // transpose itself and return reference
|
||||||
|
Matrix4& invert(); // check best inverse method before inverse
|
||||||
|
Matrix4& invertEuclidean(); // inverse of Euclidean transform matrix
|
||||||
|
Matrix4& invertAffine(); // inverse of affine transform matrix
|
||||||
|
Matrix4& invertProjective(); // inverse of projective matrix using partitioning
|
||||||
|
Matrix4& invertGeneral(); // inverse of generic matrix
|
||||||
|
|
||||||
|
// transform matrix
|
||||||
|
Matrix4& translate(float x, float y, float z); // translation by (x,y,z)
|
||||||
|
Matrix4& translate(const Vector3& v); //
|
||||||
|
Matrix4& rotate(float angle, const Vector3& axis); // rotate angle(degree) along the given axix
|
||||||
|
Matrix4& rotate(float angle, float x, float y, float z);
|
||||||
|
Matrix4& rotateX(float angle); // rotate on X-axis with degree
|
||||||
|
Matrix4& rotateY(float angle); // rotate on Y-axis with degree
|
||||||
|
Matrix4& rotateZ(float angle); // rotate on Z-axis with degree
|
||||||
|
Matrix4& scale(float scale); // uniform scale
|
||||||
|
Matrix4& scale(float sx, float sy, float sz); // scale by (sx, sy, sz) on each axis
|
||||||
|
|
||||||
|
// operators
|
||||||
|
Matrix4 operator+(const Matrix4& rhs) const; // add rhs
|
||||||
|
Matrix4 operator-(const Matrix4& rhs) const; // subtract rhs
|
||||||
|
Matrix4& operator+=(const Matrix4& rhs); // add rhs and update this object
|
||||||
|
Matrix4& operator-=(const Matrix4& rhs); // subtract rhs and update this object
|
||||||
|
Vector4 operator*(const Vector4& rhs) const; // multiplication: v' = M * v
|
||||||
|
Vector3 operator*(const Vector3& rhs) const; // multiplication: v' = M * v
|
||||||
|
Matrix4 operator*(const Matrix4& rhs) const; // multiplication: M3 = M1 * M2
|
||||||
|
Matrix4& operator*=(const Matrix4& rhs); // multiplication: M1' = M1 * M2
|
||||||
|
bool operator==(const Matrix4& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator!=(const Matrix4& rhs) const; // exact compare, no epsilon
|
||||||
|
float operator[](int index) const; // subscript operator v[0], v[1]
|
||||||
|
float& operator[](int index); // subscript operator v[0], v[1]
|
||||||
|
|
||||||
|
friend Matrix4 operator-(const Matrix4& m); // unary operator (-)
|
||||||
|
friend Matrix4 operator*(float scalar, const Matrix4& m); // pre-multiplication
|
||||||
|
friend Vector3 operator*(const Vector3& vec, const Matrix4& m); // pre-multiplication
|
||||||
|
friend Vector4 operator*(const Vector4& vec, const Matrix4& m); // pre-multiplication
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const Matrix4& m);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
private:
|
||||||
|
float getCofactor(float m0, float m1, float m2,
|
||||||
|
float m3, float m4, float m5,
|
||||||
|
float m6, float m7, float m8);
|
||||||
|
|
||||||
|
float m[16];
|
||||||
|
float tm[16]; // transpose m
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Matrix4 setFrustum(float l, float r, float b, float t, float n, float f);
|
||||||
|
Matrix4 setFrustum(float fovY, float aspect, float front, float back);
|
||||||
|
Matrix4 setOrthoFrustum(float l, float r, float b, float t, float n, float f);
|
||||||
|
Matrix4 lookAt(const Vector3& eye, const Vector3& center, const Vector3& up);
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// inline functions for Matrix2
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
inline Matrix2::Matrix2()
|
||||||
|
{
|
||||||
|
// initially identity matrix
|
||||||
|
identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2::Matrix2(const float src[4])
|
||||||
|
{
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2::Matrix2(float m0, float m1, float m2, float m3)
|
||||||
|
{
|
||||||
|
set(m0, m1, m2, m3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix2::set(const float src[4])
|
||||||
|
{
|
||||||
|
m[0] = src[0]; m[1] = src[1]; m[2] = src[2]; m[3] = src[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix2::set(float m0, float m1, float m2, float m3)
|
||||||
|
{
|
||||||
|
m[0]= m0; m[1] = m1; m[2] = m2; m[3]= m3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix2::setRow(int index, const float row[2])
|
||||||
|
{
|
||||||
|
m[index] = row[0]; m[index + 2] = row[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix2::setRow(int index, const Vector2& v)
|
||||||
|
{
|
||||||
|
m[index] = v.x; m[index + 2] = v.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix2::setColumn(int index, const float col[2])
|
||||||
|
{
|
||||||
|
m[index*2] = col[0]; m[index*2 + 1] = col[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix2::setColumn(int index, const Vector2& v)
|
||||||
|
{
|
||||||
|
m[index*2] = v.x; m[index*2 + 1] = v.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline const float* Matrix2::get() const
|
||||||
|
{
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2& Matrix2::identity()
|
||||||
|
{
|
||||||
|
m[0] = m[3] = 1.0f;
|
||||||
|
m[1] = m[2] = 0.0f;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2 Matrix2::operator+(const Matrix2& rhs) const
|
||||||
|
{
|
||||||
|
return Matrix2(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2], m[3]+rhs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2 Matrix2::operator-(const Matrix2& rhs) const
|
||||||
|
{
|
||||||
|
return Matrix2(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2], m[3]-rhs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2& Matrix2::operator+=(const Matrix2& rhs)
|
||||||
|
{
|
||||||
|
m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2]; m[3] += rhs[3];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2& Matrix2::operator-=(const Matrix2& rhs)
|
||||||
|
{
|
||||||
|
m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2]; m[3] -= rhs[3];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector2 Matrix2::operator*(const Vector2& rhs) const
|
||||||
|
{
|
||||||
|
return Vector2(m[0]*rhs.x + m[2]*rhs.y, m[1]*rhs.x + m[3]*rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2 Matrix2::operator*(const Matrix2& rhs) const
|
||||||
|
{
|
||||||
|
return Matrix2(m[0]*rhs[0] + m[2]*rhs[1], m[1]*rhs[0] + m[3]*rhs[1],
|
||||||
|
m[0]*rhs[2] + m[2]*rhs[3], m[1]*rhs[2] + m[3]*rhs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2& Matrix2::operator*=(const Matrix2& rhs)
|
||||||
|
{
|
||||||
|
*this = *this * rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Matrix2::operator==(const Matrix2& rhs) const
|
||||||
|
{
|
||||||
|
return (m[0] == rhs[0]) && (m[1] == rhs[1]) && (m[2] == rhs[2]) && (m[3] == rhs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Matrix2::operator!=(const Matrix2& rhs) const
|
||||||
|
{
|
||||||
|
return (m[0] != rhs[0]) || (m[1] != rhs[1]) || (m[2] != rhs[2]) || (m[3] != rhs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline float Matrix2::operator[](int index) const
|
||||||
|
{
|
||||||
|
return m[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline float& Matrix2::operator[](int index)
|
||||||
|
{
|
||||||
|
return m[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2 operator-(const Matrix2& rhs)
|
||||||
|
{
|
||||||
|
return Matrix2(-rhs[0], -rhs[1], -rhs[2], -rhs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix2 operator*(float s, const Matrix2& rhs)
|
||||||
|
{
|
||||||
|
return Matrix2(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector2 operator*(const Vector2& v, const Matrix2& rhs)
|
||||||
|
{
|
||||||
|
return Vector2(v.x*rhs[0] + v.y*rhs[1], v.x*rhs[2] + v.y*rhs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const Matrix2& m)
|
||||||
|
{
|
||||||
|
os << std::fixed << std::setprecision(5);
|
||||||
|
os << "[" << std::setw(10) << m[0] << " " << std::setw(10) << m[2] << "]\n"
|
||||||
|
<< "[" << std::setw(10) << m[1] << " " << std::setw(10) << m[3] << "]\n";
|
||||||
|
os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
// END OF MATRIX2 INLINE //////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// inline functions for Matrix3
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
inline Matrix3::Matrix3()
|
||||||
|
{
|
||||||
|
// initially identity matrix
|
||||||
|
identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3::Matrix3(const float src[9])
|
||||||
|
{
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3::Matrix3(float m0, float m1, float m2,
|
||||||
|
float m3, float m4, float m5,
|
||||||
|
float m6, float m7, float m8)
|
||||||
|
{
|
||||||
|
set(m0, m1, m2, m3, m4, m5, m6, m7, m8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix3::set(const float src[9])
|
||||||
|
{
|
||||||
|
m[0] = src[0]; m[1] = src[1]; m[2] = src[2];
|
||||||
|
m[3] = src[3]; m[4] = src[4]; m[5] = src[5];
|
||||||
|
m[6] = src[6]; m[7] = src[7]; m[8] = src[8];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix3::set(float m0, float m1, float m2,
|
||||||
|
float m3, float m4, float m5,
|
||||||
|
float m6, float m7, float m8)
|
||||||
|
{
|
||||||
|
m[0] = m0; m[1] = m1; m[2] = m2;
|
||||||
|
m[3] = m3; m[4] = m4; m[5] = m5;
|
||||||
|
m[6] = m6; m[7] = m7; m[8] = m8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix3::setRow(int index, const float row[3])
|
||||||
|
{
|
||||||
|
m[index] = row[0]; m[index + 3] = row[1]; m[index + 6] = row[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix3::setRow(int index, const Vector3& v)
|
||||||
|
{
|
||||||
|
m[index] = v.x; m[index + 3] = v.y; m[index + 6] = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix3::setColumn(int index, const float col[3])
|
||||||
|
{
|
||||||
|
m[index*3] = col[0]; m[index*3 + 1] = col[1]; m[index*3 + 2] = col[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix3::setColumn(int index, const Vector3& v)
|
||||||
|
{
|
||||||
|
m[index*3] = v.x; m[index*3 + 1] = v.y; m[index*3 + 2] = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline const float* Matrix3::get() const
|
||||||
|
{
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3& Matrix3::identity()
|
||||||
|
{
|
||||||
|
m[0] = m[4] = m[8] = 1.0f;
|
||||||
|
m[1] = m[2] = m[3] = m[5] = m[6] = m[7] = 0.0f;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3 Matrix3::operator+(const Matrix3& rhs) const
|
||||||
|
{
|
||||||
|
return Matrix3(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2],
|
||||||
|
m[3]+rhs[3], m[4]+rhs[4], m[5]+rhs[5],
|
||||||
|
m[6]+rhs[6], m[7]+rhs[7], m[8]+rhs[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3 Matrix3::operator-(const Matrix3& rhs) const
|
||||||
|
{
|
||||||
|
return Matrix3(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2],
|
||||||
|
m[3]-rhs[3], m[4]-rhs[4], m[5]-rhs[5],
|
||||||
|
m[6]-rhs[6], m[7]-rhs[7], m[8]-rhs[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3& Matrix3::operator+=(const Matrix3& rhs)
|
||||||
|
{
|
||||||
|
m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2];
|
||||||
|
m[3] += rhs[3]; m[4] += rhs[4]; m[5] += rhs[5];
|
||||||
|
m[6] += rhs[6]; m[7] += rhs[7]; m[8] += rhs[8];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3& Matrix3::operator-=(const Matrix3& rhs)
|
||||||
|
{
|
||||||
|
m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2];
|
||||||
|
m[3] -= rhs[3]; m[4] -= rhs[4]; m[5] -= rhs[5];
|
||||||
|
m[6] -= rhs[6]; m[7] -= rhs[7]; m[8] -= rhs[8];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector3 Matrix3::operator*(const Vector3& rhs) const
|
||||||
|
{
|
||||||
|
return Vector3(m[0]*rhs.x + m[3]*rhs.y + m[6]*rhs.z,
|
||||||
|
m[1]*rhs.x + m[4]*rhs.y + m[7]*rhs.z,
|
||||||
|
m[2]*rhs.x + m[5]*rhs.y + m[8]*rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3 Matrix3::operator*(const Matrix3& rhs) const
|
||||||
|
{
|
||||||
|
return Matrix3(m[0]*rhs[0] + m[3]*rhs[1] + m[6]*rhs[2], m[1]*rhs[0] + m[4]*rhs[1] + m[7]*rhs[2], m[2]*rhs[0] + m[5]*rhs[1] + m[8]*rhs[2],
|
||||||
|
m[0]*rhs[3] + m[3]*rhs[4] + m[6]*rhs[5], m[1]*rhs[3] + m[4]*rhs[4] + m[7]*rhs[5], m[2]*rhs[3] + m[5]*rhs[4] + m[8]*rhs[5],
|
||||||
|
m[0]*rhs[6] + m[3]*rhs[7] + m[6]*rhs[8], m[1]*rhs[6] + m[4]*rhs[7] + m[7]*rhs[8], m[2]*rhs[6] + m[5]*rhs[7] + m[8]*rhs[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3& Matrix3::operator*=(const Matrix3& rhs)
|
||||||
|
{
|
||||||
|
*this = *this * rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Matrix3::operator==(const Matrix3& rhs) const
|
||||||
|
{
|
||||||
|
return (m[0] == rhs[0]) && (m[1] == rhs[1]) && (m[2] == rhs[2]) &&
|
||||||
|
(m[3] == rhs[3]) && (m[4] == rhs[4]) && (m[5] == rhs[5]) &&
|
||||||
|
(m[6] == rhs[6]) && (m[7] == rhs[7]) && (m[8] == rhs[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Matrix3::operator!=(const Matrix3& rhs) const
|
||||||
|
{
|
||||||
|
return (m[0] != rhs[0]) || (m[1] != rhs[1]) || (m[2] != rhs[2]) ||
|
||||||
|
(m[3] != rhs[3]) || (m[4] != rhs[4]) || (m[5] != rhs[5]) ||
|
||||||
|
(m[6] != rhs[6]) || (m[7] != rhs[7]) || (m[8] != rhs[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline float Matrix3::operator[](int index) const
|
||||||
|
{
|
||||||
|
return m[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline float& Matrix3::operator[](int index)
|
||||||
|
{
|
||||||
|
return m[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3 operator-(const Matrix3& rhs)
|
||||||
|
{
|
||||||
|
return Matrix3(-rhs[0], -rhs[1], -rhs[2], -rhs[3], -rhs[4], -rhs[5], -rhs[6], -rhs[7], -rhs[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix3 operator*(float s, const Matrix3& rhs)
|
||||||
|
{
|
||||||
|
return Matrix3(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3], s*rhs[4], s*rhs[5], s*rhs[6], s*rhs[7], s*rhs[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector3 operator*(const Vector3& v, const Matrix3& m)
|
||||||
|
{
|
||||||
|
return Vector3(v.x*m[0] + v.y*m[1] + v.z*m[2], v.x*m[3] + v.y*m[4] + v.z*m[5], v.x*m[6] + v.y*m[7] + v.z*m[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const Matrix3& m)
|
||||||
|
{
|
||||||
|
os << std::fixed << std::setprecision(5);
|
||||||
|
os << "[" << std::setw(10) << m[0] << " " << std::setw(10) << m[3] << " " << std::setw(10) << m[6] << "]\n"
|
||||||
|
<< "[" << std::setw(10) << m[1] << " " << std::setw(10) << m[4] << " " << std::setw(10) << m[7] << "]\n"
|
||||||
|
<< "[" << std::setw(10) << m[2] << " " << std::setw(10) << m[5] << " " << std::setw(10) << m[8] << "]\n";
|
||||||
|
os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
// END OF MATRIX3 INLINE //////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// inline functions for Matrix4
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
inline Matrix4::Matrix4()
|
||||||
|
{
|
||||||
|
// initially identity matrix
|
||||||
|
identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4::Matrix4(const float src[16])
|
||||||
|
{
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4::Matrix4(float m00, float m01, float m02, float m03,
|
||||||
|
float m04, float m05, float m06, float m07,
|
||||||
|
float m08, float m09, float m10, float m11,
|
||||||
|
float m12, float m13, float m14, float m15)
|
||||||
|
{
|
||||||
|
set(m00, m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12, m13, m14, m15);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix4::set(const float src[16])
|
||||||
|
{
|
||||||
|
m[0] = src[0]; m[1] = src[1]; m[2] = src[2]; m[3] = src[3];
|
||||||
|
m[4] = src[4]; m[5] = src[5]; m[6] = src[6]; m[7] = src[7];
|
||||||
|
m[8] = src[8]; m[9] = src[9]; m[10]= src[10]; m[11]= src[11];
|
||||||
|
m[12]= src[12]; m[13]= src[13]; m[14]= src[14]; m[15]= src[15];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix4::set(float m00, float m01, float m02, float m03,
|
||||||
|
float m04, float m05, float m06, float m07,
|
||||||
|
float m08, float m09, float m10, float m11,
|
||||||
|
float m12, float m13, float m14, float m15)
|
||||||
|
{
|
||||||
|
m[0] = m00; m[1] = m01; m[2] = m02; m[3] = m03;
|
||||||
|
m[4] = m04; m[5] = m05; m[6] = m06; m[7] = m07;
|
||||||
|
m[8] = m08; m[9] = m09; m[10]= m10; m[11]= m11;
|
||||||
|
m[12]= m12; m[13]= m13; m[14]= m14; m[15]= m15;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix4::setRow(int index, const float row[4])
|
||||||
|
{
|
||||||
|
m[index] = row[0]; m[index + 4] = row[1]; m[index + 8] = row[2]; m[index + 12] = row[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix4::setRow(int index, const Vector4& v)
|
||||||
|
{
|
||||||
|
m[index] = v.x; m[index + 4] = v.y; m[index + 8] = v.z; m[index + 12] = v.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix4::setRow(int index, const Vector3& v)
|
||||||
|
{
|
||||||
|
m[index] = v.x; m[index + 4] = v.y; m[index + 8] = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix4::setColumn(int index, const float col[4])
|
||||||
|
{
|
||||||
|
m[index*4] = col[0]; m[index*4 + 1] = col[1]; m[index*4 + 2] = col[2]; m[index*4 + 3] = col[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix4::setColumn(int index, const Vector4& v)
|
||||||
|
{
|
||||||
|
m[index*4] = v.x; m[index*4 + 1] = v.y; m[index*4 + 2] = v.z; m[index*4 + 3] = v.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void Matrix4::setColumn(int index, const Vector3& v)
|
||||||
|
{
|
||||||
|
m[index*4] = v.x; m[index*4 + 1] = v.y; m[index*4 + 2] = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline const float* Matrix4::get() const
|
||||||
|
{
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline const float* Matrix4::getTranspose()
|
||||||
|
{
|
||||||
|
tm[0] = m[0]; tm[1] = m[4]; tm[2] = m[8]; tm[3] = m[12];
|
||||||
|
tm[4] = m[1]; tm[5] = m[5]; tm[6] = m[9]; tm[7] = m[13];
|
||||||
|
tm[8] = m[2]; tm[9] = m[6]; tm[10]= m[10]; tm[11]= m[14];
|
||||||
|
tm[12]= m[3]; tm[13]= m[7]; tm[14]= m[11]; tm[15]= m[15];
|
||||||
|
return tm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4& Matrix4::identity()
|
||||||
|
{
|
||||||
|
m[0] = m[5] = m[10] = m[15] = 1.0f;
|
||||||
|
m[1] = m[2] = m[3] = m[4] = m[6] = m[7] = m[8] = m[9] = m[11] = m[12] = m[13] = m[14] = 0.0f;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4 Matrix4::operator+(const Matrix4& rhs) const
|
||||||
|
{
|
||||||
|
return Matrix4(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2], m[3]+rhs[3],
|
||||||
|
m[4]+rhs[4], m[5]+rhs[5], m[6]+rhs[6], m[7]+rhs[7],
|
||||||
|
m[8]+rhs[8], m[9]+rhs[9], m[10]+rhs[10], m[11]+rhs[11],
|
||||||
|
m[12]+rhs[12], m[13]+rhs[13], m[14]+rhs[14], m[15]+rhs[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4 Matrix4::operator-(const Matrix4& rhs) const
|
||||||
|
{
|
||||||
|
return Matrix4(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2], m[3]-rhs[3],
|
||||||
|
m[4]-rhs[4], m[5]-rhs[5], m[6]-rhs[6], m[7]-rhs[7],
|
||||||
|
m[8]-rhs[8], m[9]-rhs[9], m[10]-rhs[10], m[11]-rhs[11],
|
||||||
|
m[12]-rhs[12], m[13]-rhs[13], m[14]-rhs[14], m[15]-rhs[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4& Matrix4::operator+=(const Matrix4& rhs)
|
||||||
|
{
|
||||||
|
m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2]; m[3] += rhs[3];
|
||||||
|
m[4] += rhs[4]; m[5] += rhs[5]; m[6] += rhs[6]; m[7] += rhs[7];
|
||||||
|
m[8] += rhs[8]; m[9] += rhs[9]; m[10]+= rhs[10]; m[11]+= rhs[11];
|
||||||
|
m[12]+= rhs[12]; m[13]+= rhs[13]; m[14]+= rhs[14]; m[15]+= rhs[15];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4& Matrix4::operator-=(const Matrix4& rhs)
|
||||||
|
{
|
||||||
|
m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2]; m[3] -= rhs[3];
|
||||||
|
m[4] -= rhs[4]; m[5] -= rhs[5]; m[6] -= rhs[6]; m[7] -= rhs[7];
|
||||||
|
m[8] -= rhs[8]; m[9] -= rhs[9]; m[10]-= rhs[10]; m[11]-= rhs[11];
|
||||||
|
m[12]-= rhs[12]; m[13]-= rhs[13]; m[14]-= rhs[14]; m[15]-= rhs[15];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector4 Matrix4::operator*(const Vector4& rhs) const
|
||||||
|
{
|
||||||
|
return Vector4(m[0]*rhs.x + m[4]*rhs.y + m[8]*rhs.z + m[12]*rhs.w,
|
||||||
|
m[1]*rhs.x + m[5]*rhs.y + m[9]*rhs.z + m[13]*rhs.w,
|
||||||
|
m[2]*rhs.x + m[6]*rhs.y + m[10]*rhs.z + m[14]*rhs.w,
|
||||||
|
m[3]*rhs.x + m[7]*rhs.y + m[11]*rhs.z + m[15]*rhs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector3 Matrix4::operator*(const Vector3& rhs) const
|
||||||
|
{
|
||||||
|
return Vector3(m[0]*rhs.x + m[4]*rhs.y + m[8]*rhs.z,
|
||||||
|
m[1]*rhs.x + m[5]*rhs.y + m[9]*rhs.z,
|
||||||
|
m[2]*rhs.x + m[6]*rhs.y + m[10]*rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4 Matrix4::operator*(const Matrix4& n) const
|
||||||
|
{
|
||||||
|
return Matrix4(m[0]*n[0] + m[4]*n[1] + m[8]*n[2] + m[12]*n[3], m[1]*n[0] + m[5]*n[1] + m[9]*n[2] + m[13]*n[3], m[2]*n[0] + m[6]*n[1] + m[10]*n[2] + m[14]*n[3], m[3]*n[0] + m[7]*n[1] + m[11]*n[2] + m[15]*n[3],
|
||||||
|
m[0]*n[4] + m[4]*n[5] + m[8]*n[6] + m[12]*n[7], m[1]*n[4] + m[5]*n[5] + m[9]*n[6] + m[13]*n[7], m[2]*n[4] + m[6]*n[5] + m[10]*n[6] + m[14]*n[7], m[3]*n[4] + m[7]*n[5] + m[11]*n[6] + m[15]*n[7],
|
||||||
|
m[0]*n[8] + m[4]*n[9] + m[8]*n[10] + m[12]*n[11], m[1]*n[8] + m[5]*n[9] + m[9]*n[10] + m[13]*n[11], m[2]*n[8] + m[6]*n[9] + m[10]*n[10] + m[14]*n[11], m[3]*n[8] + m[7]*n[9] + m[11]*n[10] + m[15]*n[11],
|
||||||
|
m[0]*n[12] + m[4]*n[13] + m[8]*n[14] + m[12]*n[15], m[1]*n[12] + m[5]*n[13] + m[9]*n[14] + m[13]*n[15], m[2]*n[12] + m[6]*n[13] + m[10]*n[14] + m[14]*n[15], m[3]*n[12] + m[7]*n[13] + m[11]*n[14] + m[15]*n[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4& Matrix4::operator*=(const Matrix4& rhs)
|
||||||
|
{
|
||||||
|
*this = *this * rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Matrix4::operator==(const Matrix4& n) const
|
||||||
|
{
|
||||||
|
return (m[0] == n[0]) && (m[1] == n[1]) && (m[2] == n[2]) && (m[3] == n[3]) &&
|
||||||
|
(m[4] == n[4]) && (m[5] == n[5]) && (m[6] == n[6]) && (m[7] == n[7]) &&
|
||||||
|
(m[8] == n[8]) && (m[9] == n[9]) && (m[10]== n[10]) && (m[11]== n[11]) &&
|
||||||
|
(m[12]== n[12]) && (m[13]== n[13]) && (m[14]== n[14]) && (m[15]== n[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Matrix4::operator!=(const Matrix4& n) const
|
||||||
|
{
|
||||||
|
return (m[0] != n[0]) || (m[1] != n[1]) || (m[2] != n[2]) || (m[3] != n[3]) ||
|
||||||
|
(m[4] != n[4]) || (m[5] != n[5]) || (m[6] != n[6]) || (m[7] != n[7]) ||
|
||||||
|
(m[8] != n[8]) || (m[9] != n[9]) || (m[10]!= n[10]) || (m[11]!= n[11]) ||
|
||||||
|
(m[12]!= n[12]) || (m[13]!= n[13]) || (m[14]!= n[14]) || (m[15]!= n[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline float Matrix4::operator[](int index) const
|
||||||
|
{
|
||||||
|
return m[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline float& Matrix4::operator[](int index)
|
||||||
|
{
|
||||||
|
return m[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4 operator-(const Matrix4& rhs)
|
||||||
|
{
|
||||||
|
return Matrix4(-rhs[0], -rhs[1], -rhs[2], -rhs[3], -rhs[4], -rhs[5], -rhs[6], -rhs[7], -rhs[8], -rhs[9], -rhs[10], -rhs[11], -rhs[12], -rhs[13], -rhs[14], -rhs[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Matrix4 operator*(float s, const Matrix4& rhs)
|
||||||
|
{
|
||||||
|
return Matrix4(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3], s*rhs[4], s*rhs[5], s*rhs[6], s*rhs[7], s*rhs[8], s*rhs[9], s*rhs[10], s*rhs[11], s*rhs[12], s*rhs[13], s*rhs[14], s*rhs[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector4 operator*(const Vector4& v, const Matrix4& m)
|
||||||
|
{
|
||||||
|
return Vector4(v.x*m[0] + v.y*m[1] + v.z*m[2] + v.w*m[3], v.x*m[4] + v.y*m[5] + v.z*m[6] + v.w*m[7], v.x*m[8] + v.y*m[9] + v.z*m[10] + v.w*m[11], v.x*m[12] + v.y*m[13] + v.z*m[14] + v.w*m[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector3 operator*(const Vector3& v, const Matrix4& m)
|
||||||
|
{
|
||||||
|
return Vector3(v.x*m[0] + v.y*m[1] + v.z*m[2], v.x*m[4] + v.y*m[5] + v.z*m[6], v.x*m[8] + v.y*m[9] + v.z*m[10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const Matrix4& m)
|
||||||
|
{
|
||||||
|
os << std::fixed << std::setprecision(5);
|
||||||
|
os << "[" << std::setw(10) << m[0] << " " << std::setw(10) << m[4] << " " << std::setw(10) << m[8] << " " << std::setw(10) << m[12] << "]\n"
|
||||||
|
<< "[" << std::setw(10) << m[1] << " " << std::setw(10) << m[5] << " " << std::setw(10) << m[9] << " " << std::setw(10) << m[13] << "]\n"
|
||||||
|
<< "[" << std::setw(10) << m[2] << " " << std::setw(10) << m[6] << " " << std::setw(10) << m[10] << " " << std::setw(10) << m[14] << "]\n"
|
||||||
|
<< "[" << std::setw(10) << m[3] << " " << std::setw(10) << m[7] << " " << std::setw(10) << m[11] << " " << std::setw(10) << m[15] << "]\n";
|
||||||
|
os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
// END OF MATRIX4 INLINE //////////////////////////////////////////////////////
|
||||||
|
#endif
|
||||||
615
Model.cpp
Normal file
615
Model.cpp
Normal file
@@ -0,0 +1,615 @@
|
|||||||
|
#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]);
|
||||||
|
}
|
||||||
96
Model.h
Normal file
96
Model.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define MAX_CUBES 20
|
||||||
|
#define MAX_ANIMS 40
|
||||||
|
#define MAX_KEYS 256
|
||||||
|
|
||||||
|
struct CubeFace
|
||||||
|
{
|
||||||
|
Vector2 uv[4] {{32, 32}, {32, 0}, {0, 0}, {0, 32}};
|
||||||
|
char rot {0};
|
||||||
|
bool selected {false};
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
void Rotate();
|
||||||
|
void FlipH();
|
||||||
|
void FlipV();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Cube
|
||||||
|
{
|
||||||
|
char name[10] {""};
|
||||||
|
CubeFace faces[6];
|
||||||
|
Vector3 position {0, 0, 0};
|
||||||
|
Vector3 pivot {0, 0, 0};
|
||||||
|
Vector3 size {8, 8, 8};
|
||||||
|
int8_t parent {-1};
|
||||||
|
bool selected {false};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnimKey
|
||||||
|
{
|
||||||
|
enum class Type { Position, Rotation, Scale };
|
||||||
|
|
||||||
|
float t {0.0f};
|
||||||
|
uint8_t cube {0};
|
||||||
|
Type type {Type::Rotation};
|
||||||
|
Vector3 value {0, 0, 0};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Anim
|
||||||
|
{
|
||||||
|
char name[10] {""};
|
||||||
|
uint8_t numKeys {0};
|
||||||
|
AnimKey keys[MAX_KEYS];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Model
|
||||||
|
{
|
||||||
|
uint8_t numCubes {1};
|
||||||
|
Cube cubes[MAX_CUBES];
|
||||||
|
uint8_t numAnims {1};
|
||||||
|
Anim anims[MAX_ANIMS];
|
||||||
|
|
||||||
|
Matrix4 localMatrix[MAX_CUBES];
|
||||||
|
Matrix4 finalMatrix[MAX_CUBES];
|
||||||
|
|
||||||
|
void Save(const char* filename);
|
||||||
|
void Load(const char* filename);
|
||||||
|
void Calculate();
|
||||||
|
void DrawSolid();
|
||||||
|
void DrawWire();
|
||||||
|
void DrawUV();
|
||||||
|
Color Pick(const float x, const float y);
|
||||||
|
Color PickPaint(const float x, const float y);
|
||||||
|
Color PickPixel(const float x, const float y);
|
||||||
|
|
||||||
|
int GetSelectedCube();
|
||||||
|
void SelectCube(const uint8_t index, const bool inclusive);
|
||||||
|
void SelectAllCubes(const bool select = true);
|
||||||
|
void NewCube();
|
||||||
|
void DeleteCube();
|
||||||
|
void DupCube();
|
||||||
|
void GrabCubes(const float x, const float y, const float z);
|
||||||
|
void ScaleCubes(const float x, const float y, const float z);
|
||||||
|
|
||||||
|
ivec2 GetSelectedFace();
|
||||||
|
void SelectFace(const uint8_t index, const uint8_t face, const bool inclusive);
|
||||||
|
void SelectAllFaces(const bool select = true);
|
||||||
|
void ClearFaces();
|
||||||
|
void RotateFaces();
|
||||||
|
void FlipHFaces();
|
||||||
|
void FlipVFaces();
|
||||||
|
void GrabFaces(const float x, const float y);
|
||||||
|
void ScaleFaces(const float x, const float y);
|
||||||
|
|
||||||
|
void DeleteKey(const int anim, const int key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const Vector3 GetCurrentValue(const int& cube, const AnimKey::Type& type);
|
||||||
|
void GetCurrentTransformation(const int& cube, Vector3& position, Vector3& rotation, Vector3& scale);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Model model;
|
||||||
687
Vectors.h
Executable file
687
Vectors.h
Executable file
@@ -0,0 +1,687 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Vectors.h
|
||||||
|
// =========
|
||||||
|
// 2D/3D/4D vectors
|
||||||
|
//
|
||||||
|
// AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
|
||||||
|
// CREATED: 2007-02-14
|
||||||
|
// UPDATED: 2013-01-20
|
||||||
|
//
|
||||||
|
// Copyright (C) 2007-2013 Song Ho Ahn
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef VECTORS_H_DEF
|
||||||
|
#define VECTORS_H_DEF
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
struct Rectangle {
|
||||||
|
float x, y, w, h;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct generic_vec2
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
T x;
|
||||||
|
T y;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
T r;
|
||||||
|
T g;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
T u;
|
||||||
|
T v;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
generic_vec2() : x(0.0f), y(0.0f) {}
|
||||||
|
generic_vec2(const T& x, const T& y) : x(x), y(y) {}
|
||||||
|
|
||||||
|
inline generic_vec2 operator-() const { return {-x,-y}; }
|
||||||
|
inline generic_vec2 operator+(const generic_vec2& o) const { return {x+o.x, y+o.y}; }
|
||||||
|
inline generic_vec2 operator-(const generic_vec2& o) const { return {x-o.x, y-o.y}; }
|
||||||
|
inline generic_vec2 operator*(const generic_vec2& o) const { return {x*o.x, y*o.y}; }
|
||||||
|
inline generic_vec2 operator/(const generic_vec2& o) const { return {x/o.x, y/o.y}; }
|
||||||
|
inline generic_vec2& operator+=(const generic_vec2& o) { x+=o.x; y+=o.y; return *this; }
|
||||||
|
inline generic_vec2& operator-=(const generic_vec2& o) { x-=o.x; y-=o.y; return *this; }
|
||||||
|
inline generic_vec2& operator*=(const generic_vec2& o) { x*=o.x; y*=o.y; return *this; }
|
||||||
|
inline generic_vec2& operator/=(const generic_vec2& o) { x/=o.x; y/=o.y; return *this; }
|
||||||
|
|
||||||
|
inline generic_vec2 operator+(const T& o) const { return {x+o, y+o}; }
|
||||||
|
inline generic_vec2 operator-(const T& o) const { return {x-o, y-o}; }
|
||||||
|
inline generic_vec2 operator*(const T& o) const { return {x*o, y*o}; }
|
||||||
|
inline generic_vec2 operator/(const T& o) const { return {x/o, y/o}; }
|
||||||
|
inline generic_vec2& operator+=(const T& o) { x+=o; y+=o; return *this; }
|
||||||
|
inline generic_vec2& operator-=(const T& o) { x-=o; y-=o; return *this; }
|
||||||
|
inline generic_vec2& operator*=(const T& o) { x*=o; y*=o; return *this; }
|
||||||
|
inline generic_vec2& operator/=(const T& o) { x/=o; y/=o; return *this; }
|
||||||
|
|
||||||
|
inline bool operator==(const generic_vec2& o) const { return (x==o.x) and (y==o.y); }
|
||||||
|
inline bool operator!=(const generic_vec2& o) const { return (x!=o.x) or (y!=o.y); }
|
||||||
|
inline T operator[](int index) const { return (&x)[index]; }
|
||||||
|
inline T& operator[](int index) { return (&x)[index]; }
|
||||||
|
};
|
||||||
|
typedef generic_vec2<bool> bvec2;
|
||||||
|
typedef generic_vec2<int> ivec2;
|
||||||
|
typedef generic_vec2<unsigned> uvec2;
|
||||||
|
typedef generic_vec2<float> vec2;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct generic_vec3
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
struct { T x, y, z; };
|
||||||
|
struct { T r, g, b; };
|
||||||
|
struct { T u, v, s; };
|
||||||
|
};
|
||||||
|
|
||||||
|
generic_vec3(const T& x, const T& y, const T& z) : x(x), y(y), z(z) {}
|
||||||
|
generic_vec3(const generic_vec2<T>& xy, const T& z) : x(xy.x), y(xy.y), z(z) {}
|
||||||
|
generic_vec3(const T& x, const generic_vec2<T>& yz) : x(x), y(yz.x), z(yz.y) {}
|
||||||
|
|
||||||
|
inline generic_vec3 operator-() const { return {-x,-y,-z}; }
|
||||||
|
inline generic_vec3 operator+(const generic_vec3& o) const { return {x+o.x, y+o.y, z+o.z}; }
|
||||||
|
inline generic_vec3 operator-(const generic_vec3& o) const { return {x-o.x, y-o.y, z-o.z}; }
|
||||||
|
inline generic_vec3 operator*(const generic_vec3& o) const { return {x*o.x, y*o.y, z*o.z}; }
|
||||||
|
inline generic_vec3 operator/(const generic_vec3& o) const { return {x/o.x, y/o.y, z/o.z}; }
|
||||||
|
inline generic_vec3& operator+=(const generic_vec3& o) { x+=o.x; y+=o.y; z+=o.z; return *this; }
|
||||||
|
inline generic_vec3& operator-=(const generic_vec3& o) { x-=o.x; y-=o.y; z-=o.z; return *this; }
|
||||||
|
inline generic_vec3& operator*=(const generic_vec3& o) { x*=o.x; y*=o.y; z*=o.z; return *this; }
|
||||||
|
inline generic_vec3& operator/=(const generic_vec3& o) { x/=o.x; y/=o.y; z/=o.z; return *this; }
|
||||||
|
|
||||||
|
inline generic_vec3 operator+(const T& o) const { return {x+o, y+o, z+o}; }
|
||||||
|
inline generic_vec3 operator-(const T& o) const { return {x-o, y-o, z-o}; }
|
||||||
|
inline generic_vec3 operator*(const T& o) const { return {x*o, y*o, z*o}; }
|
||||||
|
inline generic_vec3 operator/(const T& o) const { return {x/o, y/o, z/o}; }
|
||||||
|
inline generic_vec3& operator+=(const T& o) { x+=o; y+=o; z+=o; return *this; }
|
||||||
|
inline generic_vec3& operator-=(const T& o) { x-=o; y-=o; z-=o; return *this; }
|
||||||
|
inline generic_vec3& operator*=(const T& o) { x*=o; y*=o; z*=o; return *this; }
|
||||||
|
inline generic_vec3& operator/=(const T& o) { x/=o; y/=o; z/=o; return *this; }
|
||||||
|
|
||||||
|
inline bool operator==(const generic_vec3& o) const { return (x==o.x) and (y==o.y) and (z==o.z); }
|
||||||
|
inline bool operator!=(const generic_vec3& o) const { return (x!=o.x) or (y!=o.y) or (z!=o.z); }
|
||||||
|
inline T operator[](int index) const { return (&x)[index]; }
|
||||||
|
inline T& operator[](int index) { return (&x)[index]; }
|
||||||
|
};
|
||||||
|
typedef generic_vec3<bool> bvec3;
|
||||||
|
typedef generic_vec3<int> ivec3;
|
||||||
|
typedef generic_vec3<unsigned> uvec3;
|
||||||
|
typedef generic_vec3<float> vec3;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct generic_vec4
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
struct { T x, y, z, w; };
|
||||||
|
struct { T r, g, b, a; };
|
||||||
|
struct { T u, v, s, t; };
|
||||||
|
};
|
||||||
|
|
||||||
|
generic_vec4() : x(0), y(0), z(0), w(0) {}
|
||||||
|
generic_vec4(const T& x,const T& y, const T& z, const T& w) : x(x), y(y), z(z), w(w) {}
|
||||||
|
generic_vec4(const generic_vec2<T>& xy, const T& z, const T& w) : x(xy.x), y(xy.y), z(z), w(w) {}
|
||||||
|
generic_vec4(const T& x, const generic_vec2<T>& yz, const T& w) : x(x), y(yz.x), z(yz.y), w(w) {}
|
||||||
|
generic_vec4(const T& x, const T& y, const generic_vec2<T>& zw) : x(x), y(y), z(zw.x), w(zw.y) {}
|
||||||
|
generic_vec4(const generic_vec2<T>& xy, const generic_vec2<T>& zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y) {}
|
||||||
|
|
||||||
|
generic_vec4(const generic_vec3<T>& xyz, const T& w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
|
||||||
|
generic_vec4(const T& x, const generic_vec3<T>& yzw) : x(x), y(yzw.x), z(yzw.y), w(yzw.z) {}
|
||||||
|
|
||||||
|
|
||||||
|
inline generic_vec4 operator-() const { return {-x,-y,-z, -w}; }
|
||||||
|
inline generic_vec4 operator+(const generic_vec4& o) const { return {x+o.x, y+o.y, z+o.z, w+o.w}; }
|
||||||
|
inline generic_vec4 operator-(const generic_vec4& o) const { return {x-o.x, y-o.y, z-o.z, w-o.w}; }
|
||||||
|
inline generic_vec4 operator*(const generic_vec4& o) const { return {x*o.x, y*o.y, z*o.z, w*o.w}; }
|
||||||
|
inline generic_vec4 operator/(const generic_vec4& o) const { return {x/o.x, y/o.y, z/o.z, w/o.w}; }
|
||||||
|
inline generic_vec4& operator+=(const generic_vec4& o) { x+=o.x; y+=o.y; z+=o.z; w+=o.w; return *this; }
|
||||||
|
inline generic_vec4& operator-=(const generic_vec4& o) { x-=o.x; y-=o.y; z-=o.z; w-=o.w; return *this; }
|
||||||
|
inline generic_vec4& operator*=(const generic_vec4& o) { x*=o.x; y*=o.y; z*=o.z; w*=o.w; return *this; }
|
||||||
|
inline generic_vec4& operator/=(const generic_vec4& o) { x/=o.x; y/=o.y; z/=o.z; w/=o.w; return *this; }
|
||||||
|
|
||||||
|
inline generic_vec4 operator+(const T& o) const { return {x+o, y+o, z+o, w+o}; }
|
||||||
|
inline generic_vec4 operator-(const T& o) const { return {x-o, y-o, z-o, w-o}; }
|
||||||
|
inline generic_vec4 operator*(const T& o) const { return {x*o, y*o, z*o, w*o}; }
|
||||||
|
inline generic_vec4 operator/(const T& o) const { return {x/o, y/o, z/o, w/o}; }
|
||||||
|
inline generic_vec4& operator+=(const T& o) { x+=o; y+=o; z+=o; w+=o; return *this; }
|
||||||
|
inline generic_vec4& operator-=(const T& o) { x-=o; y-=o; z-=o; w-=o; return *this; }
|
||||||
|
inline generic_vec4& operator*=(const T& o) { x*=o; y*=o; z*=o; w*=o; return *this; }
|
||||||
|
inline generic_vec4& operator/=(const T& o) { x/=o; y/=o; z/=o; w/=o; return *this; }
|
||||||
|
|
||||||
|
inline bool operator==(const generic_vec4& o) const { return (x==o.x) and (y==o.y) and (z==o.z) and (w==o.w); }
|
||||||
|
inline bool operator!=(const generic_vec4& o) const { return (x!=o.x) or (y!=o.y) or (z!=o.z) or (w!=o.w); }
|
||||||
|
inline T operator[](int index) const { return (&x)[index]; }
|
||||||
|
inline T& operator[](int index) { return (&x)[index]; }
|
||||||
|
};
|
||||||
|
typedef generic_vec4<bool> bvec4;
|
||||||
|
typedef generic_vec4<int> ivec4;
|
||||||
|
typedef generic_vec4<unsigned> uvec4;
|
||||||
|
typedef generic_vec4<float> vec4;
|
||||||
|
typedef generic_vec4<unsigned char> ubvec4;
|
||||||
|
typedef ubvec4 Color;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 2D vector
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct Vector2
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
|
||||||
|
// ctors
|
||||||
|
Vector2() : x(0), y(0) {};
|
||||||
|
Vector2(float x, float y) : x(x), y(y) {};
|
||||||
|
|
||||||
|
// utils functions
|
||||||
|
void set(float x, float y);
|
||||||
|
float length() const; //
|
||||||
|
float distance(const Vector2& vec) const; // distance between two vectors
|
||||||
|
Vector2& normalize(); //
|
||||||
|
float dot(const Vector2& vec) const; // dot product
|
||||||
|
bool equal(const Vector2& vec, float e) const; // compare with epsilon
|
||||||
|
bool inside(const Vector2& pos, const Vector2& size) const;
|
||||||
|
|
||||||
|
// operators
|
||||||
|
Vector2 operator-() const; // unary operator (negate)
|
||||||
|
Vector2 operator+(const Vector2& rhs) const; // add rhs
|
||||||
|
Vector2 operator-(const Vector2& rhs) const; // subtract rhs
|
||||||
|
Vector2& operator+=(const Vector2& rhs); // add rhs and update this object
|
||||||
|
Vector2& operator-=(const Vector2& rhs); // subtract rhs and update this object
|
||||||
|
Vector2 operator*(const float scale) const; // scale
|
||||||
|
Vector2 operator*(const Vector2& rhs) const; // multiply each element
|
||||||
|
Vector2& operator*=(const float scale); // scale and update this object
|
||||||
|
Vector2& operator*=(const Vector2& rhs); // multiply each element and update this object
|
||||||
|
Vector2 operator/(const float scale) const; // inverse scale
|
||||||
|
Vector2& operator/=(const float scale); // scale and update this object
|
||||||
|
bool operator==(const Vector2& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator!=(const Vector2& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator<(const Vector2& rhs) const; // comparison for sort
|
||||||
|
float operator[](int index) const; // subscript operator v[0], v[1]
|
||||||
|
float& operator[](int index); // subscript operator v[0], v[1]
|
||||||
|
|
||||||
|
friend Vector2 operator*(const float a, const Vector2 vec);
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const Vector2& vec);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 3D vector
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct Vector3
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
|
||||||
|
// ctors
|
||||||
|
Vector3() : x(0), y(0), z(0) {};
|
||||||
|
Vector3(float x, float y, float z) : x(x), y(y), z(z) {};
|
||||||
|
|
||||||
|
// utils functions
|
||||||
|
void set(float x, float y, float z);
|
||||||
|
float length() const; //
|
||||||
|
float distance(const Vector3& vec) const; // distance between two vectors
|
||||||
|
Vector3& normalize(); //
|
||||||
|
float dot(const Vector3& vec) const; // dot product
|
||||||
|
Vector3 cross(const Vector3& vec) const; // cross product
|
||||||
|
bool equal(const Vector3& vec, float e) const; // compare with epsilon
|
||||||
|
|
||||||
|
// operators
|
||||||
|
Vector3 operator-() const; // unary operator (negate)
|
||||||
|
Vector3 operator+(const Vector3& rhs) const; // add rhs
|
||||||
|
Vector3 operator-(const Vector3& rhs) const; // subtract rhs
|
||||||
|
Vector3& operator+=(const Vector3& rhs); // add rhs and update this object
|
||||||
|
Vector3& operator-=(const Vector3& rhs); // subtract rhs and update this object
|
||||||
|
Vector3 operator*(const float scale) const; // scale
|
||||||
|
Vector3 operator*(const Vector3& rhs) const; // multiplay each element
|
||||||
|
Vector3& operator*=(const float scale); // scale and update this object
|
||||||
|
Vector3& operator*=(const Vector3& rhs); // product each element and update this object
|
||||||
|
Vector3 operator/(const float scale) const; // inverse scale
|
||||||
|
Vector3& operator/=(const float scale); // scale and update this object
|
||||||
|
bool operator==(const Vector3& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator!=(const Vector3& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator<(const Vector3& rhs) const; // comparison for sort
|
||||||
|
float operator[](int index) const; // subscript operator v[0], v[1]
|
||||||
|
float& operator[](int index); // subscript operator v[0], v[1]
|
||||||
|
|
||||||
|
friend Vector3 operator*(const float a, const Vector3 vec);
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const Vector3& vec);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 4D vector
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct Vector4
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
float w;
|
||||||
|
|
||||||
|
// ctors
|
||||||
|
Vector4() : x(0), y(0), z(0), w(0) {};
|
||||||
|
Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {};
|
||||||
|
Vector4(Vector3 v, float w = 1) : x(v.x), y(v.y), z(v.z), w(w) {};
|
||||||
|
Vector4(Vector2 a, Vector2 b) : x(a.x), y(a.y), z(b.x), w(b.y) {};
|
||||||
|
|
||||||
|
// utils functions
|
||||||
|
void set(float x, float y, float z, float w);
|
||||||
|
float length() const; //
|
||||||
|
float distance(const Vector4& vec) const; // distance between two vectors
|
||||||
|
Vector4& normalize(); //
|
||||||
|
float dot(const Vector4& vec) const; // dot product
|
||||||
|
bool equal(const Vector4& vec, float e) const; // compare with epsilon
|
||||||
|
|
||||||
|
// operators
|
||||||
|
Vector4 operator-() const; // unary operator (negate)
|
||||||
|
Vector4 operator+(const Vector4& rhs) const; // add rhs
|
||||||
|
Vector4 operator-(const Vector4& rhs) const; // subtract rhs
|
||||||
|
Vector4& operator+=(const Vector4& rhs); // add rhs and update this object
|
||||||
|
Vector4& operator-=(const Vector4& rhs); // subtract rhs and update this object
|
||||||
|
Vector4 operator*(const float scale) const; // scale
|
||||||
|
Vector4 operator*(const Vector4& rhs) const; // multiply each element
|
||||||
|
Vector4& operator*=(const float scale); // scale and update this object
|
||||||
|
Vector4& operator*=(const Vector4& rhs); // multiply each element and update this object
|
||||||
|
Vector4 operator/(const float scale) const; // inverse scale
|
||||||
|
Vector4& operator/=(const float scale); // scale and update this object
|
||||||
|
bool operator==(const Vector4& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator!=(const Vector4& rhs) const; // exact compare, no epsilon
|
||||||
|
bool operator<(const Vector4& rhs) const; // comparison for sort
|
||||||
|
float operator[](int index) const; // subscript operator v[0], v[1]
|
||||||
|
float& operator[](int index); // subscript operator v[0], v[1]
|
||||||
|
|
||||||
|
Vector2 GetPosition() { return Vector2(x, y); }
|
||||||
|
Vector2 GetSize() { return Vector2(z, w); }
|
||||||
|
|
||||||
|
friend Vector4 operator*(const float a, const Vector4 vec);
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const Vector4& vec);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fast math routines from Doom3 SDK
|
||||||
|
inline float invSqrt(float x)
|
||||||
|
{
|
||||||
|
float xhalf = 0.5f * x;
|
||||||
|
int i = *(int*)&x; // get bits for floating value
|
||||||
|
i = 0x5f3759df - (i>>1); // gives initial guess
|
||||||
|
x = *(float*)&i; // convert bits back to float
|
||||||
|
x = x * (1.5f - xhalf*x*x); // Newton step
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// inline functions for Vector2
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
inline Vector2 Vector2::operator-() const {
|
||||||
|
return Vector2(-x, -y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2 Vector2::operator+(const Vector2& rhs) const {
|
||||||
|
return Vector2(x+rhs.x, y+rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2 Vector2::operator-(const Vector2& rhs) const {
|
||||||
|
return Vector2(x-rhs.x, y-rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2& Vector2::operator+=(const Vector2& rhs) {
|
||||||
|
x += rhs.x; y += rhs.y; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2& Vector2::operator-=(const Vector2& rhs) {
|
||||||
|
x -= rhs.x; y -= rhs.y; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2 Vector2::operator*(const float a) const {
|
||||||
|
return Vector2(x*a, y*a);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2 Vector2::operator*(const Vector2& rhs) const {
|
||||||
|
return Vector2(x*rhs.x, y*rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2& Vector2::operator*=(const float a) {
|
||||||
|
x *= a; y *= a; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2& Vector2::operator*=(const Vector2& rhs) {
|
||||||
|
x *= rhs.x; y *= rhs.y; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2 Vector2::operator/(const float a) const {
|
||||||
|
return Vector2(x/a, y/a);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2& Vector2::operator/=(const float a) {
|
||||||
|
x /= a; y /= a; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector2::operator==(const Vector2& rhs) const {
|
||||||
|
return (x == rhs.x) && (y == rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector2::operator!=(const Vector2& rhs) const {
|
||||||
|
return (x != rhs.x) || (y != rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector2::operator<(const Vector2& rhs) const {
|
||||||
|
if(x < rhs.x) return true;
|
||||||
|
if(x > rhs.x) return false;
|
||||||
|
if(y < rhs.y) return true;
|
||||||
|
if(y > rhs.y) return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector2::operator[](int index) const {
|
||||||
|
return (&x)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float& Vector2::operator[](int index) {
|
||||||
|
return (&x)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Vector2::set(float x, float y) {
|
||||||
|
this->x = x; this->y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector2::length() const {
|
||||||
|
return sqrtf(x*x + y*y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector2::distance(const Vector2& vec) const {
|
||||||
|
return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2& Vector2::normalize() {
|
||||||
|
//@@const float EPSILON = 0.000001f;
|
||||||
|
float xxyy = x*x + y*y;
|
||||||
|
//@@if(xxyy < EPSILON)
|
||||||
|
//@@ return *this;
|
||||||
|
|
||||||
|
//float invLength = invSqrt(xxyy);
|
||||||
|
float invLength = 1.0f / sqrtf(xxyy);
|
||||||
|
x *= invLength;
|
||||||
|
y *= invLength;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector2::dot(const Vector2& rhs) const {
|
||||||
|
return (x*rhs.x + y*rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector2::equal(const Vector2& rhs, float epsilon) const {
|
||||||
|
return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector2::inside(const Vector2& pos, const Vector2& size) const {
|
||||||
|
return (x >= pos.x and y >= pos.y and x <= (pos.x+size.x) and y <= (pos.y+size.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector2 operator*(const float a, const Vector2 vec) {
|
||||||
|
return Vector2(a*vec.x, a*vec.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const Vector2& vec) {
|
||||||
|
os << "(" << vec.x << ", " << vec.y << ")";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
// END OF VECTOR2 /////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// inline functions for Vector3
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
inline Vector3 Vector3::operator-() const {
|
||||||
|
return Vector3(-x, -y, -z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 Vector3::operator+(const Vector3& rhs) const {
|
||||||
|
return Vector3(x+rhs.x, y+rhs.y, z+rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 Vector3::operator-(const Vector3& rhs) const {
|
||||||
|
return Vector3(x-rhs.x, y-rhs.y, z-rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3& Vector3::operator+=(const Vector3& rhs) {
|
||||||
|
x += rhs.x; y += rhs.y; z += rhs.z; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3& Vector3::operator-=(const Vector3& rhs) {
|
||||||
|
x -= rhs.x; y -= rhs.y; z -= rhs.z; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 Vector3::operator*(const float a) const {
|
||||||
|
return Vector3(x*a, y*a, z*a);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 Vector3::operator*(const Vector3& rhs) const {
|
||||||
|
return Vector3(x*rhs.x, y*rhs.y, z*rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3& Vector3::operator*=(const float a) {
|
||||||
|
x *= a; y *= a; z *= a; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3& Vector3::operator*=(const Vector3& rhs) {
|
||||||
|
x *= rhs.x; y *= rhs.y; z *= rhs.z; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 Vector3::operator/(const float a) const {
|
||||||
|
return Vector3(x/a, y/a, z/a);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3& Vector3::operator/=(const float a) {
|
||||||
|
x /= a; y /= a; z /= a; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector3::operator==(const Vector3& rhs) const {
|
||||||
|
return (x == rhs.x) && (y == rhs.y) && (z == rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector3::operator!=(const Vector3& rhs) const {
|
||||||
|
return (x != rhs.x) || (y != rhs.y) || (z != rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector3::operator<(const Vector3& rhs) const {
|
||||||
|
if(x < rhs.x) return true;
|
||||||
|
if(x > rhs.x) return false;
|
||||||
|
if(y < rhs.y) return true;
|
||||||
|
if(y > rhs.y) return false;
|
||||||
|
if(z < rhs.z) return true;
|
||||||
|
if(z > rhs.z) return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector3::operator[](int index) const {
|
||||||
|
return (&x)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float& Vector3::operator[](int index) {
|
||||||
|
return (&x)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Vector3::set(float x, float y, float z) {
|
||||||
|
this->x = x; this->y = y; this->z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector3::length() const {
|
||||||
|
return sqrtf(x*x + y*y + z*z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector3::distance(const Vector3& vec) const {
|
||||||
|
return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y) + (vec.z-z)*(vec.z-z));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3& Vector3::normalize() {
|
||||||
|
//@@const float EPSILON = 0.000001f;
|
||||||
|
float xxyyzz = x*x + y*y + z*z;
|
||||||
|
//@@if(xxyyzz < EPSILON)
|
||||||
|
//@@ return *this; // do nothing if it is ~zero vector
|
||||||
|
|
||||||
|
//float invLength = invSqrt(xxyyzz);
|
||||||
|
float invLength = 1.0f / sqrtf(xxyyzz);
|
||||||
|
x *= invLength;
|
||||||
|
y *= invLength;
|
||||||
|
z *= invLength;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector3::dot(const Vector3& rhs) const {
|
||||||
|
return (x*rhs.x + y*rhs.y + z*rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 Vector3::cross(const Vector3& rhs) const {
|
||||||
|
return Vector3(y*rhs.z - z*rhs.y, z*rhs.x - x*rhs.z, x*rhs.y - y*rhs.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector3::equal(const Vector3& rhs, float epsilon) const {
|
||||||
|
return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon && fabs(z - rhs.z) < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 operator*(const float a, const Vector3 vec) {
|
||||||
|
return Vector3(a*vec.x, a*vec.y, a*vec.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const Vector3& vec) {
|
||||||
|
os << "(" << vec.x << ", " << vec.y << ", " << vec.z << ")";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
// END OF VECTOR3 /////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// inline functions for Vector4
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
inline Vector4 Vector4::operator-() const {
|
||||||
|
return Vector4(-x, -y, -z, -w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4 Vector4::operator+(const Vector4& rhs) const {
|
||||||
|
return Vector4(x+rhs.x, y+rhs.y, z+rhs.z, w+rhs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4 Vector4::operator-(const Vector4& rhs) const {
|
||||||
|
return Vector4(x-rhs.x, y-rhs.y, z-rhs.z, w-rhs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4& Vector4::operator+=(const Vector4& rhs) {
|
||||||
|
x += rhs.x; y += rhs.y; z += rhs.z; w += rhs.w; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4& Vector4::operator-=(const Vector4& rhs) {
|
||||||
|
x -= rhs.x; y -= rhs.y; z -= rhs.z; w -= rhs.w; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4 Vector4::operator*(const float a) const {
|
||||||
|
return Vector4(x*a, y*a, z*a, w*a);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4 Vector4::operator*(const Vector4& rhs) const {
|
||||||
|
return Vector4(x*rhs.x, y*rhs.y, z*rhs.z, w*rhs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4& Vector4::operator*=(const float a) {
|
||||||
|
x *= a; y *= a; z *= a; w *= a; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4& Vector4::operator*=(const Vector4& rhs) {
|
||||||
|
x *= rhs.x; y *= rhs.y; z *= rhs.z; w *= rhs.w; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4 Vector4::operator/(const float a) const {
|
||||||
|
return Vector4(x/a, y/a, z/a, w/a);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4& Vector4::operator/=(const float a) {
|
||||||
|
x /= a; y /= a; z /= a; w /= a; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector4::operator==(const Vector4& rhs) const {
|
||||||
|
return (x == rhs.x) && (y == rhs.y) && (z == rhs.z) && (w == rhs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector4::operator!=(const Vector4& rhs) const {
|
||||||
|
return (x != rhs.x) || (y != rhs.y) || (z != rhs.z) || (w != rhs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector4::operator<(const Vector4& rhs) const {
|
||||||
|
if(x < rhs.x) return true;
|
||||||
|
if(x > rhs.x) return false;
|
||||||
|
if(y < rhs.y) return true;
|
||||||
|
if(y > rhs.y) return false;
|
||||||
|
if(z < rhs.z) return true;
|
||||||
|
if(z > rhs.z) return false;
|
||||||
|
if(w < rhs.w) return true;
|
||||||
|
if(w > rhs.w) return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector4::operator[](int index) const {
|
||||||
|
return (&x)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float& Vector4::operator[](int index) {
|
||||||
|
return (&x)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Vector4::set(float x, float y, float z, float w) {
|
||||||
|
this->x = x; this->y = y; this->z = z; this->w = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector4::length() const {
|
||||||
|
return sqrtf(x*x + y*y + z*z + w*w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector4::distance(const Vector4& vec) const {
|
||||||
|
return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y) + (vec.z-z)*(vec.z-z) + (vec.w-w)*(vec.w-w));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4& Vector4::normalize() {
|
||||||
|
//NOTE: leave w-component untouched
|
||||||
|
//@@const float EPSILON = 0.000001f;
|
||||||
|
float xxyyzz = x*x + y*y + z*z;
|
||||||
|
//@@if(xxyyzz < EPSILON)
|
||||||
|
//@@ return *this; // do nothing if it is zero vector
|
||||||
|
|
||||||
|
//float invLength = invSqrt(xxyyzz);
|
||||||
|
float invLength = 1.0f / sqrtf(xxyyzz);
|
||||||
|
x *= invLength;
|
||||||
|
y *= invLength;
|
||||||
|
z *= invLength;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Vector4::dot(const Vector4& rhs) const {
|
||||||
|
return (x*rhs.x + y*rhs.y + z*rhs.z + w*rhs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Vector4::equal(const Vector4& rhs, float epsilon) const {
|
||||||
|
return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon &&
|
||||||
|
fabs(z - rhs.z) < epsilon && fabs(w - rhs.w) < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4 operator*(const float a, const Vector4 vec) {
|
||||||
|
return Vector4(a*vec.x, a*vec.y, a*vec.z, a*vec.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const Vector4& vec) {
|
||||||
|
os << "(" << vec.x << ", " << vec.y << ", " << vec.z << ", " << vec.w << ")";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
// END OF VECTOR4 /////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#endif
|
||||||
41
application.cpp
Normal file
41
application.cpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
//#include "model.h"
|
||||||
|
//#include "console.h"
|
||||||
|
|
||||||
|
namespace Application
|
||||||
|
{
|
||||||
|
bool quit {false};
|
||||||
|
char dirty {1};
|
||||||
|
|
||||||
|
const bool& ShouldQuit()
|
||||||
|
{
|
||||||
|
return quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quit()
|
||||||
|
{
|
||||||
|
//if (Model::IsModified()) {
|
||||||
|
// Console::Ask("SAVE BEFORE QUITTING (YES/NO/CANCEL)?", Application::QuitHandler);
|
||||||
|
//} else {
|
||||||
|
quit = true;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuitHandler(const char* reply)
|
||||||
|
{
|
||||||
|
//if (reply[0] == 'Y') {
|
||||||
|
// Model::Save();
|
||||||
|
//} else if (reply[0] == 'N') {
|
||||||
|
// quit = true;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NeedsUpdate(const char cycles)
|
||||||
|
{
|
||||||
|
if (cycles > 0 and cycles > dirty) dirty = cycles;
|
||||||
|
return dirty > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Updated() { if (dirty > 0) dirty--; }
|
||||||
|
}
|
||||||
10
application.h
Normal file
10
application.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Application
|
||||||
|
{
|
||||||
|
void Quit();
|
||||||
|
const bool& ShouldQuit();
|
||||||
|
void QuitHandler(const char* reply);
|
||||||
|
bool NeedsUpdate(const char cycles = 2);
|
||||||
|
void Updated();
|
||||||
|
}
|
||||||
14
common.h
Normal file
14
common.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "Vectors.h"
|
||||||
|
#include "Matrices.h"
|
||||||
|
#include "geometry.h"
|
||||||
|
|
||||||
|
#define QUERY 0
|
||||||
|
#define ON 1
|
||||||
|
#define OFF 2
|
||||||
|
#define YES ON
|
||||||
|
#define NO OFF
|
||||||
|
|
||||||
|
#define Swap(x, y) { x -= y = (x += y) - y; }
|
||||||
108
font.cpp
Normal file
108
font.cpp
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#include "font.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
#include "texture.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
static float colors[16][4] = {
|
||||||
|
{0, 0, 0, 1},
|
||||||
|
{0.5f, 0, 0, 1},
|
||||||
|
{0, 0.5f, 0, 1},
|
||||||
|
{0.5f, 0.5f, 0, 1},
|
||||||
|
{0, 0, 0.5f, 1},
|
||||||
|
{0.5f, 0, 0.5f, 1},
|
||||||
|
{0, 0.5f, 0.5f, 1},
|
||||||
|
{0.75f, 0.75f, 0.75f, 1},
|
||||||
|
{0.5f, 0.5f, 0.5f, 1},
|
||||||
|
{1, 0, 0, 1},
|
||||||
|
{0, 1, 0, 1},
|
||||||
|
{1, 1, 0, 1},
|
||||||
|
{0, 0, 1, 1},
|
||||||
|
{1, 0, 1, 1},
|
||||||
|
{0, 1, 1, 1},
|
||||||
|
{1, 1, 1, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
void Font::Load(const char* filename)
|
||||||
|
{
|
||||||
|
char name[16]; strcpy(name, filename); strcat(name, ".fnt");
|
||||||
|
|
||||||
|
FILE* fin = fopen(name, "ra");
|
||||||
|
if (fin == NULL) return;
|
||||||
|
|
||||||
|
char line[256];
|
||||||
|
|
||||||
|
fgets(line, 255, fin);
|
||||||
|
fgets(line, 255, fin);
|
||||||
|
int lh, sw, sh;
|
||||||
|
assert(sscanf(line, "common lineHeight=%i base=%*i scaleW=%i scaleH=%i", &lh, &sw, &sh) == 3);
|
||||||
|
lineHeight = lh;
|
||||||
|
bw = sw;
|
||||||
|
bh = sh;
|
||||||
|
|
||||||
|
fgets(line, 255, fin);
|
||||||
|
fgets(line, 255, fin);
|
||||||
|
int numChars;
|
||||||
|
assert(sscanf(line, "chars count=%i", &numChars) == 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < numChars; i++) {
|
||||||
|
fgets(line, 255, fin);
|
||||||
|
int id, x, y, w, h, xo, yo, xa;
|
||||||
|
assert(sscanf(line, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", &id, &x, &y, &w, &h, &xo, &yo, &xa) == 8);
|
||||||
|
FontChar& c = chars[id-32];
|
||||||
|
c.w = w;
|
||||||
|
c.h = h;
|
||||||
|
c.x1 = float(x)/float(bw);
|
||||||
|
c.y1 = float(y)/float(bh);
|
||||||
|
c.x2 = c.x1 + float(w)/float(bw);
|
||||||
|
c.y2 = c.y1 + float(h)/float(bh);;
|
||||||
|
c.xo = xo;
|
||||||
|
c.yo = yo;
|
||||||
|
c.xa = xa;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture = Texture::Create();
|
||||||
|
Texture::Load(texture, filename);
|
||||||
|
fclose(fin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Font::Print(int x, int y, const char* text, char color)
|
||||||
|
{
|
||||||
|
const unsigned long len = strlen(text);
|
||||||
|
|
||||||
|
Renderer::SetState(RENDER_FILL | RENDER_BLEND | RENDER_TEXTURE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glColor4fv(colors[color]);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
FontChar& c = chars[text[i]-32];
|
||||||
|
glTexCoord2f(c.x1, c.y1);
|
||||||
|
glVertex2i(x+c.xo, y+c.yo);
|
||||||
|
glTexCoord2f(c.x1, c.y2);
|
||||||
|
glVertex2i(x+c.xo, y+c.yo+c.h);
|
||||||
|
glTexCoord2f(c.x2, c.y2);
|
||||||
|
glVertex2i(x+c.xo+c.w, y+c.yo+c.h);
|
||||||
|
glTexCoord2f(c.x2, c.y1);
|
||||||
|
glVertex2i(x+c.xo+c.w, y+c.yo);
|
||||||
|
x += c.xa;
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 Font::GetSize(const char* text)
|
||||||
|
{
|
||||||
|
Vector2 size;
|
||||||
|
size.y = lineHeight;
|
||||||
|
const unsigned long len = strlen(text);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
//if (i == len-1) {
|
||||||
|
// size.x += chars[text[i]-32].w;
|
||||||
|
//} else {
|
||||||
|
size.x += chars[text[i]-32].xa;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
99
font.fnt
Normal file
99
font.fnt
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
info face="Segoe UI" size=14 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=0,0
|
||||||
|
common lineHeight=19 base=15 scaleW=128 scaleH=128 pages=1 packed=0
|
||||||
|
page id=0 file="font.png"
|
||||||
|
chars count=95
|
||||||
|
char id=32 x=40 y=76 width=0 height=0 xoffset=0 yoffset=15 xadvance=4 page=0 chnl=0 letter="space"
|
||||||
|
char id=33 x=58 y=54 width=4 height=12 xoffset=1 yoffset=3 xadvance=4 page=0 chnl=0 letter="!"
|
||||||
|
char id=34 x=121 y=66 width=6 height=6 xoffset=1 yoffset=2 xadvance=5 page=0 chnl=0 letter="""
|
||||||
|
char id=35 x=62 y=54 width=10 height=11 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 letter="#"
|
||||||
|
char id=36 x=22 y=0 width=8 height=15 xoffset=1 yoffset=1 xadvance=8 page=0 chnl=0 letter="$"
|
||||||
|
char id=37 x=94 y=0 width=13 height=13 xoffset=1 yoffset=2 xadvance=11 page=0 chnl=0 letter="%"
|
||||||
|
char id=38 x=107 y=0 width=13 height=13 xoffset=1 yoffset=2 xadvance=11 page=0 chnl=0 letter="&"
|
||||||
|
char id=39 x=4 y=76 width=4 height=6 xoffset=1 yoffset=2 xadvance=3 page=0 chnl=0 letter="'"
|
||||||
|
char id=40 x=30 y=0 width=6 height=15 xoffset=1 yoffset=2 xadvance=4 page=0 chnl=0 letter="("
|
||||||
|
char id=41 x=36 y=0 width=6 height=15 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 letter=")"
|
||||||
|
char id=42 x=105 y=66 width=7 height=7 xoffset=1 yoffset=3 xadvance=6 page=0 chnl=0 letter="*"
|
||||||
|
char id=43 x=63 y=66 width=9 height=9 xoffset=2 yoffset=5 xadvance=10 page=0 chnl=0 letter="+"
|
||||||
|
char id=44 x=0 y=76 width=4 height=6 xoffset=0 yoffset=11 xadvance=3 page=0 chnl=0 letter=","
|
||||||
|
char id=45 x=34 y=76 width=6 height=3 xoffset=1 yoffset=9 xadvance=6 page=0 chnl=0 letter="-"
|
||||||
|
char id=46 x=22 y=76 width=4 height=4 xoffset=1 yoffset=11 xadvance=3 page=0 chnl=0 letter="."
|
||||||
|
char id=47 x=78 y=0 width=8 height=14 xoffset=-0 yoffset=3 xadvance=5 page=0 chnl=0 letter="/"
|
||||||
|
char id=48 x=59 y=16 width=9 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="0"
|
||||||
|
char id=49 x=32 y=29 width=8 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="1"
|
||||||
|
char id=50 x=115 y=42 width=8 height=12 xoffset=1 yoffset=3 xadvance=8 page=0 chnl=0 letter="2"
|
||||||
|
char id=51 x=8 y=29 width=8 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="3"
|
||||||
|
char id=52 x=88 y=42 width=9 height=12 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 letter="4"
|
||||||
|
char id=53 x=8 y=54 width=8 height=12 xoffset=1 yoffset=3 xadvance=8 page=0 chnl=0 letter="5"
|
||||||
|
char id=54 x=68 y=16 width=9 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="6"
|
||||||
|
char id=55 x=106 y=42 width=9 height=12 xoffset=1 yoffset=3 xadvance=8 page=0 chnl=0 letter="7"
|
||||||
|
char id=56 x=77 y=16 width=9 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="8"
|
||||||
|
char id=57 x=86 y=16 width=9 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="9"
|
||||||
|
char id=58 x=29 y=66 width=4 height=10 xoffset=1 yoffset=5 xadvance=3 page=0 chnl=0 letter=":"
|
||||||
|
char id=59 x=72 y=54 width=5 height=11 xoffset=0 yoffset=6 xadvance=3 page=0 chnl=0 letter=";"
|
||||||
|
char id=60 x=72 y=66 width=8 height=9 xoffset=2 yoffset=5 xadvance=10 page=0 chnl=0 letter="<"
|
||||||
|
char id=61 x=112 y=66 width=9 height=6 xoffset=2 yoffset=7 xadvance=10 page=0 chnl=0 letter="="
|
||||||
|
char id=62 x=80 y=66 width=8 height=9 xoffset=2 yoffset=5 xadvance=10 page=0 chnl=0 letter=">"
|
||||||
|
char id=63 x=40 y=29 width=7 height=13 xoffset=1 yoffset=2 xadvance=6 page=0 chnl=0 letter="?"
|
||||||
|
char id=64 x=64 y=0 width=14 height=14 xoffset=1 yoffset=2 xadvance=13 page=0 chnl=0 letter="@"
|
||||||
|
char id=65 x=89 y=29 width=11 height=12 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 letter="A"
|
||||||
|
char id=66 x=97 y=42 width=9 height=12 xoffset=1 yoffset=3 xadvance=8 page=0 chnl=0 letter="B"
|
||||||
|
char id=67 x=22 y=16 width=10 height=13 xoffset=1 yoffset=2 xadvance=9 page=0 chnl=0 letter="C"
|
||||||
|
char id=68 x=111 y=29 width=10 height=12 xoffset=1 yoffset=3 xadvance=10 page=0 chnl=0 letter="D"
|
||||||
|
char id=69 x=16 y=54 width=8 height=12 xoffset=1 yoffset=3 xadvance=7 page=0 chnl=0 letter="E"
|
||||||
|
char id=70 x=32 y=54 width=7 height=12 xoffset=1 yoffset=3 xadvance=7 page=0 chnl=0 letter="F"
|
||||||
|
char id=71 x=12 y=16 width=10 height=13 xoffset=1 yoffset=2 xadvance=10 page=0 chnl=0 letter="G"
|
||||||
|
char id=72 x=40 y=42 width=10 height=12 xoffset=1 yoffset=3 xadvance=10 page=0 chnl=0 letter="H"
|
||||||
|
char id=73 x=52 y=54 width=6 height=12 xoffset=0 yoffset=3 xadvance=4 page=0 chnl=0 letter="I"
|
||||||
|
char id=74 x=46 y=54 width=6 height=12 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=0 letter="J"
|
||||||
|
char id=75 x=79 y=42 width=9 height=12 xoffset=1 yoffset=3 xadvance=8 page=0 chnl=0 letter="K"
|
||||||
|
char id=76 x=24 y=54 width=8 height=12 xoffset=1 yoffset=3 xadvance=7 page=0 chnl=0 letter="L"
|
||||||
|
char id=77 x=77 y=29 width=12 height=12 xoffset=1 yoffset=3 xadvance=13 page=0 chnl=0 letter="M"
|
||||||
|
char id=78 x=0 y=42 width=10 height=12 xoffset=1 yoffset=3 xadvance=10 page=0 chnl=0 letter="N"
|
||||||
|
char id=79 x=0 y=16 width=12 height=13 xoffset=1 yoffset=2 xadvance=11 page=0 chnl=0 letter="O"
|
||||||
|
char id=80 x=0 y=54 width=8 height=12 xoffset=1 yoffset=3 xadvance=8 page=0 chnl=0 letter="P"
|
||||||
|
char id=81 x=10 y=0 width=12 height=15 xoffset=1 yoffset=3 xadvance=11 page=0 chnl=0 letter="Q"
|
||||||
|
char id=82 x=50 y=42 width=10 height=12 xoffset=1 yoffset=3 xadvance=8 page=0 chnl=0 letter="R"
|
||||||
|
char id=83 x=0 y=29 width=8 height=13 xoffset=1 yoffset=2 xadvance=7 page=0 chnl=0 letter="S"
|
||||||
|
char id=84 x=70 y=42 width=9 height=12 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 letter="T"
|
||||||
|
char id=85 x=20 y=42 width=10 height=12 xoffset=1 yoffset=3 xadvance=10 page=0 chnl=0 letter="U"
|
||||||
|
char id=86 x=100 y=29 width=11 height=12 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 letter="V"
|
||||||
|
char id=87 x=62 y=29 width=15 height=12 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=0 letter="W"
|
||||||
|
char id=88 x=10 y=42 width=10 height=12 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 letter="X"
|
||||||
|
char id=89 x=30 y=42 width=10 height=12 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 letter="Y"
|
||||||
|
char id=90 x=60 y=42 width=10 height=12 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 letter="Z"
|
||||||
|
char id=91 x=54 y=0 width=5 height=15 xoffset=1 yoffset=2 xadvance=4 page=0 chnl=0 letter="["
|
||||||
|
char id=92 x=86 y=0 width=8 height=14 xoffset=-0 yoffset=3 xadvance=5 page=0 chnl=0 letter="\"
|
||||||
|
char id=93 x=59 y=0 width=5 height=15 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 letter="]"
|
||||||
|
char id=94 x=96 y=66 width=9 height=8 xoffset=2 yoffset=3 xadvance=10 page=0 chnl=0 letter="^"
|
||||||
|
char id=95 x=26 y=76 width=8 height=3 xoffset=0 yoffset=14 xadvance=6 page=0 chnl=0 letter="_"
|
||||||
|
char id=96 x=17 y=76 width=5 height=5 xoffset=1 yoffset=2 xadvance=4 page=0 chnl=0 letter="`"
|
||||||
|
char id=97 x=107 y=54 width=8 height=10 xoffset=1 yoffset=5 xadvance=7 page=0 chnl=0 letter="a"
|
||||||
|
char id=98 x=41 y=16 width=9 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="b"
|
||||||
|
char id=99 x=8 y=66 width=8 height=10 xoffset=1 yoffset=5 xadvance=6 page=0 chnl=0 letter="c"
|
||||||
|
char id=100 x=50 y=16 width=9 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="d"
|
||||||
|
char id=101 x=98 y=54 width=9 height=10 xoffset=1 yoffset=5 xadvance=7 page=0 chnl=0 letter="e"
|
||||||
|
char id=102 x=47 y=29 width=7 height=13 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 letter="f"
|
||||||
|
char id=103 x=95 y=16 width=9 height=13 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="g"
|
||||||
|
char id=104 x=24 y=29 width=8 height=13 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0 letter="h"
|
||||||
|
char id=105 x=54 y=29 width=4 height=13 xoffset=1 yoffset=2 xadvance=3 page=0 chnl=0 letter="i"
|
||||||
|
char id=106 x=0 y=0 width=6 height=16 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 letter="j"
|
||||||
|
char id=107 x=16 y=29 width=8 height=13 xoffset=1 yoffset=2 xadvance=7 page=0 chnl=0 letter="k"
|
||||||
|
char id=108 x=58 y=29 width=4 height=13 xoffset=1 yoffset=2 xadvance=3 page=0 chnl=0 letter="l"
|
||||||
|
char id=109 x=77 y=54 width=12 height=10 xoffset=1 yoffset=5 xadvance=12 page=0 chnl=0 letter="m"
|
||||||
|
char id=110 x=115 y=54 width=8 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="n"
|
||||||
|
char id=111 x=89 y=54 width=9 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="o"
|
||||||
|
char id=112 x=104 y=16 width=9 height=13 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="p"
|
||||||
|
char id=113 x=113 y=16 width=9 height=13 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="q"
|
||||||
|
char id=114 x=23 y=66 width=6 height=10 xoffset=1 yoffset=5 xadvance=5 page=0 chnl=0 letter="r"
|
||||||
|
char id=115 x=16 y=66 width=7 height=10 xoffset=1 yoffset=5 xadvance=6 page=0 chnl=0 letter="s"
|
||||||
|
char id=116 x=39 y=54 width=7 height=12 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=0 letter="t"
|
||||||
|
char id=117 x=0 y=66 width=8 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="u"
|
||||||
|
char id=118 x=45 y=66 width=9 height=9 xoffset=0 yoffset=6 xadvance=7 page=0 chnl=0 letter="v"
|
||||||
|
char id=119 x=33 y=66 width=12 height=9 xoffset=0 yoffset=6 xadvance=10 page=0 chnl=0 letter="w"
|
||||||
|
char id=120 x=54 y=66 width=9 height=9 xoffset=0 yoffset=6 xadvance=6 page=0 chnl=0 letter="x"
|
||||||
|
char id=121 x=32 y=16 width=9 height=13 xoffset=0 yoffset=5 xadvance=7 page=0 chnl=0 letter="y"
|
||||||
|
char id=122 x=88 y=66 width=8 height=9 xoffset=0 yoffset=6 xadvance=6 page=0 chnl=0 letter="z"
|
||||||
|
char id=123 x=42 y=0 width=6 height=15 xoffset=1 yoffset=2 xadvance=4 page=0 chnl=0 letter="{"
|
||||||
|
char id=124 x=6 y=0 width=4 height=16 xoffset=1 yoffset=2 xadvance=3 page=0 chnl=0 letter="|"
|
||||||
|
char id=125 x=48 y=0 width=6 height=15 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 letter="}"
|
||||||
|
char id=126 x=8 y=76 width=9 height=5 xoffset=1 yoffset=7 xadvance=10 page=0 chnl=0 letter="~"
|
||||||
21
font.h
Normal file
21
font.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct FontChar
|
||||||
|
{
|
||||||
|
float x1, y1, x2, y2;
|
||||||
|
char w, h, xo, yo, xa;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Font
|
||||||
|
{
|
||||||
|
char lineHeight;
|
||||||
|
unsigned char bw, bh;
|
||||||
|
FontChar chars[96];
|
||||||
|
unsigned texture;
|
||||||
|
|
||||||
|
void Load(const char* filename);
|
||||||
|
void Print(int x, int y, const char* text, char color = 15);
|
||||||
|
Vector2 GetSize(const char* text);
|
||||||
|
};
|
||||||
26
geometry.cpp
Normal file
26
geometry.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include "geometry.h"
|
||||||
|
|
||||||
|
Vector3 calculate_normal(const Vector3& v1, const Vector3& v2, const Vector3& v3)
|
||||||
|
{
|
||||||
|
Vector3 normal;
|
||||||
|
const Vector3 U = v2 - v1;
|
||||||
|
const Vector3 V = v3 - v1;
|
||||||
|
|
||||||
|
normal.x = U.y * V.z - U.z * V.y;
|
||||||
|
normal.y = U.z * V.x - U.x * V.z;
|
||||||
|
normal.z = U.x * V.y - U.y * V.x;
|
||||||
|
|
||||||
|
return normal.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const float random(const float& rangeMin, const float& rangeMax)
|
||||||
|
{
|
||||||
|
const float range = rangeMax - rangeMin;
|
||||||
|
return rangeMin + (float(rand())/float(RAND_MAX))*range;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float random_int(const int& rangeMin, const int& rangeMax)
|
||||||
|
{
|
||||||
|
const int range = rangeMax - rangeMin;
|
||||||
|
return rangeMin + (rand() % range);
|
||||||
|
}
|
||||||
85
geometry.h
Normal file
85
geometry.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Vectors.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#define MAX(x, y) x > y ? x : y
|
||||||
|
#define MIN(x, y) x < y ? x : y
|
||||||
|
|
||||||
|
#define List std::list
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Array
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Array() : m_allocated(1000), m_dynamic(true)
|
||||||
|
{
|
||||||
|
m_values = (T*)malloc(sizeof(T)*m_allocated);
|
||||||
|
}
|
||||||
|
Array(int size, bool dynamic) : m_allocated(size), m_dynamic(dynamic)
|
||||||
|
{
|
||||||
|
m_values = (T*)malloc(sizeof(T)*m_allocated);
|
||||||
|
}
|
||||||
|
Array(const Array<T>& other) : m_allocated(other.m_filled), m_dynamic(other.m_dynamic)
|
||||||
|
{
|
||||||
|
m_filled = other.m_filled;
|
||||||
|
m_allocated = other.m_filled;
|
||||||
|
m_values = (T*)malloc(sizeof(T)*m_allocated);
|
||||||
|
memcpy((T*)m_values, (T*)other.m_values, sizeof(T)*m_filled);
|
||||||
|
}
|
||||||
|
~Array() { free(m_values); }
|
||||||
|
void Prealloc(int size)
|
||||||
|
{
|
||||||
|
m_allocated = size;
|
||||||
|
m_values = (T*)realloc(m_values, sizeof(T)*m_allocated);
|
||||||
|
}
|
||||||
|
const int push_back(const T& value)
|
||||||
|
{
|
||||||
|
if (m_filled >= m_allocated) {
|
||||||
|
if (not m_dynamic) {assert(false); }
|
||||||
|
if (m_allocated == 0) m_allocated = 1; else m_allocated*=2;
|
||||||
|
m_values = (T*)realloc(m_values, sizeof(T)*m_allocated);
|
||||||
|
}
|
||||||
|
m_values[m_filled++] = value;
|
||||||
|
|
||||||
|
return m_filled-1;
|
||||||
|
}
|
||||||
|
void remove_simple(int index)
|
||||||
|
{
|
||||||
|
assert(index < m_filled);
|
||||||
|
m_filled--;
|
||||||
|
if (index != m_filled) m_values[index] = m_values[m_filled];
|
||||||
|
}
|
||||||
|
const int exists(const T& value) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_filled; i++) if (m_values[i] == value) return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
void clear() { m_filled = 0; }
|
||||||
|
const unsigned size() const { return m_filled; }
|
||||||
|
const bool empty() const { return m_filled == 0; }
|
||||||
|
T operator[](int index) const { return m_values[index]; }
|
||||||
|
T& operator[](int index) { return m_values[index]; }
|
||||||
|
Array<T>& operator=( const Array<T>& other ) {
|
||||||
|
if (other.m_filled > m_allocated) {
|
||||||
|
m_values = (T*)realloc(m_values, sizeof(T)*other.m_filled);
|
||||||
|
}
|
||||||
|
m_allocated = other.m_filled;
|
||||||
|
m_filled = other.m_filled;
|
||||||
|
m_dynamic = other.m_dynamic;
|
||||||
|
memcpy(m_values, other.m_values, sizeof(T)*m_filled);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
unsigned m_allocated{0};
|
||||||
|
unsigned m_filled{0};
|
||||||
|
bool m_dynamic{true};
|
||||||
|
T* m_values{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector3 calculate_normal(const Vector3& v1, const Vector3& v2, const Vector3& v3);
|
||||||
|
|
||||||
|
const float random(const float& rangeMin, const float& rangeMax);
|
||||||
|
const float random_int(const int& rangeMin, const int& rangeMax);
|
||||||
77
grid.cpp
Normal file
77
grid.cpp
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#include "grid.h"
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
|
||||||
|
//#include "viewport.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
namespace Grid
|
||||||
|
{
|
||||||
|
bool visible = true;
|
||||||
|
|
||||||
|
void Toggle()
|
||||||
|
{
|
||||||
|
visible = not visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Draw(const char viewport, int size)
|
||||||
|
{
|
||||||
|
if (not visible) return;
|
||||||
|
|
||||||
|
int planeOffset = 0;
|
||||||
|
char axis = 1; //AXIS_Y;
|
||||||
|
/* Viewport::Viewport v = Viewport::GetViewport(viewport);
|
||||||
|
if (v.perspective == Viewport::Perspective::Ortho) {
|
||||||
|
if (v.yaw == 0 and v.pitch == 90) {
|
||||||
|
planeOffset = 999;
|
||||||
|
axis = AXIS_Y;
|
||||||
|
} else if (v.yaw == 0 and v.pitch == -90) {
|
||||||
|
planeOffset = -999;
|
||||||
|
axis = AXIS_Y;
|
||||||
|
} else if (v.yaw == 90 and v.pitch == 0) {
|
||||||
|
planeOffset = -999;
|
||||||
|
axis = AXIS_X;
|
||||||
|
} else if (v.yaw == -90 and v.pitch == 0) {
|
||||||
|
planeOffset = 999;
|
||||||
|
axis = AXIS_X;
|
||||||
|
} else if (v.yaw == 0 and v.pitch == 0) {
|
||||||
|
planeOffset = 999;
|
||||||
|
axis = AXIS_Z;
|
||||||
|
} else if (v.yaw == 180 and v.pitch == 0) {
|
||||||
|
planeOffset = -999;
|
||||||
|
axis = AXIS_Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const char axis_x = 0; //axis == AXIS_Z ? AXIS_X : axis == AXIS_X ? AXIS_Z : AXIS_X;
|
||||||
|
const char axis_y = 1; //axis == AXIS_Z ? AXIS_Y : axis == AXIS_X ? AXIS_Y : AXIS_Z;
|
||||||
|
|
||||||
|
|
||||||
|
Renderer::Push();
|
||||||
|
Renderer::Light(OFF);
|
||||||
|
Renderer::Depth(OFF);
|
||||||
|
if (size == 0) size = planeOffset == 0 ? 20 : 30;
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
for (int i = -size; i <= size; i++) {
|
||||||
|
if (i == 0) {
|
||||||
|
glColor4f(0.5f, 0.5f, 0.5f, 1);
|
||||||
|
} else {
|
||||||
|
glColor4f(0.25f, 0.25f, 0.25f, 1);
|
||||||
|
}
|
||||||
|
char pos[2][3] {{0,0,0}, {0,0,0}};
|
||||||
|
pos[0][axis_x] = -size;
|
||||||
|
pos[1][axis_x] = size;
|
||||||
|
pos[0][axis_y] = pos[1][axis_y] = i;
|
||||||
|
pos[0][axis] = pos[1][axis] = planeOffset;
|
||||||
|
glVertex3f(pos[0][0], pos[0][1], pos[0][2]);
|
||||||
|
glVertex3f(pos[1][0], pos[1][1], pos[1][2]);
|
||||||
|
pos[0][axis_y] = -size;
|
||||||
|
pos[1][axis_y] = size;
|
||||||
|
pos[0][axis_x] = pos[1][axis_x] = i;
|
||||||
|
pos[0][axis] = pos[1][axis] = planeOffset;
|
||||||
|
glVertex3f(pos[0][0], pos[0][1], pos[0][2]);
|
||||||
|
glVertex3f(pos[1][0], pos[1][1], pos[1][2]);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
Renderer::Pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
7
grid.h
Normal file
7
grid.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Grid
|
||||||
|
{
|
||||||
|
void Toggle();
|
||||||
|
void Draw(const char viewport, int size = 0);
|
||||||
|
}
|
||||||
5
lagueirtofile
Normal file
5
lagueirtofile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
libs = -lSDL2 -lGL
|
||||||
|
cppflags = -D DEBUG -g
|
||||||
|
executable = biomed_debug
|
||||||
|
sourcepath = .
|
||||||
|
buildpath = build
|
||||||
156
main.cpp
Normal file
156
main.cpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#include "screen.h"
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
//#include "console.h"
|
||||||
|
//#include "interpreter.h"
|
||||||
|
//#include "worker.h"
|
||||||
|
//#include "layout.h"
|
||||||
|
//#include "texture.h"
|
||||||
|
//#include "turtle.h"
|
||||||
|
//#include "keystrokes.h"
|
||||||
|
#include "GUI.h"
|
||||||
|
#include "GUIMouse.h"
|
||||||
|
#include "GUIKeyboard.h"
|
||||||
|
#include "font.h"
|
||||||
|
#include "GUIViewport.h"
|
||||||
|
#include "Editor.h"
|
||||||
|
#include "texture.h"
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[])
|
||||||
|
{
|
||||||
|
// SDL INIT
|
||||||
|
|
||||||
|
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { puts("SDL_Init error"); return -1; }
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||||
|
|
||||||
|
SDL_Window* gWindow = SDL_CreateWindow("BiomED", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
||||||
|
if (gWindow == NULL) { puts("SDL_CreateWindow error"); return -1; }
|
||||||
|
|
||||||
|
SDL_GLContext gContext = SDL_GL_CreateContext(gWindow);
|
||||||
|
if (gContext == NULL) { puts("SDL_GL_CreateContext error"); return -1; }
|
||||||
|
|
||||||
|
if (SDL_GL_SetSwapInterval(1) < 0) { puts("WARNING: no vsync!"); }
|
||||||
|
|
||||||
|
|
||||||
|
// OPENGL INIT
|
||||||
|
|
||||||
|
glClearColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glClearDepth(1.0f);
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
glEnable(GL_NORMALIZE);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
||||||
|
glEnable(GL_LIGHT0);
|
||||||
|
//static const GLfloat LightPosition[]= {0.408248f, 0.408248f, -0.816497f, 0.0f};//{ 0.5f, 0.5f, 1.0f, 0.0f }; // 5 4 2 0
|
||||||
|
static const GLfloat LightPosition[]= {0, 0, -1.0f, 0.0f};//{ 0.5f, 0.5f, 1.0f, 0.0f }; // 5 4 2 0
|
||||||
|
static const GLfloat LightAmbient[]= { 0.2f, 0.2f, 0.2f, 1.0f };
|
||||||
|
static const GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
|
glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
|
||||||
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
|
||||||
|
glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
|
||||||
|
|
||||||
|
|
||||||
|
// SUBSYSTEMS INIT
|
||||||
|
|
||||||
|
//Console::Init();
|
||||||
|
//Worker::RegisterCommands();
|
||||||
|
//Layout::Load("_last", SILENT);
|
||||||
|
//Texture::texture = Texture::Create();
|
||||||
|
//Turtle::Clear();
|
||||||
|
|
||||||
|
Editor::texture = Texture::Create(32, 32);
|
||||||
|
for (int i = 0; i < 32*32*4; i++) Editor::bitmap[i] = 255;
|
||||||
|
Texture::Update(Editor::texture, 32, 32, Editor::bitmap);
|
||||||
|
|
||||||
|
Font* f = new Font();
|
||||||
|
f->Load("font");
|
||||||
|
|
||||||
|
viewports[1].rotation = {0,0};
|
||||||
|
|
||||||
|
// MAIN LOOP
|
||||||
|
|
||||||
|
SDL_Event e;
|
||||||
|
while (not Application::ShouldQuit()) {
|
||||||
|
|
||||||
|
// SDL EVENTS
|
||||||
|
|
||||||
|
while (SDL_PollEvent(&e) != 0) {
|
||||||
|
if (e.type == SDL_QUIT) {
|
||||||
|
Application::Quit();
|
||||||
|
} else if (e.type == SDL_WINDOWEVENT) {
|
||||||
|
if (e.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
|
SCREEN_WIDTH = e.window.data1;
|
||||||
|
SCREEN_HEIGHT = e.window.data2;
|
||||||
|
//GUIElement::root->SetSize(Vector2(e.window.data1, e.window.data2));
|
||||||
|
//} else if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
|
||||||
|
// GUIState::NeedsRedraw();
|
||||||
|
}
|
||||||
|
} else if (e.type == SDL_MOUSEMOTION) {
|
||||||
|
GUIMouse::ReceiveMouseMoveEvent(e.motion.x, e.motion.y);
|
||||||
|
} else if (e.type == SDL_MOUSEBUTTONDOWN) {
|
||||||
|
GUIMouse::Button b = e.button.button == 1 ? GUIMouse::Button::Left : e.button.button == 2 ? GUIMouse::Button::Middle : GUIMouse::Button::Right;
|
||||||
|
GUIMouse::ReceiveMouseDownEvent(b);
|
||||||
|
} else if (e.type == SDL_MOUSEBUTTONUP) {
|
||||||
|
GUIMouse::Button b = e.button.button == 1 ? GUIMouse::Button::Left : e.button.button == 2 ? GUIMouse::Button::Middle : GUIMouse::Button::Right;
|
||||||
|
GUIMouse::ReceiveMouseUpEvent(b);
|
||||||
|
} else if (e.type == SDL_KEYDOWN) {
|
||||||
|
GUIKeyboard::ReceiveKeyboardEvent(e.key.keysym.sym);
|
||||||
|
} else if (e.type == SDL_KEYUP) {
|
||||||
|
GUIKeyboard::ReceiveKeyboardEvent(SDLK_UNKNOWN);
|
||||||
|
} else if (e.type == SDL_MOUSEWHEEL) {
|
||||||
|
GUIMouse::ReceiveMouseWheelEvent(e.wheel.x, e.wheel.y);
|
||||||
|
} else if (e.type == SDL_MULTIGESTURE) {
|
||||||
|
printf("GESTURE: %.2f, %.2f, %i\n", e.mgesture.dTheta*100, e.mgesture.dDist*100, e.mgesture.numFingers);
|
||||||
|
GUIMouse::ReceiveMultigestureEvent(e.mgesture.dTheta, e.mgesture.dDist, e.mgesture.numFingers);
|
||||||
|
}
|
||||||
|
/*if (Console::Enable(QUERY)) {
|
||||||
|
if (e.type == SDL_TEXTINPUT) {
|
||||||
|
Console::PutChar(toupper(e.text.text[0]));
|
||||||
|
//printf("%c",e.text.text[0]);
|
||||||
|
} else if (e.type == SDL_KEYDOWN) {
|
||||||
|
if (e.key.keysym.sym == SDLK_RETURN) {
|
||||||
|
char command[80];
|
||||||
|
Console::Enter(command);
|
||||||
|
Worker::ExecuteCommand(Interpreter::Do(command));
|
||||||
|
} else if (e.key.keysym.sym == SDLK_BACKSPACE) {
|
||||||
|
Console::DelChar();
|
||||||
|
} else if (e.key.keysym.sym == SDLK_UP) {
|
||||||
|
Console::PrevComm();
|
||||||
|
} else if (e.key.keysym.sym == SDLK_DOWN) {
|
||||||
|
Console::NextComm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (e.type == SDL_KEYDOWN) {
|
||||||
|
Keystrokes::KeyPressed(e.key.keysym.sym);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DRAW
|
||||||
|
|
||||||
|
if (Application::NeedsUpdate(0)) {
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
//GUIState::Update();
|
||||||
|
GUI::Draw();
|
||||||
|
//Layout::Draw();
|
||||||
|
//Console::Draw();
|
||||||
|
|
||||||
|
SDL_GL_SwapWindow(gWindow);
|
||||||
|
glClearColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||||
|
Application::Updated();
|
||||||
|
GUIMouse::Reset();
|
||||||
|
GUIKeyboard::Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Layout::Save("_last");
|
||||||
|
}
|
||||||
|
|
||||||
171
renderer.cpp
Normal file
171
renderer.cpp
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
|
||||||
|
namespace Renderer
|
||||||
|
{
|
||||||
|
State currentState {RENDER_DEPTH};
|
||||||
|
State stackedStates[10];
|
||||||
|
char stackPos {0};
|
||||||
|
|
||||||
|
void DoLightOn();
|
||||||
|
void DoLightOff();
|
||||||
|
void DoFillOn();
|
||||||
|
void DoFillOff();
|
||||||
|
void DoDepthOn();
|
||||||
|
void DoDepthOff();
|
||||||
|
void DoBlendOn();
|
||||||
|
void DoBlendOff();
|
||||||
|
void DoTextureOn();
|
||||||
|
void DoTextureOff();
|
||||||
|
|
||||||
|
bool Light(const char state)
|
||||||
|
{
|
||||||
|
if (state == ON) {
|
||||||
|
DoLightOn();
|
||||||
|
} else if (state == OFF) {
|
||||||
|
DoLightOff();
|
||||||
|
}
|
||||||
|
return (currentState & RENDER_LIGHT) == RENDER_LIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Fill(const char state)
|
||||||
|
{
|
||||||
|
if (state == ON) {
|
||||||
|
DoFillOn();
|
||||||
|
} else if (state == OFF) {
|
||||||
|
DoFillOff();
|
||||||
|
}
|
||||||
|
return (currentState & RENDER_FILL) == RENDER_FILL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Depth(const char state)
|
||||||
|
{
|
||||||
|
if (state == ON) {
|
||||||
|
DoDepthOn();
|
||||||
|
} else if (state == OFF) {
|
||||||
|
DoDepthOff();
|
||||||
|
}
|
||||||
|
return (currentState & RENDER_DEPTH) == RENDER_DEPTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Blend(const char state)
|
||||||
|
{
|
||||||
|
if (state == ON) {
|
||||||
|
DoBlendOn();
|
||||||
|
} else if (state == OFF) {
|
||||||
|
DoBlendOff();
|
||||||
|
}
|
||||||
|
return (currentState & RENDER_BLEND) == RENDER_BLEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Texture(const char state)
|
||||||
|
{
|
||||||
|
if (state == ON) {
|
||||||
|
DoTextureOn();
|
||||||
|
} else if (state == OFF) {
|
||||||
|
DoTextureOff();
|
||||||
|
}
|
||||||
|
return (currentState & RENDER_TEXTURE) == RENDER_TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Push()
|
||||||
|
{
|
||||||
|
if (stackPos == 10) return;
|
||||||
|
stackedStates[stackPos++] = currentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pop()
|
||||||
|
{
|
||||||
|
if (stackPos == 0) return;
|
||||||
|
SetState(stackedStates[--stackPos]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetState(const State& state)
|
||||||
|
{
|
||||||
|
if ((state & RENDER_LIGHT) == RENDER_LIGHT) DoLightOn(); else DoLightOff();
|
||||||
|
if ((state & RENDER_FILL) == RENDER_FILL) DoFillOn(); else DoFillOff();
|
||||||
|
if ((state & RENDER_BLEND) == RENDER_BLEND) DoBlendOn(); else DoBlendOff();
|
||||||
|
if ((state & RENDER_DEPTH) == RENDER_DEPTH) DoDepthOn(); else DoDepthOff();
|
||||||
|
if ((state & RENDER_TEXTURE) == RENDER_TEXTURE) DoTextureOn(); else DoTextureOff();
|
||||||
|
}
|
||||||
|
|
||||||
|
State GetState()
|
||||||
|
{
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DoLightOn()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_LIGHT) == RENDER_LIGHT) return;
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
|
currentState |= RENDER_LIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoLightOff()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_LIGHT) != RENDER_LIGHT) return;
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glDisable(GL_COLOR_MATERIAL);
|
||||||
|
currentState &= uint8_t(~RENDER_LIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoFillOn()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_FILL) == RENDER_FILL) return;
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
currentState |= RENDER_FILL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoFillOff()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_FILL) != RENDER_FILL) return;
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||||
|
currentState &= uint8_t(~RENDER_FILL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoDepthOn()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_DEPTH) == RENDER_DEPTH) return;
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
currentState |= RENDER_DEPTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoDepthOff()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_DEPTH) != RENDER_DEPTH) return;
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
currentState &= uint8_t(~RENDER_DEPTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoBlendOn()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_BLEND) == RENDER_BLEND) return;
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
currentState |= RENDER_BLEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoBlendOff()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_BLEND) != RENDER_BLEND) return;
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
currentState &= uint8_t(~RENDER_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoTextureOn()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_TEXTURE) == RENDER_TEXTURE) return;
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
currentState |= RENDER_TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoTextureOff()
|
||||||
|
{
|
||||||
|
if ((currentState & RENDER_TEXTURE) != RENDER_TEXTURE) return;
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
currentState &= uint8_t(~RENDER_TEXTURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
26
renderer.h
Normal file
26
renderer.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define RENDER_NONE 0
|
||||||
|
#define RENDER_LIGHT 1
|
||||||
|
#define RENDER_FILL 2
|
||||||
|
#define RENDER_DEPTH 4
|
||||||
|
#define RENDER_BLEND 8
|
||||||
|
#define RENDER_TEXTURE 16
|
||||||
|
|
||||||
|
namespace Renderer
|
||||||
|
{
|
||||||
|
typedef unsigned char State;
|
||||||
|
|
||||||
|
bool Light(const char state = QUERY);
|
||||||
|
bool Fill(const char state = QUERY);
|
||||||
|
bool Depth(const char state = QUERY);
|
||||||
|
bool Blend(const char state = QUERY);
|
||||||
|
bool Texture(const char state = QUERY);
|
||||||
|
|
||||||
|
void Push();
|
||||||
|
void Pop();
|
||||||
|
void SetState(const State& state);
|
||||||
|
State GetState();
|
||||||
|
}
|
||||||
17
screen.cpp
Normal file
17
screen.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
float SCREEN_WIDTH = 1280;
|
||||||
|
float SCREEN_HEIGHT = 700;
|
||||||
|
|
||||||
|
namespace Screen
|
||||||
|
{
|
||||||
|
SDL_Window* gWindow = nullptr;
|
||||||
|
|
||||||
|
void Beep(unsigned char r, unsigned char g, unsigned char b){
|
||||||
|
glClearColor(float(r)/255.0f, float(g)/255.0f, float(b)/255.0f, 1.0f);
|
||||||
|
Application::NeedsUpdate(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
screen.h
Normal file
12
screen.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
extern float SCREEN_WIDTH;
|
||||||
|
extern float SCREEN_HEIGHT;
|
||||||
|
|
||||||
|
namespace Screen
|
||||||
|
{
|
||||||
|
extern SDL_Window* gWindow;
|
||||||
|
void Beep(unsigned char r = 255, unsigned char g = 255, unsigned char b = 255);
|
||||||
|
}
|
||||||
4687
stb_image.h
Normal file
4687
stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
71
texture.cpp
Normal file
71
texture.cpp
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#include "texture.h"
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STBI_NO_FAILURE_STRINGS
|
||||||
|
#include "stb_image.h"
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
|
||||||
|
namespace Texture
|
||||||
|
{
|
||||||
|
unsigned texture = 0;
|
||||||
|
|
||||||
|
unsigned Create(const int w, const int h)
|
||||||
|
{
|
||||||
|
unsigned texture;
|
||||||
|
glGenTextures(1, &texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
if (w != -1) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool Load(const unsigned& texture, const char* filename)
|
||||||
|
{
|
||||||
|
int x,y,n;
|
||||||
|
char name[400]; strcpy(name, filename);
|
||||||
|
if (strrchr(filename, '.') == nullptr) strcat(name, ".png");
|
||||||
|
unsigned char *data = stbi_load(name, &x, &y, &n, 4);
|
||||||
|
if (data == nullptr) return false;
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
|
||||||
|
stbi_image_free(data);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* Load(const char* filename)
|
||||||
|
{
|
||||||
|
int x,y,n;
|
||||||
|
char name[400]; strcpy(name, filename);
|
||||||
|
if (strrchr(filename, '.') == nullptr) strcat(name, ".png");
|
||||||
|
unsigned char *data = stbi_load(name, &x, &y, &n, 4);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(const unsigned& texture, const int w, const int h, const uint8_t* data)
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Bitmap
|
||||||
|
{
|
||||||
|
void PutPixel(uint8_t* data, const int x, const int y, const Color& color)
|
||||||
|
{
|
||||||
|
memcpy(&data[x+y*128], &color, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color GetPixel(uint8_t* data, const int x, const int y)
|
||||||
|
{
|
||||||
|
Color color;
|
||||||
|
data += (x+y*128);
|
||||||
|
color.r = *(data++);
|
||||||
|
color.g = *(data++);
|
||||||
|
color.b = *(data++);
|
||||||
|
color.a = *(data++);
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
texture.h
Normal file
19
texture.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
namespace Texture
|
||||||
|
{
|
||||||
|
extern unsigned texture;
|
||||||
|
|
||||||
|
unsigned Create(const int w = -1, const int h = -1);
|
||||||
|
const bool Load(const unsigned& texture, const char* filename);
|
||||||
|
uint8_t* Load(const char* filename);
|
||||||
|
void Update(const unsigned& texture, const int w, const int h, const uint8_t* data);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Bitmap
|
||||||
|
{
|
||||||
|
void PutPixel(uint8_t* data, const int x, const int y, const Color& color);
|
||||||
|
const Color GetPixel(uint8_t* data, const int x, const int y);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user