#if 0
vertex_o.xyz = helix_coord[hidx].xyz + radius * gl_Normal;
layout ( binding = 7 ) buffer Helix_Coord { vec4 helix_coord[]; };
smooth noperspective flat
layout ( TYPE_OF_PRIMITIVE ) in;
layout ( triangles ) in;
out Data {
int hidx;
vec3 normal_o;
vec4 color;
};
in Data {
int hidx;
vec3 normal_o;
vec4 color;
} In[];
layout ( triangle_strip, max_vertices = 4 ) out;
out Data_GF
{
vec3 var_normal_e;
vec4 var_vertex_e;
flat vec4 color;
};
#endif
#define MAIN_INCLUDE
#include <vhelper.h>
#include <vstroke.h>
#include <gp/coord.h>
#include <gp/pstring.h>
#include <gp/misc.h>
#include <gp/colors.h>
#include <vutil-texture.h>
#include <vutil-pipeline.h>
#include "shapes.h"
enum Shader_Program
{ SP_Plain, SP_Vtx_Animation, SP_Geo_Shade,
SP_Geo_Animation, SP_ENUM_SIZE };
const char* const shader_program[] =
{ "SP_Plain", "SP_Vtx_Animation", "SP_Geo_Shade",
"SP_Geo_Animation", "SP_ENUM_SIZE" };
struct Buldge_Info
{
float bulge_pos;
float bulge_dist_thresh;
float wire_radius;
bool opt_texture;
};
class World {
public:
World(pVulkan_Helper &fb)
:vh(fb), ff_state(fb.qs), frame_timer(vh.frame_timer), shapes(ff_state),
transform(fb.qs)
{init();}
World() = delete;
void init();
void run();
void render(vk::CommandBuffer& cb);
void cb_keyboard();
void modelview_update();
pVulkan_Helper& vh;
VFixed_Function_State_Manager ff_state;
pFrame_Timer& frame_timer; Shapes shapes;
pVariable_Control variable_control;
pCoor light_location;
float opt_light_intensity;
VBufferV<Uni_Lighting> uni_light;
pCoor helix_location;
float helix_radius; float wire_radius; int seg_per_helix_revolution;
int seg_per_wire_revolution;
float opt_bulge_dist_thresh;
bool coords_stale;
VVertex_Buffer_Set bset_helix, bset_lonely;
VBufferVV<int32_t> buf_wire_surface_indices;
VBufferVV<pCoor> buf_helix_coords;
VBufferV<Buldge_Info> buf_bulge_info;
int opt_shader;
VPipeline pipe_plain; VPipeline pipe_vtx_animation; VPipeline pipe_geo_shade; VPipeline pipe_geo_animation;
enum { MI_Eye, MI_Light, MI_Ball, MI_Ball_V, MI_COUNT } opt_move_item;
bool opt_sim_paused;
double last_evolve_time;
double sim_time;
pCoor eye_location;
pVect eye_direction;
pMatrix modelview;
VTransform transform;
vk::Sampler sampler;
VTexture texture_id_syllabus;
bool opt_texture;
};
void
World::init()
{
vh.init();
vh.opt_record_every_time = true;
vh.display_cb_set([&](){});
vh.cbs_cmd_record.push_back( [&](vk::CommandBuffer& cb){ render(cb); });
opt_sim_paused = false;
sim_time = 0;
last_evolve_time = time_wall_fp();
frame_timer.work_unit_set("Steps / s");
coords_stale = true;
seg_per_helix_revolution = 40;
seg_per_wire_revolution = 20;
opt_bulge_dist_thresh = 2;
variable_control.insert(seg_per_helix_revolution,"Helix Seg Per Rev");
variable_control.insert(seg_per_wire_revolution,"Wire Seg Per Rev");
variable_control.insert(opt_bulge_dist_thresh,"Buldge Distance");
eye_location = pCoor(2.6,5.7,15);
eye_direction = pVect(0,0,-1);
opt_light_intensity = 1.5;
light_location = pCoor(7,4.0,-0.3);
uni_light.init(vh.qs,vk::BufferUsageFlagBits::eUniformBuffer);
helix_location = pCoor(0,0,-5);
helix_radius = 5;
wire_radius = 0.5;
variable_control.insert(opt_light_intensity,"Light Intensity");
opt_move_item = MI_Eye;
texture_id_syllabus.init(vh.qs, P_Image_Read("gpup.png",255) );
opt_texture = true;
sampler = vh.qs.dev.createSampler
( { {},
vk::Filter::eLinear, vk::Filter::eLinear,
vk::SamplerMipmapMode::eLinear,
vk::SamplerAddressMode::eRepeat,
vk::SamplerAddressMode::eRepeat,
vk::SamplerAddressMode::eRepeat,
0.0f,
true, 16.0f,
false,
vk::CompareOp::eNever,
0.0f, VK_LOD_CLAMP_NONE, vk::BorderColor::eFloatOpaqueBlack } );
buf_bulge_info.init
(vh.dev_phys, vh.dev, vk::BufferUsageFlagBits::eUniformBuffer );
buf_helix_coords.init
(vh.dev_phys, vh.dev, vk::BufferUsageFlagBits::eStorageBuffer );
buf_wire_surface_indices.init
(vh.dev_phys, vh.dev, vk::BufferUsageFlagBits::eIndexBuffer );
pipe_plain
.init( vh.qs ).ds_use_texture().ds_set_material().ds_use( uni_light )
.ds_uniform_use( "BIND_BULGE_INFO", buf_bulge_info )
.shader_inputs_info_set<pCoor,pNorm,pTCoor>()
.shader_code_set
("demo-10-shdr-ngeo.cc", "vs_main_basic(); ", "fs_main_phong();" )
.topology_set( vk::PrimitiveTopology::eTriangleStrip )
.create();
pipe_vtx_animation
.init( vh.qs ).ds_use_texture().ds_set_material().ds_use( uni_light )
.ds_uniform_use( "BIND_BULGE_INFO", buf_bulge_info )
.ds_storage_follow( "BIND_HELIX_COORDS", buf_helix_coords )
.shader_inputs_info_set<int,pNorm,pTCoor>()
.shader_code_set
("demo-10-shdr-ngeo.cc", "vs_main_helix();", "fs_main_phong();" )
.topology_set( vk::PrimitiveTopology::eTriangleStrip )
.create();
pipe_geo_shade
.init( vh.qs ).ds_use_texture().ds_set_material().ds_use( uni_light )
.ds_uniform_use( "BIND_BULGE_INFO", buf_bulge_info )
.ds_storage_follow( "BIND_HELIX_COORDS", buf_helix_coords )
.shader_inputs_info_set<int,pNorm,pTCoor>()
.shader_code_set
("demo-10-shdr-simple.cc", "vs_main_helix();", "gs_main_helix();", "fs_main_phong();" )
.topology_set( vk::PrimitiveTopology::eTriangleStrip )
.create();
pipe_geo_animation
.init( vh.qs ).ds_use_texture().ds_set_material().ds_use( uni_light )
.ds_uniform_use( "BIND_BULGE_INFO", buf_bulge_info )
.ds_storage_follow( "BIND_HELIX_COORDS", buf_helix_coords )
.shader_inputs_info_set<int,pNorm,pTCoor>()
.shader_code_set
("demo-10-shdr-geo.cc", "vs_main_helix();", "gs_main_helix();", "fs_main_phong();" )
.topology_set( vk::PrimitiveTopology::eTriangleStrip )
.create();
opt_shader = SP_Geo_Animation;
modelview_update();
}
void
World::modelview_update()
{
pMatrix_Translate center_eye(-eye_location);
pMatrix_Rotation rotate_eye(eye_direction,pVect(0,0,-1));
modelview = rotate_eye * center_eye;
}
void
World::run()
{
vh.message_loop_spin();
bset_helix.destroy();
bset_lonely.destroy();
buf_wire_surface_indices.destroy();
buf_helix_coords.destroy();
buf_bulge_info.destroy();
pipe_plain.destroy();
pipe_vtx_animation.destroy();
pipe_geo_shade.destroy();
pipe_geo_animation.destroy();
uni_light.destroy();
texture_id_syllabus.destroy();
vh.dev.destroySampler(sampler);
shapes.destroy();
transform.destroy();
vh.finish();
}
void
World::render(vk::CommandBuffer& cb)
{
cb_keyboard();
vh.clearValues[0].color =
vk::ClearColorValue( array<float, 4>( { { 0, 0, 0, 0 } } ) );
vh.fbprintf("%s\n",frame_timer.frame_rate_text_get());
vh.fbprintf
("Eye location: [%5.1f, %5.1f, %5.1f] "
"Eye direction: [%+.2f, %+.2f, %+.2f]\n",
eye_location.x, eye_location.y, eye_location.z,
eye_direction.x, eye_direction.y, eye_direction.z);
pVariable_Control_Elt* const cvar = variable_control.current;
vh.fbprintf("VAR %s = %.5f (TAB or '`' to change, +/- to adjust)\n",
cvar->name,cvar->get_val());
vh.fbprintf
("Light location: [%5.1f, %5.1f, %5.1f] "
"Helix Location[%5.1f, %5.1f, %5.1f]\n",
light_location.x, light_location.y, light_location.z,
helix_location.x, helix_location.y, helix_location.z
);
vh.fbprintf("Active Shader Program: %s (s TO CHANGE)\n",
shader_program[opt_shader]);
const int win_width = vh.get_width();
const int win_height = vh.get_height();
const float aspect = float(win_width) / win_height;
const float n_dist = 0.01;
const float xr = .8 * n_dist;
transform.eye_from_global_set( modelview );
transform.clip_from_eye_set
( pMatrix_Frustum( -xr, xr, -xr/aspect, xr/aspect, n_dist, 5000 ) );
auto& light0 = uni_light->cgl_LightSource[0];
uni_light->cgl_LightModel.ambient = color_white * 0.5;
light0.diffuse = opt_light_intensity * color_white;
light0.position = transform.eye_from_global * light_location;
light0.constantAttenuation = 0;
light0.linearAttenuation = 1;
light0.quadraticAttenuation = 0.05;
light0.ambient = color_black;
uni_light.to_dev();
pColor color_tri(0x7815b6);
if ( !bset_lonely )
{
bset_lonely.reset( pipe_plain );
pCoor p1( 9, 6, -7 );
pCoor p2( 0, 5, -3 );
pCoor p3( 9.5, -5, -1.2 );
pNorm triangle_normal = cross(p3,p2,p1);
bset_lonely << triangle_normal << pTCoor(0.90,1.0) << p1
<< triangle_normal << pTCoor(0.00,0.9) << p2
<< triangle_normal << pTCoor(0.95,0.0) << p3;
bset_lonely.to_dev();
}
pipe_plain.ds_set( color_tri, color_red );
pipe_plain.ds_use(sampler, texture_id_syllabus );
pipe_plain.ds_set( transform ).record_draw( cb, bset_lonely );
if ( coords_stale || !bset_helix )
{
coords_stale = false;
bset_helix.reset(vh.qs)
.setup_pos().setup_normal().setup_tcoor().setup_int1();
buf_wire_surface_indices.clear();
buf_helix_coords.clear();
const int revolutions_per_helix = 6;
const int segments_per_helix =
revolutions_per_helix * seg_per_helix_revolution;
const double delta_eta = 2 * M_PI / seg_per_helix_revolution;
const double delta_y = 4 * wire_radius / seg_per_helix_revolution;
const double delta_theta = 2 * M_PI / seg_per_wire_revolution;
for ( int i = 0; i < segments_per_helix; i++ )
{
const bool last_i_iteration = i + 1 == segments_per_helix;
const double eta = i * delta_eta;
const float cos_eta = cosf(eta);
const float sin_eta = sinf(eta);
pCoor p0( helix_radius * cos_eta,
i * delta_y,
helix_radius * sin_eta);
buf_helix_coords << p0;
pVect ax( -wire_radius * cos_eta, 0, -wire_radius * sin_eta);
pNorm ay( delta_eta * helix_radius * -sin_eta,
delta_y,
delta_eta * helix_radius * cos_eta );
pVect az = cross(ax,ay);
for ( int j = 0; j < seg_per_wire_revolution; j++ )
{
const int idx = bset_helix.size();
const float theta = j * delta_theta;
pVect norm0 = cosf(theta) * ax + sinf(theta) * az;
pCoor s0 = p0 + norm0;
bset_helix << s0;
bset_helix << norm0.normal() << i << pTCoor(theta/(2*M_PI),2*eta);
if ( last_i_iteration ) continue;
buf_wire_surface_indices << idx << idx + seg_per_wire_revolution;
}
}
bset_helix.to_dev();
buf_wire_surface_indices.to_dev();
buf_helix_coords.to_dev();
}
VPipeline& pipe =
opt_shader == SP_Plain ? pipe_plain :
opt_shader == SP_Vtx_Animation ? pipe_vtx_animation :
opt_shader == SP_Geo_Shade ? pipe_geo_shade :
opt_shader == SP_Geo_Animation ? pipe_geo_animation : pipe_geo_animation;
if ( !opt_sim_paused )
{
const double now = time_wall_fp();
sim_time += now - last_evolve_time;
last_evolve_time = now;
}
const float bulge_pos = fmodf( sim_time * 5.0f, buf_helix_coords.size());
buf_bulge_info->bulge_pos = bulge_pos;
buf_bulge_info->bulge_dist_thresh = opt_bulge_dist_thresh;
buf_bulge_info->wire_radius = wire_radius;
buf_bulge_info->opt_texture = opt_texture;
buf_bulge_info.to_dev();
pMatrix tform =
pMatrix_Translate(helix_location) * pMatrix_Rotation(pVect(0,1,0),M_PI/3);
pipe.ds_use(sampler, texture_id_syllabus );
pipe.ds_set( transform * tform );
pipe.ds_set( color_lsu_spirit_gold, color_red );
pipe.record_draw_indexed( cb, bset_helix, buf_wire_surface_indices );
shapes.record_tetrahedron(cb,transform,light_location,0.5);
}
void
World::cb_keyboard()
{
const int key = vh.keyboard_key_get();
if ( !key ) return;
pVect adjustment(0,0,0);
pVect user_rot_axis(0,0,0);
const bool kb_mod_s = vh.keyboard_shift;
const bool kb_mod_c = vh.keyboard_control;
const float move_amt = kb_mod_s ? 2.0 : kb_mod_c ? 0.08 : 0.4;
switch ( key ) {
case FB_KEY_LEFT: adjustment.x = -move_amt; break;
case FB_KEY_RIGHT: adjustment.x = move_amt; break;
case FB_KEY_PAGE_UP: adjustment.y = move_amt; break;
case FB_KEY_PAGE_DOWN: adjustment.y = -move_amt; break;
case FB_KEY_DOWN: adjustment.z = move_amt; break;
case FB_KEY_UP: adjustment.z = -move_amt; break;
case FB_KEY_DELETE: user_rot_axis.y = 1; break;
case FB_KEY_INSERT: user_rot_axis.y = -1; break;
case FB_KEY_HOME: user_rot_axis.x = 1; break;
case FB_KEY_END: user_rot_axis.x = -1; break;
case 's':
opt_shader++; if ( opt_shader == SP_ENUM_SIZE ) opt_shader = 0;
break;
case 'S':
if ( opt_shader == 0 ) opt_shader = SP_ENUM_SIZE;
opt_shader--;
break;
case 'b': case 'B': opt_move_item = MI_Ball; break;
case 'e': case 'E': opt_move_item = MI_Eye; break;
case 'l': case 'L': opt_move_item = MI_Light; break;
case 'p': case 'P':
if ( opt_sim_paused ) last_evolve_time = time_wall_fp();
opt_sim_paused = !opt_sim_paused;
break;
case 't': case 'T': opt_texture = !opt_texture; coords_stale=true; break;
case ' ': opt_sim_paused = true; sim_time += 0.1; break;
case FB_KEY_TAB:
if ( !kb_mod_s ) { variable_control.switch_var_right(); break; }
case 96: variable_control.switch_var_left(); break;
case '-':case '_': variable_control.adjust_lower(); coords_stale=true; break;
case '+':case '=': variable_control.adjust_higher(); coords_stale=true; break;
default: printf("Unknown key, %d\n",key); break;
}
if ( user_rot_axis.x || user_rot_axis.y )
{
pMatrix_Rotation rotall(eye_direction,pVect(0,0,-1));
user_rot_axis *= invert(rotall);
eye_direction *= pMatrix_Rotation(user_rot_axis, M_PI * 0.03);
modelview_update();
}
if ( adjustment.x || adjustment.y || adjustment.z )
{
const double angle =
fabs(eye_direction.y) > 0.99
? 0 : atan2(eye_direction.x,-eye_direction.z);
pMatrix_Rotation rotall(pVect(0,1,0),-angle);
adjustment *= rotall;
switch ( opt_move_item ){
case MI_Light: light_location += adjustment; break;
case MI_Eye: eye_location += adjustment; break;
case MI_Ball: helix_location += adjustment; break;
default: break;
}
modelview_update();
}
}
int
main(int argv, char **argc)
{
pVulkan_Helper pvulkan_helper(argv,argc);
World world(pvulkan_helper);
world.run();
return 0;
}