- First commit to gitea

This commit is contained in:
2026-02-12 10:51:02 +01:00
commit a16a5a4102
40 changed files with 10033 additions and 0 deletions

3
.gitignore vendored Executable file
View File

@@ -0,0 +1,3 @@
build/*
biomed
biomed_debug

34
Editor.cpp Normal file
View 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
View 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
View 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
GUI.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
namespace GUI
{
void Draw();
}

6
GUIDialogs.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
namespace GUIDialogs
{
char* ChooseFile();
}

29
GUIDialogs.mm Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,3 @@
#include "GUIViewport.h"
Viewport viewports[3];

18
GUIViewport.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
};

BIN
font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

26
geometry.cpp Normal file
View 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
View 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
View 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
View File

@@ -0,0 +1,7 @@
#pragma once
namespace Grid
{
void Toggle();
void Draw(const char viewport, int size = 0);
}

5
lagueirtofile Normal file
View File

@@ -0,0 +1,5 @@
libs = -lSDL2 -lGL
cppflags = -D DEBUG -g
executable = biomed_debug
sourcepath = .
buildpath = build

156
main.cpp Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

71
texture.cpp Normal file
View 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
View 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);
}