Pixel-Composer/scripts/d3d_surface_extrude/d3d_surface_extrude.gml

308 lines
No EOL
12 KiB
Text

function __3dSurfaceExtrude(surface = noone, height = noone, smooth = false) : __3dObject() constructor {
VF = global.VF_POS_NORM_TEX_COL;
render_type = pr_trianglelist;
self.surface = surface;
self.height = height;
self.smooth = smooth;
surface_w = 1;
surface_h = 1;
normal_draw_size = 0.05;
static getHeight = function(h, gw, gh, i, j) {
gml_pragma("forceinline");
var _i = round(i * gw);
var _j = round(j * gh);
_i = clamp(_i, 0, array_length(h) - 1);
_j = clamp(_j, 0, array_length(h[_i]) - 1);
return h[_i][_j];
}
static initModel = function() {
if(!is_surface(surface)) return;
var _surface = surface;
var _height = height;
var ww = surface_get_width(_surface);
var hh = surface_get_height(_surface);
surface_w = ww;
surface_h = hh;
var tw = 1 / ww;
var th = 1 / hh;
var sw = -ww / 2 * tw;
var sh = hh / 2 * th;
var useH = is_surface(_height);
#region ---- data prepare ----
if(smooth) {
var ts = surface_create(ww, hh);
surface_set_shader(ts, sh_3d_extrude_filler);
shader_set_f("dimension", ww, hh);
draw_surface(_surface, 0, 0);
surface_reset_shader();
_surface = ts;
if(useH) {
var ds = surface_create(ww, hh);
surface_set_shader(ds, sh_3d_extrude_filler_depth);
shader_set_f("dimension", ww, hh);
draw_surface(_height, 0, 0);
surface_reset_shader();
_height = ds;
}
}
if(useH) {
var hgw = surface_get_width(_height);
var hgh = surface_get_height(_height);
var hgtW = hgw / ww;
var hgtH = hgh / hh;
var height_buffer = buffer_create(hgw * hgh * 4, buffer_fixed, 2);
buffer_get_surface(height_buffer, _height, 0);
buffer_seek(height_buffer, buffer_seek_start, 0);
var hei = array_create(hgw, hgh);
for( var j = 0; j < hgh; j++ )
for( var i = 0; i < hgw; i++ ) {
var cc = buffer_read(height_buffer, buffer_u32);
var _b = colorBrightness(cc & ~0b11111111);
hei[i][j] = _b;
}
buffer_delete(height_buffer);
}
var surface_buffer = buffer_create(ww * hh * 4, buffer_fixed, 2);
buffer_get_surface(surface_buffer, _surface, 0);
buffer_seek(surface_buffer, buffer_seek_start, 0);
var v = ds_list_create();
var ap = array_create(ww, hh);
for( var j = 0; j < hh; j++ )
for( var i = 0; i < ww; i++ ) {
var cc = buffer_read(surface_buffer, buffer_u32);
var _a = (cc & (0b11111111 << 24)) >> 24;
ap[i][j] = _a;
}
buffer_delete(surface_buffer);
#endregion
for( var i = 0; i < ww; i++ )
for( var j = 0; j < hh; j++ ) {
if(!smooth && ap[i][j] == 0) continue;
var j0 = sh - j * th;
var j1 = j0 - th;
var i0 = sw + i * tw;
var i1 = i0 + tw;
var tx0 = tw * i, tx1 = tx0 + tw;
var ty0 = th * j, ty1 = ty0 + th;
var dep = (useH? getHeight(hei, hgtW, hgtH, i, j) : 1) * 0.5;
if(smooth) { #region
var d0, d1, d2, d3;
var d00, d10, d01, d11;
var a, a0, a1, a2, a3;
// d00 | a0 | d10
// a1 | a | a2
// d01 | a3 | d11
if(useH) {
d00 = (i > 0 && j > 0)? getHeight(hei, hgtW, hgtH, i - 1, j - 1) * 0.5 : 0;
d10 = (i < ww - 1 && j > 0)? getHeight(hei, hgtW, hgtH, i + 1, j - 1) * 0.5 : 0;
d01 = (i > 0 && j < hh - 1)? getHeight(hei, hgtW, hgtH, i - 1, j + 1) * 0.5 : 0;
d11 = (i < ww - 1 && j < hh - 1)? getHeight(hei, hgtW, hgtH, i + 1, j + 1) * 0.5 : 0;
d0 = (j > 0)? getHeight(hei, hgtW, hgtH, i, j - 1) * 0.5 : 0;
d1 = (i > 0)? getHeight(hei, hgtW, hgtH, i - 1, j) * 0.5 : 0;
d2 = (i < ww - 1)? getHeight(hei, hgtW, hgtH, i + 1, j) * 0.5 : 0;
d3 = (j < hh - 1)? getHeight(hei, hgtW, hgtH, i, j + 1) * 0.5 : 0;
} else {
d00 = (i > 0 && j > 0)? bool(ap[i - 1][j - 1]) * 0.5 : 0;
d10 = (i < ww - 1 && j > 0)? bool(ap[i + 1][j - 1]) * 0.5 : 0;
d01 = (i > 0 && j < hh - 1)? bool(ap[i - 1][j + 1]) * 0.5 : 0;
d11 = (i < ww - 1 && j < hh - 1)? bool(ap[i + 1][j + 1]) * 0.5 : 0;
d0 = (j > 0)? bool(ap[i][j - 1]) * 0.5 : 0;
d1 = (i > 0)? bool(ap[i - 1][j]) * 0.5 : 0;
d2 = (i < ww - 1)? bool(ap[i + 1][j]) * 0.5 : 0;
d3 = (j < hh - 1)? bool(ap[i][j + 1]) * 0.5 : 0;
}
a = ap[i][j];
a0 = (j > 0)? ap[i][j - 1] : 0;
a1 = (i > 0)? ap[i - 1][j] : 0;
a2 = (i < ww - 1)? ap[i + 1][j] : 0;
a3 = (j < hh - 1)? ap[i][j + 1] : 0;
if(a1 && a0) d00 = (d1 + d0) / 2;
if(a0 && a2) d10 = (d0 + d2) / 2;
if(a2 && a3) d11 = (d2 + d3) / 2;
if(a3 && a1) d01 = (d3 + d1) / 2;
if(a) {
ds_list_add(v, new __vertex(j0, i1, -d10).setNormal(0, 0, -1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(j1, i1, -d11).setNormal(0, 0, -1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j0, i0, -d00).setNormal(0, 0, -1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(j1, i1, -d11).setNormal(0, 0, -1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j1, i0, -d01).setNormal(0, 0, -1).setUV(tx0, ty1));
ds_list_add(v, new __vertex(j0, i0, -d00).setNormal(0, 0, -1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(j0, i1, d10).setNormal(0, 0, 1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(j0, i0, d00).setNormal(0, 0, 1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(j1, i1, d11).setNormal(0, 0, 1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j1, i1, d11).setNormal(0, 0, 1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j0, i0, d00).setNormal(0, 0, 1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(j1, i0, d01).setNormal(0, 0, 1).setUV(tx0, ty1));
} else if(!a0 && !a1 && a2 && a3) {
//var _tx0 = tw * (i + 1), _tx1 = _tx0 + tw;
//var _ty0 = th * (j + 0), _ty1 = _ty0 + th;
d00 *= d0 * d1;
d10 *= d1 * d2;
d01 *= d1 * d3;
ds_list_add(v, new __vertex(j0, i1, -d10).setNormal(0, 0, -1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(j1, i1, -d11).setNormal(0, 0, -1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j1, i0, -d01).setNormal(0, 0, -1).setUV(tx0, ty1));
ds_list_add(v, new __vertex(j0, i1, d10).setNormal(0, 0, 1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(j1, i1, d11).setNormal(0, 0, 1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j1, i0, d01).setNormal(0, 0, 1).setUV(tx0, ty1));
} else if(!a0 && a1 && !a2 && a3) {
//var _tx0 = tw * (i - 1), _tx1 = _tx0 + tw;
//var _ty0 = th * (j + 0), _ty1 = _ty0 + th;
d00 *= d0 * d1;
d10 *= d1 * d2;
d11 *= d2 * d3;
ds_list_add(v, new __vertex(j1, i1, -d11).setNormal(0, 0, -1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j1, i0, -d01).setNormal(0, 0, -1).setUV(tx0, ty1));
ds_list_add(v, new __vertex(j0, i0, -d00).setNormal(0, 0, -1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(j1, i1, d11).setNormal(0, 0, 1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j1, i0, d01).setNormal(0, 0, 1).setUV(tx0, ty1));
ds_list_add(v, new __vertex(j0, i0, d00).setNormal(0, 0, 1).setUV(tx0, ty0));
} else if(a0 && a1 && !a2 && !a3) {
//var _tx0 = tw * (i - 1), _tx1 = _tx0 + tw;
//var _ty0 = th * (j + 0), _ty1 = _ty0 + th;
d10 *= d1 * d2;
d01 *= d1 * d3;
d11 *= d2 * d3;
ds_list_add(v, new __vertex(j0, i0, -d00).setNormal(0, 0, -1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(j0, i1, -d10).setNormal(0, 0, -1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(j1, i0, -d01).setNormal(0, 0, -1).setUV(tx0, ty1));
ds_list_add(v, new __vertex(j0, i0, d00).setNormal(0, 0, 1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(j0, i1, d10).setNormal(0, 0, 1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(j1, i0, d01).setNormal(0, 0, 1).setUV(tx0, ty1));
} else if(a0 && !a1 && a2 && !a3) {
//var _tx0 = tw * (i + 1), _tx1 = _tx0 + tw;
//var _ty0 = th * (j + 0), _ty1 = _ty0 + th;
d00 *= d0 * d1;
d01 *= d1 * d3;
d11 *= d2 * d3;
ds_list_add(v, new __vertex(j0, i1, -d10).setNormal(0, 0, -1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(j1, i1, -d11).setNormal(0, 0, -1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j0, i0, -d00).setNormal(0, 0, -1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(j0, i1, d10).setNormal(0, 0, 1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(j1, i1, d11).setNormal(0, 0, 1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(j0, i0, d00).setNormal(0, 0, 1).setUV(tx0, ty0));
}
#endregion
} else { #region
ds_list_add(v, new __vertex(i1, j0, -dep).setNormal(0, 0, -1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(i0, j0, -dep).setNormal(0, 0, -1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i1, j1, -dep).setNormal(0, 0, -1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i1, j1, -dep).setNormal(0, 0, -1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i0, j0, -dep).setNormal(0, 0, -1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i0, j1, -dep).setNormal(0, 0, -1).setUV(tx0, ty1));
ds_list_add(v, new __vertex(i1, j0, dep).setNormal(0, 0, 1).setUV(tx1, ty0));
ds_list_add(v, new __vertex(i1, j1, dep).setNormal(0, 0, 1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i0, j0, dep).setNormal(0, 0, 1).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i1, j1, dep).setNormal(0, 0, 1).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i0, j1, dep).setNormal(0, 0, 1).setUV(tx0, ty1));
ds_list_add(v, new __vertex(i0, j0, dep).setNormal(0, 0, 1).setUV(tx0, ty0));
if((useH && dep * 2 > getHeight(hei, hgtW, hgtH, i, j - 1)) || (j == 0 || ap[i][j - 1] == 0)) { //y side
ds_list_add(v, new __vertex(i0, j0, dep).setNormal(0, 1, 0).setUV(tx1, ty0));
ds_list_add(v, new __vertex(i0, j0, -dep).setNormal(0, 1, 0).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i1, j0, dep).setNormal(0, 1, 0).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i0, j0, -dep).setNormal(0, 1, 0).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i1, j0, -dep).setNormal(0, 1, 0).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i1, j0, dep).setNormal(0, 1, 0).setUV(tx0, ty1));
}
if((useH && dep * 2 > getHeight(hei, hgtW, hgtH, i, j + 1)) || (j == hh - 1 || ap[i][j + 1] == 0)) { //y side
ds_list_add(v, new __vertex(i0, j1, dep).setNormal(0, -1, 0).setUV(tx1, ty0));
ds_list_add(v, new __vertex(i1, j1, dep).setNormal(0, -1, 0).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i0, j1, -dep).setNormal(0, -1, 0).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i0, j1, -dep).setNormal(0, -1, 0).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i1, j1, dep).setNormal(0, -1, 0).setUV(tx0, ty1));
ds_list_add(v, new __vertex(i1, j1, -dep).setNormal(0, -1, 0).setUV(tx0, ty0));
}
if((useH && dep * 2 > getHeight(hei, hgtW, hgtH, i - 1, j)) || (i == 0 || ap[i - 1][j] == 0)) { //x side
ds_list_add(v, new __vertex(i0, j0, dep).setNormal(-1, 0, 0).setUV(tx1, ty0));
ds_list_add(v, new __vertex(i0, j1, dep).setNormal(-1, 0, 0).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i0, j0, -dep).setNormal(-1, 0, 0).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i0, j0, -dep).setNormal(-1, 0, 0).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i0, j1, dep).setNormal(-1, 0, 0).setUV(tx0, ty1));
ds_list_add(v, new __vertex(i0, j1, -dep).setNormal(-1, 0, 0).setUV(tx0, ty0));
}
if((useH && dep * 2 > getHeight(hei, hgtW, hgtH, i + 1, j)) || (i == ww - 1 || ap[i + 1][j] == 0)) { //x side
ds_list_add(v, new __vertex(i1, j0, dep).setNormal(1, 0, 0).setUV(tx1, ty0));
ds_list_add(v, new __vertex(i1, j0, -dep).setNormal(1, 0, 0).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i1, j1, dep).setNormal(1, 0, 0).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i1, j0, -dep).setNormal(1, 0, 0).setUV(tx1, ty1));
ds_list_add(v, new __vertex(i1, j1, -dep).setNormal(1, 0, 0).setUV(tx0, ty0));
ds_list_add(v, new __vertex(i1, j1, dep).setNormal(1, 0, 0).setUV(tx0, ty1));
}
#endregion
}
}
if(smooth) {
surface_free(_surface);
if(useH) surface_free(_height);
}
vertex = [ ds_list_to_array(v) ];
ds_list_destroy(v);
VB = build();
} initModel();
static onParameterUpdate = initModel;
}