tacraft/model_object.hpp

330 lines
12 KiB
C++

#ifndef _MODEL_OBJECT_HPP_
#define _MODEL_OBJECT_HPP_
#include <functional>
#include "rusty.hpp"
#include "basic_model.hpp"
class SceneMgr {
};
class ModelBasic {
public:
ModelBasic(ModelUnit u, VertCollection& v) : unit(u), vc(v) {}
const VertexAttribute& get_attribute() { return vc.all_attributes()[index[0]]; }
ModelBasic& set_attribute_index(uint32_t idx) {
index[0] = idx;
auto& vertices = vc.all_vertices();
for(uint32_t i = unit.vert_offset; i < unit.vert_offset + unit.vert_count; ++i)
vertices[i].index[0] = idx;
return *this;
}
ModelBasic& set_texture_index(uint32_t idx) {
index[1] = idx;
auto& vertices = vc.all_vertices();
for(uint32_t i = unit.vert_offset; i < unit.vert_offset + unit.vert_count; ++i)
vertices[i].index[1] = idx;
return *this;
}
uint32_t att_index() { return index[0]; }
uint32_t tex_index() { return index[1]; }
ModelUnit model_info() { return unit; }
ModelBasic& set_matrix(tmath::fmat4 mat) {
vc.all_attributes()[index[0]].matrix = mat;
vc.all_attributes()[index[0]].nmatrix = mat.homo_inverse().transpose();
return *this;
}
ModelBasic& set_matrix_no_normal(tmath::fmat4 mat) {
vc.all_attributes()[index[0]].matrix = mat;
return *this;
}
ModelBasic& set_color(tmath::fvec4 color) { vc.all_attributes()[index[0]].color = color; return *this; }
ModelBasic& set_mixcolor(tmath::fvec4 color) { vc.all_attributes()[index[0]].mixcolor = color; return *this; }
private:
ModelUnit unit;
uint32_t index[2];
VertCollection& vc;
};
class ModelObject {
public:
virtual bool update(double tm) = 0;
};
namespace mdo {
class MDLAxis : public ModelObject {
public:
MDLAxis(VertCollection& collection) {
auto m1 = collection.gen_cylinder(0.05f, 0.05f, 1.0f, 16, 1);
auto ptr1 = std::make_shared<ModelBasic>(m1, collection);
ptr1->set_attribute_index(collection.allocate_attribute_index())
.set_matrix(tmath::fmat4::identity().rotatey(pi * 0.5f))
.set_color({1.0f, 0.0f, 0.0f, 1.0f});
units.push_back(ptr1);
auto m2 = collection.gen_cylinder(0.05f, 0.05f, 1.0f, 16, 1);
auto ptr2 = std::make_shared<ModelBasic>(m2, collection);
ptr2->set_attribute_index(collection.allocate_attribute_index())
.set_matrix(tmath::fmat4::identity().rotatex(pi * -0.5f))
.set_color({0.0f, 0.85f, 0.3f, 1.0f});
units.push_back(ptr2);
auto m3 = collection.gen_cylinder(0.05f, 0.05f, 1.0f, 16, 1);
auto ptr3 = std::make_shared<ModelBasic>(m3, collection);
ptr3->set_attribute_index(collection.allocate_attribute_index())
.set_matrix(tmath::fmat4::identity())
.set_color({0.0f, 0.2f, 1.0f, 1.0f});
units.push_back(ptr3);
auto m4 = collection.gen_cylinder(0.1f, 0.0f, 0.2f, 16, 1);
auto ptr4 = std::make_shared<ModelBasic>(m4, collection);
ptr4->set_attribute_index(collection.allocate_attribute_index())
.set_matrix(tmath::fmat4::identity().rotatey(pi * 0.5f).translate(1.0f, 0.0f, 0.0f))
.set_color({1.0f, 0.0f, 0.0f, 1.0f});
units.push_back(ptr4);
auto m5 = collection.gen_cylinder(0.1f, 0.0f, 0.2f, 16, 1);
auto ptr5 = std::make_shared<ModelBasic>(m5, collection);
ptr5->set_attribute_index(collection.allocate_attribute_index())
.set_matrix(tmath::fmat4::identity().rotatex(pi * -0.5f).translate(0.0f, 1.0f, 0.0f))
.set_color({0.0f, 0.85f, 0.3f, 1.0f});
units.push_back(ptr5);
auto m6 = collection.gen_cylinder(0.1f, 0.0f, 0.2f, 16, 1);
auto ptr6 = std::make_shared<ModelBasic>(m6, collection);
ptr6->set_attribute_index(collection.allocate_attribute_index())
.set_matrix(tmath::fmat4::identity().translate(0.0f, 0.0f, 1.0f))
.set_color({0.0f, 0.2f, 1.0f, 1.0f});
units.push_back(ptr6);
}
bool update(double tm) override { return false; }
private:
std::vector<std::shared_ptr<ModelBasic>> units;
};
class MDLUnits : public ModelObject {
public:
static tmath::fvec3 pos_center(int32_t x, int32_t y) {
return tmath::fvec3{0.25f + x * 0.5f, 0.25f + (31 - y) * 0.5f, 0.0f};
}
std::pair<int32_t, int32_t> pos() { return std::make_pair(posx, posy); }
std::pair<int32_t, int32_t> target_pos() { return std::make_pair(tposx, tposy); }
void set_pos(int32_t x, int32_t y) {
posx = x;
posy = y;
auto pc = pos_center(x, y);
self_matrix = tmath::fmat4::identity().translate(pc[0], pc[1], pc[2]);
self_matrix_updated = true;
}
void set_target_pos(int32_t x, int32_t y) {
tposx = x;
tposy = y;
}
virtual void move_to(int32_t x, int32_t y, float tm) = 0;
virtual void attack(MDLUnits&, float tm) = 0;
virtual void damage(MDLUnits&, float tm) = 0;
bool update(double tm) override {
last_update = tm;
self_matrix_updated = false;
return false;
}
protected:
int32_t posx;
int32_t posy;
int32_t tposx;
int32_t tposy;
float last_update = 0.0f;
bool self_matrix_updated = false;
tmath::fmat4 self_matrix;
};
class MDLField : public ModelObject {
public:
MDLField(VertCollection& collection) {
float tw = 1.0f / 32;
float th = 1.0f / 32;
for(uint32_t y = 0; y < 32; ++y) {
for(uint32_t x = 0; x < 32; ++x) {
auto m = collection.gen_square(tw * x, th * y, tw, th);
auto ptr = std::make_shared<ModelBasic>(m, collection);
ptr->set_attribute_index(collection.allocate_attribute_index())
.set_matrix_no_normal(tmath::fmat4::identity().scale(0.25f, 0.25f, 1.0f).translate(0.25f + x * 0.5f, 0.25f + y * 0.5f, 0.0f))
.set_texture_index(1);
units.push_back(ptr);
}
}
}
bool update(double tm) override {
if(hindex != -1) {
units[hindex]->set_mixcolor({1.0f, 1.0f, 1.0f, std::sin((float)tm * 32.0f / pi) * 0.4f + 0.5f});
}
auto iter = status.begin();
while(iter != status.end()) {
auto cur = iter++;
float delta = (tm - cur->second) * 2.0f;
auto mc = units[cur->first]->get_attribute().mixcolor;
if(mc[3] > delta) {
mc[3] = mc[3] - delta;
units[cur->first]->set_mixcolor(mc);
cur->second = tm;
} else {
mc[3] = 0.0f;
units[cur->first]->set_mixcolor(mc);
status.erase(cur);
}
}
last_update = tm;
return false;
}
void mouse_point(float x, float y) {
int32_t idx = -1;
if(x > 0.0f && x < 16.0f && y > 0.0f && y < 16.0f) {
int32_t bx = (int32_t)(x * 2.0f);
int32_t by = (int32_t)(y * 2.0f);
idx = bx + by * 32;
}
if(hindex == idx)
return;
status.erase(idx);
if(hindex != -1) {
status[hindex] = last_update;
units[hindex]->set_mixcolor({1.0f, 1.0f, 1.0f, 0.9f});
}
hindex = idx;
}
void mouse_press(bool up) {
}
void add_object(std::weak_ptr<MDLUnits> obj, int32_t x, int32_t y) {
auto fid = uindex(x, y);
if(objects[fid].lock() != nullptr)
return;
objects[fid] = obj;
}
std::shared_ptr<MDLUnits> get_unit(int32_t x, int32_t y) {
return objects[uindex(x, y)].lock();
}
static int32_t uindex(int32_t x, int32_t y) { return x + (31 - y) * 32; }
private:
int32_t hindex = -1;
float last_update = 0.0f;
rs::unordered_map<int32_t, float> status;
std::vector<std::shared_ptr<ModelBasic>> units;
std::weak_ptr<MDLUnits> objects[1024];
};
class MDLUnit1 : public MDLUnits {
public:
MDLUnit1(VertCollection& collection) {
auto m1 = collection.gen_solid_of_revolution(0.0f, 1.0f, [](float z){ return (z - 0.55f) * (z - 0.55f)* 0.5f + 0.1f; }, 32, 32);
auto ptr1 = std::make_shared<ModelBasic>(m1, collection);
ptr1->set_attribute_index(collection.allocate_attribute_index())
.set_matrix(tmath::fmat4::identity().scale(1.0f, 1.0f, 0.5f))
.set_color({0.0f, 0.8f, 0.3f, 1.0f});
units.push_back(ptr1);
auto m2 = collection.gen_octahedron();
auto ptr2 = std::make_shared<ModelBasic>(m2, collection);
ptr2->set_attribute_index(collection.allocate_attribute_index())
.set_matrix(tmath::fmat4::identity().scale(0.2f, 0.2f, 0.4f).translate(0.0f, 0.0f, 1.0f))
.set_color({0.7f, 0.1f, 0.3f, 0.8f});
units.push_back(ptr2);
}
bool update(double tm) override {
bool updated = self_matrix_updated;
MDLUnits::update(tm);
for(auto iter = updator.begin(); iter != updator.end();) {
if((*iter)(tm))
updator.erase(iter++);
else
iter++;
}
if(updated)
units[0]->set_matrix(self_matrix * tmath::fmat4::identity().scale(0.6f, 0.6f, 0.5f));
units[1]->set_matrix(self_matrix * tmath::fmat4::identity().scale(0.15f, 0.15f, 0.2f).rotatez(tm * 2.0f).translate(0.0f, 0.0f, 0.8f));
return !updator.empty();
}
void move_to(int32_t x, int32_t y, float tm) {
auto cur = pos_center(posx, posy);
auto end = pos_center(x, y);
posx = x;
posy = y;
add_move(cur, end, tm, {0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, nullptr);
}
void attack(MDLUnits& u, float tm) {
auto [x, y] = u.pos();
auto cur = pos_center(posx, posy);
auto src = pos_center(x, y);
auto end = cur + (src - cur) * 0.8f;
add_move(cur, end, tm * 0.5f, {0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, [this, &u, tm, end, cur](){
u.damage(*this, 0.2f);
add_move(end, cur, tm * 0.5f, {0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, nullptr);
});
}
void damage(MDLUnits& u, float tm) {
auto [fx, fy] = u.pos();
auto cur = pos_center(posx, posy);
auto src = pos_center(fx, fy);
auto end = cur + (cur - src) * 0.25f;
add_move(cur, end, tm * 0.5f, {1.0f, 1.0f, 1.0f}, 0.0f, 0.9f, [this, tm, end, cur](){
add_move(end, cur, tm * 0.5f, {1.0f, 1.0f, 1.0f}, 0.9f, 0.0f, nullptr);
});
}
void add_move(tmath::fvec3 from, tmath::fvec3 to, float tm, tmath::fvec3 mc, float a1, float a2, const std::function<void()>& end_cb) {
updator.push_back([this, from, to, st = last_update, tm, mc, a1, a2, end_cb](float t){
auto h = std::sqrt((to[0] - from[0]) * (to[0] - from[0]) + (to[1] - from[1]) * (to[1] - from[1]))* 1.0f;
if(t >= st + tm) {
if(end_cb)
end_cb();
for(auto& m : units)
m->set_mixcolor({mc[0], mc[1], mc[2], a2});
self_matrix = tmath::fmat4::identity().translate(to[0], to[1], to[2]);
self_matrix_updated = true;
return true;
} else {
float factor = (t - st) / tm;
auto pos = from + (to - from) * factor;
for(auto& m : units)
m->set_mixcolor({mc[0], mc[1], mc[2], a1 + (a2 - a1) * factor});
self_matrix = tmath::fmat4::identity().translate(pos[0], pos[1], (factor - 0.5f) * (0.5f - factor) * h + h * 0.25f);
self_matrix_updated = true;
return false;
}
});
}
private:
std::vector<std::shared_ptr<ModelBasic>> units;
rs::list<std::function<bool(float)>> updator;
};
}
#endif