mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-24 01:00:25 +00:00
rogueviz:: added objmodels.cpp and some demos using it
This commit is contained in:
parent
ccc5e3bf9b
commit
30b79de1f5
293
rogueviz/ascending-descending.cpp
Normal file
293
rogueviz/ascending-descending.cpp
Normal file
@ -0,0 +1,293 @@
|
||||
#include "rogueviz.h"
|
||||
|
||||
namespace hr {
|
||||
|
||||
namespace ply {
|
||||
|
||||
bool in, animated;
|
||||
|
||||
using namespace rogueviz::objmodels;
|
||||
|
||||
hyperpoint A = point31(9.7, -38.1, 10.116);
|
||||
hyperpoint B = point31(17.3, -38.1, 10.95);
|
||||
hyperpoint C = point31(17.3, -46.1, 11.75);
|
||||
hyperpoint D = point31(12.95, -46.08, 12.28);
|
||||
hyperpoint E = point31(12.86, -44.53, 12.4);
|
||||
|
||||
ld radius = (12.86 - 11.11) / 2;
|
||||
|
||||
transmatrix nilform;
|
||||
|
||||
map<hyperpoint, pair<int, hyperpoint> > cache;
|
||||
|
||||
bool debugnil = false;
|
||||
bool usecache = true;
|
||||
|
||||
pair<int, hyperpoint> nilize(hyperpoint h) {
|
||||
|
||||
hyperpoint hc = h;
|
||||
for(int i=0; i<4; i++) hc[i] = floor(h[i] * 1000 + .5);
|
||||
if(usecache && cache.count(hc)) return cache[hc];
|
||||
|
||||
hyperpoint at = A;
|
||||
|
||||
hyperpoint result = C0;
|
||||
|
||||
auto move_coord_full = [&] (hyperpoint tgt) {
|
||||
for(int i=0; i<100; i++) {
|
||||
result = nisot::translate(result) * nilform * ((tgt - at) / 100 + C0);
|
||||
}
|
||||
at = tgt;
|
||||
};
|
||||
|
||||
auto move_coord = [&] (int c, hyperpoint upto) {
|
||||
ld part = (h[c] - at[c]) / (upto[c] - at[c]);
|
||||
if(part > 1) part = 1;
|
||||
move_coord_full(at + part * (upto-at));
|
||||
};
|
||||
|
||||
int cat = 0;
|
||||
|
||||
if(h[1] > -39) {
|
||||
move_coord(0, B);
|
||||
cat = 1;
|
||||
goto finish;
|
||||
}
|
||||
move_coord_full(B);
|
||||
if(h[0] > 17.2) {
|
||||
move_coord(1, C);
|
||||
cat = 2;
|
||||
goto finish;
|
||||
}
|
||||
move_coord_full(C);
|
||||
if(h[1] < -45.5) {
|
||||
move_coord(0, D);
|
||||
cat = 3;
|
||||
goto finish;
|
||||
}
|
||||
cat = 4;
|
||||
move_coord_full(D);
|
||||
move_coord(1, E);
|
||||
finish:
|
||||
|
||||
move_coord_full(h);
|
||||
return cache[hc] = {cat, result};
|
||||
}
|
||||
|
||||
ld vperiod;
|
||||
|
||||
pair<hyperpoint, hyperpoint> trace_path(ld v) {
|
||||
|
||||
ld vorig = v;
|
||||
|
||||
hyperpoint lctr = A;
|
||||
ld angle = 0;
|
||||
|
||||
ld arclen = radius * M_PI/2;
|
||||
|
||||
auto change_angle = [&] (ld x) {
|
||||
if(v == 0) return;
|
||||
else if(v >= arclen) v -= arclen, angle += 1;
|
||||
else angle += v / arclen, v = 0;
|
||||
};
|
||||
|
||||
auto shift_to = [&] (hyperpoint h, bool last = false) {
|
||||
ld seglen = hypot_d(3, h - lctr);
|
||||
if(v == 0) return;
|
||||
else if(v >= seglen && !last) v -= seglen, lctr = h;
|
||||
else lctr = lerp(lctr, h, v / seglen), v = 0;
|
||||
};
|
||||
|
||||
change_angle(1);
|
||||
shift_to(B);
|
||||
change_angle(2);
|
||||
shift_to(C);
|
||||
change_angle(3);
|
||||
shift_to(D);
|
||||
change_angle(4);
|
||||
shift_to(E, true);
|
||||
|
||||
angle *= M_PI/2;
|
||||
|
||||
if(v > 0) vperiod = vorig - v;
|
||||
|
||||
return { lctr + point3(radius * -cos(angle), radius * sin(angle), 0), point3(-sin(angle), -cos(angle), 0) };
|
||||
}
|
||||
|
||||
transmatrix scaleby(ld x) {
|
||||
transmatrix res = Id;
|
||||
for(int i=0; i<LDIM; i++)
|
||||
res[i][i] = x;
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<hyperpoint> route(1000), forwards(1000), overroute(1000);
|
||||
|
||||
hyperpoint interpolate_at(vector<hyperpoint>& v, ld x) {
|
||||
while(x > 1000) x -= 1000;
|
||||
return lerp(v[x], v[(int(x)+1) % 1000], frac(x));
|
||||
}
|
||||
|
||||
ld advance = 2;
|
||||
ld over = 1.5;
|
||||
ld over2 = 1;
|
||||
|
||||
void make_routes() {
|
||||
for(int i=0; i<1000; i++) {
|
||||
ld v = vperiod * i / 1000;
|
||||
route[i] = nilize(trace_path(v).first + point3(0,0,over)).second;
|
||||
ld vb = v + advance;
|
||||
if(vb > vperiod) vb -= vperiod;
|
||||
forwards[i] = nilize(trace_path(vb).first).second;
|
||||
overroute[i] = nilize(trace_path(v).first + point3(0,0,over+over2)).second;
|
||||
}
|
||||
|
||||
auto smoothen = [&] (vector<hyperpoint>& v) {
|
||||
for(int it=0; it<100; it++) {
|
||||
vector<hyperpoint> smoother;
|
||||
for(int i=0; i<1000; i++) {
|
||||
hyperpoint& a = v[i];
|
||||
hyperpoint& b = v[(i+1) % 1000];
|
||||
hyperpoint& c = v[(i+2) % 1000];
|
||||
smoother.push_back((a + b + c) / 3);
|
||||
}
|
||||
v = smoother;
|
||||
}
|
||||
};
|
||||
|
||||
smoothen(route);
|
||||
smoothen(forwards);
|
||||
smoothen(overroute);
|
||||
}
|
||||
|
||||
bool prepared;
|
||||
|
||||
void prepare_nilform() {
|
||||
if(prepared) return;
|
||||
prepared = true;
|
||||
hyperpoint axis = (E - A);
|
||||
transmatrix rotator = Id;
|
||||
rotator[2] = axis;
|
||||
println(hlog, " = ", (rotator[2] | rotator[2]));
|
||||
rotator[2] /= sqrt(rotator[2] | rotator[2]);
|
||||
rotator[1] -= (rotator[1] | rotator[2]) * rotator[2];
|
||||
rotator[1] /= sqrt(rotator[1] | rotator[1]);
|
||||
rotator[0] -= (rotator[0] | rotator[2]) * rotator[2];
|
||||
rotator[0] -= (rotator[0] | rotator[1]) * rotator[1];
|
||||
rotator[0] /= sqrt(rotator[0] | rotator[0]);
|
||||
println(hlog, "rotator = ", kz(rotator));
|
||||
rotator = inverse(transpose(rotator));
|
||||
println(hlog, "rotator = ", kz(rotator));
|
||||
|
||||
ld minscale = 0.5; // positive
|
||||
ld maxscale = 1.5; // negative
|
||||
ld scale;
|
||||
|
||||
for(int it=0; it<100; it++) {
|
||||
scale = (minscale + maxscale) / 2;
|
||||
nilform = rotator * scaleby(scale);
|
||||
cache.clear();
|
||||
hyperpoint nE = nilize(E).second;
|
||||
if(nE[2] < 0) maxscale = scale;
|
||||
else minscale = scale;
|
||||
}
|
||||
|
||||
println(hlog, "scale = ", scale);
|
||||
println(hlog, nilize(E).second);
|
||||
|
||||
vperiod = radius * 2 * M_PI + hypot_d(3, B-A) + hypot_d(3, C-B) + hypot_d(3, D-C) + hypot_d(3, E-D);
|
||||
println(hlog, "vperiod = ", vperiod);
|
||||
|
||||
make_routes();
|
||||
}
|
||||
|
||||
model staircase("rogueviz/nil/", "aco.obj", nilize);
|
||||
|
||||
bool draw_ply() {
|
||||
|
||||
if(!in) return false;
|
||||
|
||||
if(nil) prepare_nilform();
|
||||
|
||||
staircase.render(ggmatrix(currentmap->gamestart()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void show() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("Ascending & Descending"), 0xFFFFFFFF, 150, 0);
|
||||
|
||||
dialog::addSelItem("advance", fts(advance), 'a');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(advance, 0, 100, 1, 1, "advance", "");
|
||||
dialog::reaction = make_routes;
|
||||
});
|
||||
|
||||
dialog::addSelItem("over", fts(over), 'o');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(over, 0, 100, 1, 1, "over", "");
|
||||
dialog::reaction = make_routes;
|
||||
});
|
||||
|
||||
dialog::addSelItem("over2", fts(over2), 'p');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(over2, 0, 100, 1, 1, "over2", "");
|
||||
dialog::reaction = make_routes;
|
||||
});
|
||||
|
||||
dialog::addBoolItem_action("animated", animated, 'a');
|
||||
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
void o_key(o_funcs& v) {
|
||||
if(in) v.push_back(named_dialog("Ascending & Descending", show));
|
||||
}
|
||||
|
||||
auto plyhook = addHook(hooks_frame, 100, draw_ply)
|
||||
|
||||
+ addHook(anims::hooks_anim, 100, [] {
|
||||
if(!in || !animated) return;
|
||||
usecache = false;
|
||||
ld t = ticks * 1. / anims::period;
|
||||
t = t - floor(t);
|
||||
t *= 1000;
|
||||
|
||||
centerover = currentmap->gamestart();
|
||||
set_view(
|
||||
interpolate_at(route, t),
|
||||
interpolate_at(forwards, t),
|
||||
interpolate_at(overroute, t)
|
||||
);
|
||||
|
||||
anims::moved();
|
||||
})
|
||||
|
||||
+ addHook(hooks_o_key, 80, o_key)
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
+ addHook(hooks_args, 100, [] {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-asd")) {
|
||||
in = true;
|
||||
}
|
||||
else if(argis("-asd-prec")) {
|
||||
shift(); prec = argi();
|
||||
}
|
||||
else if(argis("-asd-anim")) {
|
||||
in = true;
|
||||
animated = true;
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
})
|
||||
#endif
|
||||
;
|
||||
|
||||
}
|
||||
}
|
189
rogueviz/backhead.cpp
Normal file
189
rogueviz/backhead.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
#include "rogueviz.h"
|
||||
|
||||
/*
|
||||
|
||||
used for https://youtu.be/KxjnibOkuLs
|
||||
|
||||
you need the models from https://renderpeople.com/free-3d-people/ (and convert them to the Wavefront OBJ format)
|
||||
|
||||
-geo 120c -canvas 1 -noplayer camspd=.1
|
||||
|
||||
*/
|
||||
|
||||
namespace hr {
|
||||
|
||||
namespace backhead {
|
||||
|
||||
int view_model_id = 0;
|
||||
int camera_model = 1;
|
||||
|
||||
using namespace rogueviz::objmodels;
|
||||
|
||||
map<int, model> models;
|
||||
|
||||
tf_result person_tf(hyperpoint h) { return {0, direct_exp(h*5)}; }
|
||||
|
||||
ld smoothen(ld x) { return x*x*(3-2*x); }
|
||||
|
||||
ld cm = 0.08 / 160;
|
||||
|
||||
bool use_camera;
|
||||
|
||||
transmatrix eyematrix(int id) {
|
||||
transmatrix S = Id;
|
||||
|
||||
int i = 0;
|
||||
if(id == 1) for(ld val: {-0.997647,0.00073308,-0.0685486,7.63928e-05,0.0147183,-0.971198,-0.224516,0.0784166,-0.0669523,-0.224937,0.972022,0.00970247,-0.000429702,0.0785862,0.00820562,0.996873})
|
||||
S[0][i++] = val;
|
||||
if(id == 0) for(ld val: {-0.976869,0.119464,-0.17719,-0.00766071,-0.0534002,-0.935386,-0.339797,0.0820953,-0.207062,-0.322171,0.923596,0.0173391,0.000492418,0.0835894,0.0105615,0.996444})
|
||||
S[0][i++] = val;
|
||||
|
||||
return S;
|
||||
}
|
||||
|
||||
ld back = 0;
|
||||
|
||||
bool do_anim = false;
|
||||
|
||||
int tf;
|
||||
|
||||
vector<string> captions = {
|
||||
"as seen by another person",
|
||||
"changing the view...",
|
||||
"L/R",
|
||||
"downward",
|
||||
"upwards",
|
||||
"back"
|
||||
};
|
||||
|
||||
EX bool ourStats() {
|
||||
|
||||
/*
|
||||
if(tf < 0 || tf >= 5) { println(hlog, "tf=", tf); tf = gmod(tf, 5); }
|
||||
|
||||
println(hlog, "displaying tf = ", tf);
|
||||
|
||||
displayfr(10, 10 + 7 * vid.fsize, 2, vid.fsize * 7, captions[tf], 0xFFFFFF, 0);
|
||||
|
||||
nohelp = true;
|
||||
nomenukey = true;
|
||||
clearMessages();
|
||||
|
||||
glflush();
|
||||
|
||||
println(hlog, "done?");
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void face_animation() {
|
||||
|
||||
if(!do_anim) return;
|
||||
|
||||
ld t = ticks / anims::period;
|
||||
|
||||
t = t - floor(t);
|
||||
|
||||
t *= 2;
|
||||
view_model_id = (t >= 1 ? 0 : 1);
|
||||
camera_model = 1 - view_model_id;
|
||||
if(t>=1) t -= 1;
|
||||
|
||||
t *= 4.5;
|
||||
|
||||
if(t < 1) {
|
||||
if(t < .7) t /= .7;
|
||||
else t = (t-.7) / .3 + 1;
|
||||
}
|
||||
else
|
||||
t++;
|
||||
|
||||
// t *= 5;
|
||||
|
||||
tf = t;
|
||||
t -= tf;
|
||||
|
||||
View = Id;
|
||||
|
||||
ld up = view_model_id == 0 ? 82 : 90;
|
||||
ld down = view_model_id == 1 ? 65 : 70;
|
||||
|
||||
up -= 15; down -= 15;
|
||||
|
||||
tie(up, down) = make_pair(-down, -up);
|
||||
|
||||
if(tf == 0) {
|
||||
View = cspin(0, 2, 360 * degree * smoothen(t)) * View;
|
||||
View = zpush(-0.1) * View;
|
||||
View = cspin(0, 2, M_PI) * View;
|
||||
back = 0;
|
||||
}
|
||||
else if(tf == 1) {
|
||||
View = zpush(-0.1 * (1-smoothen(t))) * View;
|
||||
if(t > .9)
|
||||
back = -0.1 * smoothen(10*t-9);
|
||||
View = cspin(0, 2, M_PI) * View;
|
||||
}
|
||||
else if(tf == 2) {
|
||||
View = cspin(0, 2, 75*degree*sin(2*M_PI*smoothen(t))) * View;
|
||||
}
|
||||
else if(tf == 3) {
|
||||
View = cspin(1, 2, up*degree*smoothen(t)) * View;
|
||||
}
|
||||
else if(tf == 4) {
|
||||
View = cspin(1, 2, degree*(up-(up+down)*smoothen(t))) * View;
|
||||
}
|
||||
else if(tf == 5) {
|
||||
View = cspin(1, 2, degree*-down*(1-smoothen(t*2))) * View;
|
||||
}
|
||||
|
||||
use_camera = tf <= 1;
|
||||
|
||||
sightranges[geometry] = use_camera ? 30 : 100;
|
||||
if(tf == 5) sightranges[geometry] = 100 - 70 * smoothen(t*2);
|
||||
|
||||
anims::moved();
|
||||
|
||||
hide_hud = false;
|
||||
}
|
||||
|
||||
bool draw_ply() {
|
||||
|
||||
if(models.empty()) {
|
||||
models[0] = model("rogueviz/models/", "dennis.obj", person_tf);
|
||||
models[1] = model("rogueviz/models/", "mei.obj", person_tf);
|
||||
}
|
||||
|
||||
shiftmatrix Zero = ggmatrix(currentmap->gamestart());
|
||||
|
||||
Zero = Zero * eyematrix(view_model_id);
|
||||
println(hlog, Zero);
|
||||
|
||||
models[view_model_id].render(Zero);
|
||||
|
||||
if(use_camera) models[camera_model].render(shiftless(eyematrix(camera_model) * zpush(back)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto plyhook = addHook(hooks_frame, 100, draw_ply)
|
||||
+ addHook(anims::hooks_anim, 100, face_animation)
|
||||
+ addHook(hooks_args, 100, [] {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-head-swap")) {
|
||||
swap(view_model_id, camera_model);
|
||||
}
|
||||
else if(argis("-head-anim")) {
|
||||
do_anim = !do_anim;
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
})
|
||||
+ addHook(hooks_prestats, 100, ourStats)
|
||||
;
|
||||
|
||||
}
|
||||
}
|
94
rogueviz/hypcity.cpp
Normal file
94
rogueviz/hypcity.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#include "rogueviz.h"
|
||||
|
||||
// 'hyperbolic city' demo
|
||||
// download the model from https://sketchfab.com/3d-models/night-city-p2-82637933a7cb4fafadb0e2a79415c438 as rogueviz/models/emilejohansson_p2.obj
|
||||
|
||||
// see the results posted here:
|
||||
|
||||
// https://twitter.com/ZenoRogue/status/1375750351391981570
|
||||
// -noplayer -geo 4x5 -gp 1 1 -unrectified -switch-fpp -canvas 303030 camera=0 depth=0 -sr 3 -PM 0 -alpha 1 -zoom .95
|
||||
|
||||
// https://twitter.com/ZenoRogue/status/1375748835046215682
|
||||
// -noplayer -geo nil -canvas 303030 -back 44e4 -sight3 3
|
||||
|
||||
// https://twitter.com/ZenoRogue/status/1375754422752575488
|
||||
// add -PM 0 -alpha 1
|
||||
|
||||
namespace hr {
|
||||
|
||||
using namespace rogueviz::objmodels;
|
||||
|
||||
model city("rogueviz/models/", "emilejohansson_p2.obj");
|
||||
|
||||
hyperpoint low, high;
|
||||
|
||||
void prepare_tf() {
|
||||
if(!city.models.empty()) return;
|
||||
|
||||
prec = 40;
|
||||
|
||||
for(int i=0; i<4; i++) low[i] = 100, high[i] = -100;
|
||||
|
||||
cgi.require_basics();
|
||||
hyperpoint corner = get_corner_position(cwt.at, 0);
|
||||
|
||||
ld t = abs(corner[0] / corner[3]);
|
||||
|
||||
city.tf = [=] (hyperpoint h) -> pair<int, hyperpoint> {
|
||||
swap(h[1], h[2]);
|
||||
h[2] = -h[2];
|
||||
h[2] += 0.063;
|
||||
h[0] -= 0.063;
|
||||
h[1] += 0.063;
|
||||
h *= 6;
|
||||
// h[0] -= .5;
|
||||
// h[1] += .5;
|
||||
|
||||
for(int i=0; i<4; i++)
|
||||
low[i] = min(low[i], h[i]),
|
||||
high[i] = max(high[i], h[i]);
|
||||
|
||||
if(hyperbolic) {
|
||||
|
||||
hyperpoint hx;
|
||||
hx[0] = h[0] * t * 2;
|
||||
hx[1] = h[1] * t * 2;
|
||||
hx[2] = 0;
|
||||
hx[3] = 1;
|
||||
hx = spin(45 * degree) * hx;
|
||||
normalize(hx);
|
||||
hx = zshift(hx, h[2]*(t*7));
|
||||
|
||||
return {0, hx};
|
||||
}
|
||||
|
||||
if(nil) {
|
||||
swap(h[1], h[2]);
|
||||
h *= 0.5 / 0.378;
|
||||
h[3] = 1;
|
||||
return {0, h};
|
||||
}
|
||||
|
||||
return {0, h};
|
||||
};
|
||||
println(hlog, "low = ", low);
|
||||
println(hlog, "high = ", high);
|
||||
}
|
||||
|
||||
bool draw_city_at(cell *c, const shiftmatrix& V) {
|
||||
prepare_tf();
|
||||
|
||||
if(nil) {
|
||||
auto co = nilv::get_coord(c->master);
|
||||
if(co[1]) return false;
|
||||
}
|
||||
|
||||
if(c == cwt.at || true)
|
||||
city.render(V);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto hypcity_ah = addHook(hooks_drawcell, 100, draw_city_at);
|
||||
|
||||
}
|
243
rogueviz/objmodels.cpp
Normal file
243
rogueviz/objmodels.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
/* a library for loading 3D models */
|
||||
|
||||
#include "rogueviz.h"
|
||||
|
||||
namespace rogueviz {
|
||||
|
||||
namespace objmodels {
|
||||
|
||||
bool scan(fhstream& hs, char& c) { return fscanf(hs.f, "%c", &c) == 1; }
|
||||
|
||||
char peek(fhstream& fs) {
|
||||
char g = fgetc(fs.f);
|
||||
ungetc(g, fs.f);
|
||||
return g;
|
||||
}
|
||||
|
||||
void model::load_obj(model_type& objects) {
|
||||
fhstream fs(path+fname, "rt");
|
||||
|
||||
if(!fs.f)
|
||||
throw hr_exception("failed to open model file: " + path + fname);
|
||||
|
||||
vector<hyperpoint> vertices;
|
||||
vector<hyperpoint> normals;
|
||||
vector<hyperpoint> tvertices;
|
||||
|
||||
while(!feof(fs.f)) {
|
||||
string s;
|
||||
scan(fs, s);
|
||||
if(s == "#") { scanline(fs); }
|
||||
else if(s == "mtllib") {
|
||||
string mtllib;
|
||||
scan(fs, mtllib);
|
||||
fhstream fsm(path+mtllib, "rt");
|
||||
if(!fsm.f)
|
||||
throw hr_exception("failed to open mtllib: " + mtllib);
|
||||
color_t nextcol = 0xFFFFFFFF;
|
||||
string mtlname, texname = "";
|
||||
auto emit_material = [&] {
|
||||
if(texname != "") {
|
||||
texture::texture_data tdata;
|
||||
materials[mtlname] = tdata;
|
||||
auto& mat = materials[mtlname];
|
||||
mat.twidth = mat.theight = 0; mat.stretched = true;
|
||||
println(hlog, "texname: ", texname);
|
||||
mat.readtexture(path+texname);
|
||||
mat.loadTextureGL();
|
||||
println(hlog, "texture ID: ", mat.textureid);
|
||||
}
|
||||
colors[mtlname] = nextcol;
|
||||
println(hlog, "color of ", mtlname, " is ", nextcol);
|
||||
};
|
||||
while(!feof(fsm.f)) {
|
||||
string s;
|
||||
scan(fsm, s);
|
||||
if(s == "#") { scanline(fsm); }
|
||||
if(s == "Kd") {
|
||||
ld a, b, c;
|
||||
scan(fsm, a, b, c);
|
||||
part(nextcol, 1) = a * 319.99;
|
||||
part(nextcol, 2) = b * 319.99;
|
||||
part(nextcol, 3) = c * 319.99;
|
||||
}
|
||||
if(s == "newmtl") {
|
||||
emit_material();
|
||||
nextcol = 0xFFFFFFFF;
|
||||
texname = "";
|
||||
mtlname = scanline(fsm);
|
||||
}
|
||||
if(s == "map_Kd") {
|
||||
scan(fsm, texname);
|
||||
}
|
||||
}
|
||||
emit_material();
|
||||
}
|
||||
else if(s == "o" || s == "g") {
|
||||
next_object:
|
||||
object *co = nullptr;
|
||||
bool textured = false;
|
||||
string oname = scanline(fs);
|
||||
println(hlog, "reading object: ", oname);
|
||||
while(true) {
|
||||
if(feof(fs.f)) {
|
||||
if(co) cgi.finishshape();
|
||||
if(co) println(hlog, "vertices = ", co->sh.e-co->sh.s, " tvertices = ", isize(co->tv.tvertices));
|
||||
break;
|
||||
}
|
||||
scan(fs, s);
|
||||
if(s == "#") {
|
||||
scanline(fs);
|
||||
}
|
||||
else if(s == "o" || s == "g") {
|
||||
if(co) cgi.finishshape();
|
||||
if(co) println(hlog, "vertices = ", co->sh.e-co->sh.s, " tvertices = ", isize(co->tv.tvertices));
|
||||
goto next_object;
|
||||
}
|
||||
else if(s == "v") {
|
||||
hyperpoint h = C0;
|
||||
scan(fs, h[0], h[1], h[2]); // assume all
|
||||
h[0] /= 100;
|
||||
h[1] /= 100;
|
||||
h[2] /= 100;
|
||||
vertices.push_back(h);
|
||||
}
|
||||
else if(s == "vt") {
|
||||
ld u, v;
|
||||
scan(fs, u, v);
|
||||
tvertices.push_back(point3(u, 1-v, 0));
|
||||
}
|
||||
else if(s == "vn") {
|
||||
hyperpoint hn = C0;
|
||||
scan(fs, hn[0], hn[1], hn[2]);
|
||||
normals.push_back(hn);
|
||||
}
|
||||
else if(s == "s") {
|
||||
scan(fs, s);
|
||||
}
|
||||
else if(s == "usemtl") {
|
||||
if(co) cgi.finishshape();
|
||||
if(co) println(hlog, "vertices = ", co->sh.e-co->sh.s, " tvertices = ", isize(co->tv.tvertices));
|
||||
string mtlname = scanline(fs);
|
||||
co = nullptr;
|
||||
if(mtlname.find("Layer_Layer0") != string::npos) continue;
|
||||
objects.push_back(make_shared<object>());
|
||||
co = &*objects.back();
|
||||
cgi.bshape(co->sh, PPR::WALL);
|
||||
cgi.last->flags |= POLY_TRIANGLES;
|
||||
cgi.last->texture_offset = 0;
|
||||
if(materials.count(mtlname)) {
|
||||
textured = true;
|
||||
cgi.last->tinf = &co->tv;
|
||||
co->tv.texture_id = materials[mtlname].textureid;
|
||||
println(hlog, "using texture_id : ", co->tv.texture_id);
|
||||
co->color = 0xFFFFFFFF;
|
||||
}
|
||||
else {
|
||||
textured = false;
|
||||
cgi.last->tinf = &co->tv;
|
||||
co->tv.texture_id = floor_textures->renderedTexture;
|
||||
if(colors.count(mtlname))
|
||||
co->color = colors[mtlname];
|
||||
else
|
||||
co->color = 0xFFFFFFFF;
|
||||
}
|
||||
println(hlog, "set textured to ", textured);
|
||||
}
|
||||
else if(s == "f") {
|
||||
struct vertexinfo { int f, t, n; };
|
||||
array<vertexinfo, 3> vis;
|
||||
vector<hyperpoint> hys;
|
||||
vector<hyperpoint> tot;
|
||||
char bar;
|
||||
for(int i=0; i<3; i++) {
|
||||
vis[i].f = vis[i].t = vis[i].n = 1;
|
||||
scan(fs, vis[i].f);
|
||||
if(peek(fs) == '/') {
|
||||
scan(fs, bar);
|
||||
if(peek(fs) != '/') scan(fs, vis[i].t);
|
||||
}
|
||||
if(peek(fs) == '/') {
|
||||
scan(fs, bar);
|
||||
scan(fs, vis[i].n);
|
||||
}
|
||||
|
||||
vis[i].f--; vis[i].t--; vis[i].n--;
|
||||
if(vis[i].f < 0 || vis[i].f >= isize(vertices))
|
||||
throw hr_exception("illegal ID");
|
||||
hys.push_back(vertices[vis[i].f]);
|
||||
tot.push_back(textured ? tvertices[vis[i].t] : point3(0,0,0));
|
||||
}
|
||||
if(!co) continue;
|
||||
|
||||
hyperpoint norm = (hys[1] - hys[0]) ^ (hys[2] - hys[0]);
|
||||
norm /= hypot_d(3, norm);
|
||||
ld y = .5 + (.2 * norm[0] + .16 * norm[1] + .14 * norm[2]);
|
||||
glvertex shade = glhr::makevertex(0, y, 0);
|
||||
glvertex shadecol = glhr::makevertex(y, y, y);
|
||||
|
||||
auto n0 = tf(hys[0]);
|
||||
auto n1 = tf(hys[1]);
|
||||
auto n2 = tf(hys[2]);
|
||||
auto mi = min(n0.first, min(n1.first, n2.first));
|
||||
auto ma = max(n0.first, max(n1.first, n2.first));
|
||||
if(ma - mi > 1) continue;
|
||||
|
||||
int parts = sd(hys);
|
||||
auto tri = [&] (int a, int b) {
|
||||
cgi.hpcpush(tf(hys[0] + (hys[1] - hys[0]) * a / parts + (hys[2] - hys[0]) * b / parts).second);
|
||||
// cgi.hpcpush(tf(tot[0] + (tot[1] - tot[0]) * a / parts + (tot[2] - tot[0]) * b / parts).second);
|
||||
if(textured) {
|
||||
co->tv.tvertices.push_back(glhr::pointtogl(tot[0] + (tot[1] - tot[0]) * a / parts + (tot[2] - tot[0]) * b / parts));
|
||||
co->tv.colors.push_back(shadecol);
|
||||
}
|
||||
else {
|
||||
co->tv.tvertices.push_back(shade);
|
||||
}
|
||||
};
|
||||
|
||||
for(int a=0; a<parts; a++)
|
||||
for(int b=0; b<parts-a; b++) {
|
||||
tri(a, b);
|
||||
tri(a+1, b);
|
||||
tri(a, b+1);
|
||||
if(a+b < parts-1) {
|
||||
tri(a, b+1);
|
||||
tri(a+1, b);
|
||||
tri(a+1, b+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(s == "l") {
|
||||
int a, b;
|
||||
scan(fs, a, b);
|
||||
/* ignore */
|
||||
}
|
||||
else if(s == "") { }
|
||||
else
|
||||
throw hr_exception("unknown command: " + s);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
throw("unknown command: " + s);
|
||||
}
|
||||
|
||||
println(hlog, "reading finished");
|
||||
|
||||
cgi.extra_vertices();
|
||||
}
|
||||
|
||||
void model::render(const shiftmatrix& V) {
|
||||
|
||||
auto& objs = models[cgi_string()];
|
||||
|
||||
if(objs.empty()) load_obj(objs);
|
||||
|
||||
for(auto& obj: objs) {
|
||||
queuepoly(V, obj->sh, obj->color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -181,6 +181,55 @@ function<void(presmode)> roguevizslide_action(char c, const T& t, const U& act)
|
||||
colorpair perturb(colorpair cp);
|
||||
void queuedisk(const shiftmatrix& V, const colorpair& cp, bool legend, const string* info, int i);
|
||||
|
||||
/* 3D models */
|
||||
|
||||
namespace objmodels {
|
||||
|
||||
using tf_result = pair<int, hyperpoint>;
|
||||
|
||||
using transformer = std::function<tf_result(hyperpoint)>;
|
||||
using subdivider = std::function<int(vector<hyperpoint>&)>;
|
||||
|
||||
inline int prec = 10;
|
||||
|
||||
struct object {
|
||||
hpcshape sh;
|
||||
basic_textureinfo tv;
|
||||
color_t color;
|
||||
};
|
||||
|
||||
using model_type = vector<shared_ptr<object>>;
|
||||
|
||||
struct model {
|
||||
|
||||
string path, fname;
|
||||
transformer tf;
|
||||
subdivider sd;
|
||||
|
||||
model(string path = "", string fn = "",
|
||||
transformer tf = [] (hyperpoint h) {
|
||||
return tf_result{0, direct_exp(h)};
|
||||
},
|
||||
subdivider sd = [] (vector<hyperpoint>& hys) {
|
||||
if(euclid) return 1;
|
||||
ld maxlen = prec * max(hypot_d(3, hys[1] - hys[0]), max(hypot_d(3, hys[2] - hys[0]), hypot_d(3, hys[2] - hys[1])));
|
||||
return int(ceil(maxlen));
|
||||
}
|
||||
) : path(path), fname(fn), tf(tf), sd(sd) {}
|
||||
|
||||
map<string, texture::texture_data> materials;
|
||||
map<string, color_t> colors;
|
||||
|
||||
map<string, model_type> models;
|
||||
|
||||
/* private */
|
||||
void load_obj(model_type& objects);
|
||||
|
||||
void render(const shiftmatrix& V);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user