/ /code /code.swankyquant /code.swankyquant.algorithm /code.swankyquant.color_distance /code.swankyquant.color_distance_weight /code.swankyquant.swanky_quant /code.swankyquant.swanky_quant_remap /draw/entities /entities.systems /entities.systems.bang /entities.systems.donut /entities.systems.horde /entities.systems.invader /entities.systems.item /entities.systems.level /entities.systems.menu /entities.systems.missile /entities.systems.npc /entities.systems.player /entities.systems.score /entities.systems.space /entities.systems.stars /entities.systems.tile /entities.systems.yarn/entities.tiles /entities.tiles.npc /entities.tiles.sprite /entities.tiles.start /graphics /hardware /levels/lua /lua.glslang /lua.glslang.lint_gles2 /lua.glslang.parse_chunks /lua.glslang.pp /lua.glslang.replace_include /lua.glslang.yank_shader_versions/lua.wetgenes /lua.wetgenes.bullet /lua.wetgenes.bullet.body /lua.wetgenes.bullet.body.cgroup /lua.wetgenes.bullet.body.change_shape /lua.wetgenes.bullet.body.cmask /lua.wetgenes.bullet.body.force /lua.wetgenes.bullet.body.gravity /lua.wetgenes.bullet.body.impulse /lua.wetgenes.bullet.body.overlaps /lua.wetgenes.bullet.body.support/lua.wetgenes.bullet.world /lua.wetgenes.bullet.world.body /lua.wetgenes.bullet.world.body.active /lua.wetgenes.bullet.world.body.angular_factor /lua.wetgenes.bullet.world.body.angular_velocity /lua.wetgenes.bullet.world.body.ccd /lua.wetgenes.bullet.world.body.custom_material_callback /lua.wetgenes.bullet.world.body.damping /lua.wetgenes.bullet.world.body.destroy /lua.wetgenes.bullet.world.body.factor /lua.wetgenes.bullet.world.body.friction /lua.wetgenes.bullet.world.body.restitution /lua.wetgenes.bullet.world.body.transform /lua.wetgenes.bullet.world.body.velocity /lua.wetgenes.bullet.world.contacts /lua.wetgenes.bullet.world.destroy /lua.wetgenes.bullet.world.get /lua.wetgenes.bullet.world.gravity/lua.wetgenes.bullet.world.mesh /lua.wetgenes.bullet.world.mesh.destroy /lua.wetgenes.bullet.world.ray_test /lua.wetgenes.bullet.world.set/lua.wetgenes.bullet.world.shape /lua.wetgenes.bullet.world.shape.destroy /lua.wetgenes.bullet.world.shape.margin /lua.wetgenes.bullet.world.status /lua.wetgenes.bullet.world.step/lua.wetgenes.chipmunk /lua.wetgenes.chipmunk.arbiter /lua.wetgenes.chipmunk.arbiter.ignore /lua.wetgenes.chipmunk.arbiter.points /lua.wetgenes.chipmunk.arbiter.surface_velocity/lua.wetgenes.chipmunk.body /lua.wetgenes.chipmunk.body.angle /lua.wetgenes.chipmunk.body.angular_velocity /lua.wetgenes.chipmunk.body.apply_force /lua.wetgenes.chipmunk.body.apply_impulse /lua.wetgenes.chipmunk.body.center_of_gravity /lua.wetgenes.chipmunk.body.force /lua.wetgenes.chipmunk.body.mass /lua.wetgenes.chipmunk.body.moment /lua.wetgenes.chipmunk.body.position /lua.wetgenes.chipmunk.body.position_func /lua.wetgenes.chipmunk.body.shape /lua.wetgenes.chipmunk.body.torque /lua.wetgenes.chipmunk.body.type /lua.wetgenes.chipmunk.body.velocity /lua.wetgenes.chipmunk.body.velocity_func/lua.wetgenes.chipmunk.constraint /lua.wetgenes.chipmunk.constraint.collide_bodies /lua.wetgenes.chipmunk.constraint.error_bias /lua.wetgenes.chipmunk.constraint.impulse /lua.wetgenes.chipmunk.constraint.max_bias /lua.wetgenes.chipmunk.constraint.max_force/lua.wetgenes.chipmunk.shape /lua.wetgenes.chipmunk.shape.bounding_box /lua.wetgenes.chipmunk.shape.collision_type /lua.wetgenes.chipmunk.shape.elasticity /lua.wetgenes.chipmunk.shape.filter /lua.wetgenes.chipmunk.shape.friction /lua.wetgenes.chipmunk.shape.query_point /lua.wetgenes.chipmunk.shape.query_segment /lua.wetgenes.chipmunk.shape.radius /lua.wetgenes.chipmunk.shape.sensor /lua.wetgenes.chipmunk.shape.surface_velocity/lua.wetgenes.chipmunk.space /lua.wetgenes.chipmunk.space.add /lua.wetgenes.chipmunk.space.add_handler /lua.wetgenes.chipmunk.space.body /lua.wetgenes.chipmunk.space.collision_bias /lua.wetgenes.chipmunk.space.collision_persistence /lua.wetgenes.chipmunk.space.collision_slop /lua.wetgenes.chipmunk.space.constraint /lua.wetgenes.chipmunk.space.contains /lua.wetgenes.chipmunk.space.current_time_step /lua.wetgenes.chipmunk.space.damping /lua.wetgenes.chipmunk.space.gravity /lua.wetgenes.chipmunk.space.idle_speed_threshold /lua.wetgenes.chipmunk.space.iterations /lua.wetgenes.chipmunk.space.locked /lua.wetgenes.chipmunk.space.query_bounding_box /lua.wetgenes.chipmunk.space.query_point /lua.wetgenes.chipmunk.space.query_point_nearest /lua.wetgenes.chipmunk.space.query_segment /lua.wetgenes.chipmunk.space.query_segment_first /lua.wetgenes.chipmunk.space.query_shape /lua.wetgenes.chipmunk.space.reindex /lua.wetgenes.chipmunk.space.remove /lua.wetgenes.chipmunk.space.sleep_time_threshold /lua.wetgenes.chipmunk.space.step /lua.wetgenes.chipmunk.space.type/lua.wetgenes.csv /lua.wetgenes.csv.build /lua.wetgenes.csv.doesc /lua.wetgenes.csv.doquote /lua.wetgenes.csv.map /lua.wetgenes.csv.parse /lua.wetgenes.csv.unesc /lua.wetgenes.csv.unquote /lua.wetgenes.deepcompare /lua.wetgenes.deepcopy /lua.wetgenes.export/lua.wetgenes.gamecake /lua.wetgenes.gamecake.framebuffers /lua.wetgenes.gamecake.framebuffers.create /lua.wetgenes.gamecake.framebuffers.dirty/lua.wetgenes.gamecake.framebuffers.fbo /lua.wetgenes.gamecake.framebuffers.fbo.bind_depth /lua.wetgenes.gamecake.framebuffers.fbo.bind_depth_snapshot /lua.wetgenes.gamecake.framebuffers.fbo.bind_frame /lua.wetgenes.gamecake.framebuffers.fbo.bind_texture /lua.wetgenes.gamecake.framebuffers.fbo.bind_texture_snapshot /lua.wetgenes.gamecake.framebuffers.fbo.check /lua.wetgenes.gamecake.framebuffers.fbo.clean /lua.wetgenes.gamecake.framebuffers.fbo.download /lua.wetgenes.gamecake.framebuffers.fbo.free_depth /lua.wetgenes.gamecake.framebuffers.fbo.free_frame /lua.wetgenes.gamecake.framebuffers.fbo.free_snapshot /lua.wetgenes.gamecake.framebuffers.fbo.free_texture /lua.wetgenes.gamecake.framebuffers.fbo.mipmap /lua.wetgenes.gamecake.framebuffers.fbo.mipmap_depth /lua.wetgenes.gamecake.framebuffers.fbo.mipmap_texture /lua.wetgenes.gamecake.framebuffers.fbo.pingpong /lua.wetgenes.gamecake.framebuffers.fbo.render_start /lua.wetgenes.gamecake.framebuffers.fbo.render_stop /lua.wetgenes.gamecake.framebuffers.fbo.resize /lua.wetgenes.gamecake.framebuffers.fbo.snapshot /lua.wetgenes.gamecake.framebuffers.start /lua.wetgenes.gamecake.framebuffers.stop/lua.wetgenes.gamecake.fun /lua.wetgenes.gamecake.fun.chatdown /lua.wetgenes.gamecake.fun.chatdown.chat /lua.wetgenes.gamecake.fun.chatdown.chat.get_tag /lua.wetgenes.gamecake.fun.chatdown.chat.replace_tags /lua.wetgenes.gamecake.fun.chatdown.chat.set_tag /lua.wetgenes.gamecake.fun.chatdown.chat.set_tags /lua.wetgenes.gamecake.fun.chatdown.chat.set_topic/lua.wetgenes.gamecake.fun.chatdown.chats /lua.wetgenes.gamecake.fun.chatdown.chats.changes /lua.wetgenes.gamecake.fun.chatdown.chats.get_subject /lua.wetgenes.gamecake.fun.chatdown.chats.get_tag /lua.wetgenes.gamecake.fun.chatdown.chats.replace_tags /lua.wetgenes.gamecake.fun.chatdown.chats.set_subject /lua.wetgenes.gamecake.fun.chatdown.chats.set_tag /lua.wetgenes.gamecake.fun.chatdown.dotnames /lua.wetgenes.gamecake.fun.chatdown.parse /lua.wetgenes.gamecake.fun.chatdown.setup /lua.wetgenes.gamecake.fun.chatdown.setup_chat /lua.wetgenes.gamecake.fun.chatdown.text/lua.wetgenes.gamecake.fun.yarn /lua.wetgenes.gamecake.fun.yarn.cells/lua.wetgenes.gamecake.fun.yarn.items /lua.wetgenes.gamecake.fun.yarn.items.cells /lua.wetgenes.gamecake.fun.yarn.items.create /lua.wetgenes.gamecake.fun.yarn.items.create_pages /lua.wetgenes.gamecake.fun.yarn.items.destroy /lua.wetgenes.gamecake.fun.yarn.items.find /lua.wetgenes.gamecake.fun.yarn.items.get_big /lua.wetgenes.gamecake.fun.yarn.items.insert /lua.wetgenes.gamecake.fun.yarn.items.iterate_dotnames /lua.wetgenes.gamecake.fun.yarn.items.iterate_parents /lua.wetgenes.gamecake.fun.yarn.items.metatable /lua.wetgenes.gamecake.fun.yarn.items.prefabs /lua.wetgenes.gamecake.fun.yarn.items.remove /lua.wetgenes.gamecake.fun.yarn.items.rules /lua.wetgenes.gamecake.fun.yarn.pages/lua.wetgenes.gamecake.fun.yarn.prefabs /lua.wetgenes.gamecake.fun.yarn.prefabs.set/lua.wetgenes.gamecake.fun.yarn.rules /lua.wetgenes.gamecake.fun.yarn.rules.apply /lua.wetgenes.gamecake.fun.yarn.rules.can /lua.wetgenes.gamecake.fun.yarn.rules.set/lua.wetgenes.gamecake.oven /lua.wetgenes.gamecake.oven.bake/lua.wetgenes.gamecake.toaster /lua.wetgenes.gamecake.toaster.bake /lua.wetgenes.gamecake.toaster.newticks/lua.wetgenes.gamecake.widgets /lua.wetgenes.gamecake.widgets.button /lua.wetgenes.gamecake.widgets.button.setup /lua.wetgenes.gamecake.widgets.button.update/lua.wetgenes.gamecake.widgets.center /lua.wetgenes.gamecake.widgets.center.layout /lua.wetgenes.gamecake.widgets.center.setup/lua.wetgenes.gamecake.widgets.checkbox /lua.wetgenes.gamecake.widgets.checkbox.class_hooks /lua.wetgenes.gamecake.widgets.checkbox.setup /lua.wetgenes.gamecake.widgets.checkbox.update/lua.wetgenes.gamecake.widgets.data /lua.wetgenes.gamecake.widgets.data.add_class_hook /lua.wetgenes.gamecake.widgets.data.call_hook /lua.wetgenes.gamecake.widgets.data.call_hook_later /lua.wetgenes.gamecake.widgets.data.data_dec /lua.wetgenes.gamecake.widgets.data.data_get_pos /lua.wetgenes.gamecake.widgets.data.data_get_size /lua.wetgenes.gamecake.widgets.data.data_inc /lua.wetgenes.gamecake.widgets.data.data_set /lua.wetgenes.gamecake.widgets.data.data_snap /lua.wetgenes.gamecake.widgets.data.data_tonumber /lua.wetgenes.gamecake.widgets.data.data_tonumber_from_list /lua.wetgenes.gamecake.widgets.data.data_tostring /lua.wetgenes.gamecake.widgets.data.data_tostring_from_list /lua.wetgenes.gamecake.widgets.data.data_value /lua.wetgenes.gamecake.widgets.data.del_class_hook /lua.wetgenes.gamecake.widgets.data.new_data/lua.wetgenes.gamecake.widgets.datas /lua.wetgenes.gamecake.widgets.datas.del /lua.wetgenes.gamecake.widgets.datas.get /lua.wetgenes.gamecake.widgets.datas.get_number /lua.wetgenes.gamecake.widgets.datas.get_string /lua.wetgenes.gamecake.widgets.datas.get_value /lua.wetgenes.gamecake.widgets.datas.new /lua.wetgenes.gamecake.widgets.datas.new_datas /lua.wetgenes.gamecake.widgets.datas.set /lua.wetgenes.gamecake.widgets.datas.set_infos /lua.wetgenes.gamecake.widgets.datas.set_string /lua.wetgenes.gamecake.widgets.datas.set_value/lua.wetgenes.gamecake.widgets.defs /lua.wetgenes.gamecake.widgets.defs.add /lua.wetgenes.gamecake.widgets.defs.add_border /lua.wetgenes.gamecake.widgets.defs.copy /lua.wetgenes.gamecake.widgets.defs.create /lua.wetgenes.gamecake.widgets.defs.reset /lua.wetgenes.gamecake.widgets.defs.set/lua.wetgenes.gamecake.widgets.dialogs /lua.wetgenes.gamecake.widgets.dialogs.hide_overlay /lua.wetgenes.gamecake.widgets.dialogs.setup /lua.wetgenes.gamecake.widgets.dialogs.show /lua.wetgenes.gamecake.widgets.dialogs.show_overlay/lua.wetgenes.gamecake.widgets.drag /lua.wetgenes.gamecake.widgets.drag.drag /lua.wetgenes.gamecake.widgets.drag.setup /lua.wetgenes.gamecake.widgets.drag.update/lua.wetgenes.gamecake.widgets.paragraph /lua.wetgenes.gamecake.widgets.paragraph.setup /lua.wetgenes.gamecake.widgets.setup/lua.wetgenes.gamecake.zone /lua.wetgenes.gamecake.zone.scene /lua.wetgenes.gamecake.zone.scene.add /lua.wetgenes.gamecake.zone.scene.call /lua.wetgenes.gamecake.zone.scene.caste /lua.wetgenes.gamecake.zone.scene.create_values /lua.wetgenes.gamecake.zone.scene.find_uid /lua.wetgenes.gamecake.zone.scene.forget_uid /lua.wetgenes.gamecake.zone.scene.generate_uid /lua.wetgenes.gamecake.zone.scene.remember_uid /lua.wetgenes.gamecake.zone.scene.remove /lua.wetgenes.gamecake.zone.scene.reset /lua.wetgenes.gamecake.zone.scene.sortby_update /lua.wetgenes.gamecake.zone.scene.status/lua.wetgenes.gamecake.zone.scene.systems /lua.wetgenes.gamecake.zone.scene.systems.call /lua.wetgenes.gamecake.zone.scene.systems.cocall /lua.wetgenes.gamecake.zone.scene.systems.insert /lua.wetgenes.gamecake.zone.scene.systems.remove /lua.wetgenes.gamecake.zone.scene.uids/lua.wetgenes.gamecake.zone.scene.values /lua.wetgenes.gamecake.zone.scene.values.get /lua.wetgenes.gamecake.zone.scene.values.manifest /lua.wetgenes.gamecake.zone.scene.values.new /lua.wetgenes.gamecake.zone.scene.values.push /lua.wetgenes.gamecake.zone.scene.values.set /lua.wetgenes.gamecake.zone.scene.values.tween /lua.wetgenes.gamecake.zone.scene.values.twrap /lua.wetgenes.gamecake.zone.scene.values.unpush/lua.wetgenes.gamecake.zone.system /lua.wetgenes.gamecake.zone.system.items/lua.wetgenes.grd /lua.wetgenes.grd.adjust_contrast /lua.wetgenes.grd.adjust_hsv /lua.wetgenes.grd.adjust_rgb /lua.wetgenes.grd.attr_redux /lua.wetgenes.grd.blit /lua.wetgenes.grd.clear /lua.wetgenes.grd.clip /lua.wetgenes.grd.convert /lua.wetgenes.grd.copy_data /lua.wetgenes.grd.copy_data_layer /lua.wetgenes.grd.create /lua.wetgenes.grd.create_convert /lua.wetgenes.grd.create_normal /lua.wetgenes.grd.destroy /lua.wetgenes.grd.duplicate /lua.wetgenes.grd.fillmask /lua.wetgenes.grd.flipx /lua.wetgenes.grd.flipy /lua.wetgenes.grd.info /lua.wetgenes.grd.load /lua.wetgenes.grd.load_data /lua.wetgenes.grd.load_file /lua.wetgenes.grd.paint /lua.wetgenes.grd.palette /lua.wetgenes.grd.pixels /lua.wetgenes.grd.quant /lua.wetgenes.grd.remap /lua.wetgenes.grd.reset /lua.wetgenes.grd.resize /lua.wetgenes.grd.save /lua.wetgenes.grd.scale /lua.wetgenes.grd.shrink /lua.wetgenes.grd.slide /lua.wetgenes.grd.sort_cmap /lua.wetgenes.grd.stream /lua.wetgenes.grd.xor /lua.wetgenes.grdcanvas/lua.wetgenes.grdhistory /lua.wetgenes.grdhistory.history /lua.wetgenes.grdlayers /lua.wetgenes.grdpaint/lua.wetgenes.grdsvg /lua.wetgenes.grdsvg.string/lua.wetgenes.json /lua.wetgenes.json.decode /lua.wetgenes.json.encode/lua.wetgenes.json_diff /lua.wetgenes.json_diff.apply /lua.wetgenes.json_diff.array_common /lua.wetgenes.json_diff.array_match /lua.wetgenes.json_diff.array_trim /lua.wetgenes.json_diff.diff /lua.wetgenes.json_diff.dupe /lua.wetgenes.json_diff.equal /lua.wetgenes.json_diff.similar /lua.wetgenes.json_diff.undo/lua.wetgenes.json_pack /lua.wetgenes.json_pack.from_data /lua.wetgenes.json_pack.into_data /lua.wetgenes.lookup/lua.wetgenes.midi /lua.wetgenes.midi.clients /lua.wetgenes.midi.create /lua.wetgenes.midi.destroy /lua.wetgenes.midi.event_to_string /lua.wetgenes.midi.get /lua.wetgenes.midi.peek /lua.wetgenes.midi.port_create /lua.wetgenes.midi.port_destroy /lua.wetgenes.midi.pull /lua.wetgenes.midi.push /lua.wetgenes.midi.set /lua.wetgenes.midi.string_to_clientport /lua.wetgenes.midi.subscribe /lua.wetgenes.midi.unsubscribe/lua.wetgenes.package /lua.wetgenes.package.reload/lua.wetgenes.path /lua.wetgenes.path.currentdir /lua.wetgenes.path.dir /lua.wetgenes.path.ext /lua.wetgenes.path.folder /lua.wetgenes.path.join /lua.wetgenes.path.name /lua.wetgenes.path.normalize /lua.wetgenes.path.parent /lua.wetgenes.path.parse /lua.wetgenes.path.relative /lua.wetgenes.path.resolve /lua.wetgenes.path.root /lua.wetgenes.path.setup /lua.wetgenes.path.split/lua.wetgenes.plate /lua.wetgenes.plate.replace_lookup /lua.wetgenes.plate.replace_lookup_istable /lua.wetgenes.plate.table_lookup /lua.wetgenes.rnd64k /lua.wetgenes.safecall /lua.wetgenes.safewrap /lua.wetgenes.set_env /lua.wetgenes.snippets/lua.wetgenes.spew /lua.wetgenes.spew.connect /lua.wetgenes.spew.test/lua.wetgenes.tardis /lua.wetgenes.tardis.array /lua.wetgenes.tardis.array.__add /lua.wetgenes.tardis.array.__div /lua.wetgenes.tardis.array.__eq /lua.wetgenes.tardis.array.__mul /lua.wetgenes.tardis.array.__sub /lua.wetgenes.tardis.array.__tostring /lua.wetgenes.tardis.array.__unm /lua.wetgenes.tardis.array.abs /lua.wetgenes.tardis.array.acos /lua.wetgenes.tardis.array.add /lua.wetgenes.tardis.array.asin /lua.wetgenes.tardis.array.atan /lua.wetgenes.tardis.array.ceil /lua.wetgenes.tardis.array.compare /lua.wetgenes.tardis.array.cos /lua.wetgenes.tardis.array.exp /lua.wetgenes.tardis.array.floor /lua.wetgenes.tardis.array.fract /lua.wetgenes.tardis.array.log /lua.wetgenes.tardis.array.max /lua.wetgenes.tardis.array.min /lua.wetgenes.tardis.array.mix /lua.wetgenes.tardis.array.pow /lua.wetgenes.tardis.array.product /lua.wetgenes.tardis.array.quantize /lua.wetgenes.tardis.array.round /lua.wetgenes.tardis.array.scalar /lua.wetgenes.tardis.array.set /lua.wetgenes.tardis.array.sin /lua.wetgenes.tardis.array.sub /lua.wetgenes.tardis.array.tan /lua.wetgenes.tardis.array.trunc /lua.wetgenes.tardis.array.unpack /lua.wetgenes.tardis.array.zero /lua.wetgenes.tardis.class/lua.wetgenes.tardis.line /lua.wetgenes.tardis.line.new/lua.wetgenes.tardis.m2 /lua.wetgenes.tardis.m2.adjugate /lua.wetgenes.tardis.m2.cofactor /lua.wetgenes.tardis.m2.determinant /lua.wetgenes.tardis.m2.identity /lua.wetgenes.tardis.m2.inverse /lua.wetgenes.tardis.m2.minor_xy /lua.wetgenes.tardis.m2.new /lua.wetgenes.tardis.m2.scale /lua.wetgenes.tardis.m2.transpose/lua.wetgenes.tardis.m3 /lua.wetgenes.tardis.m3.adjugate /lua.wetgenes.tardis.m3.cofactor /lua.wetgenes.tardis.m3.determinant /lua.wetgenes.tardis.m3.identity /lua.wetgenes.tardis.m3.inverse /lua.wetgenes.tardis.m3.m4 /lua.wetgenes.tardis.m3.minor_xy /lua.wetgenes.tardis.m3.new /lua.wetgenes.tardis.m3.scale /lua.wetgenes.tardis.m3.transpose /lua.wetgenes.tardis.m3.v3/lua.wetgenes.tardis.m4 /lua.wetgenes.tardis.m4.add /lua.wetgenes.tardis.m4.adjugate /lua.wetgenes.tardis.m4.arotate /lua.wetgenes.tardis.m4.cofactor /lua.wetgenes.tardis.m4.determinant /lua.wetgenes.tardis.m4.get_rotation_q4 /lua.wetgenes.tardis.m4.get_scale_v3 /lua.wetgenes.tardis.m4.get_translation_v3 /lua.wetgenes.tardis.m4.identity /lua.wetgenes.tardis.m4.inverse /lua.wetgenes.tardis.m4.m3 /lua.wetgenes.tardis.m4.minor_xy /lua.wetgenes.tardis.m4.mix /lua.wetgenes.tardis.m4.new /lua.wetgenes.tardis.m4.prearotate /lua.wetgenes.tardis.m4.preqrotate /lua.wetgenes.tardis.m4.prerotate /lua.wetgenes.tardis.m4.prerrotate /lua.wetgenes.tardis.m4.prescale /lua.wetgenes.tardis.m4.pretranslate /lua.wetgenes.tardis.m4.pretranslate_v3 /lua.wetgenes.tardis.m4.qrotate /lua.wetgenes.tardis.m4.rotate /lua.wetgenes.tardis.m4.rrotate /lua.wetgenes.tardis.m4.scale /lua.wetgenes.tardis.m4.scale_v3 /lua.wetgenes.tardis.m4.setrot /lua.wetgenes.tardis.m4.setrrot /lua.wetgenes.tardis.m4.sub /lua.wetgenes.tardis.m4.translate /lua.wetgenes.tardis.m4.translate_v3 /lua.wetgenes.tardis.m4.transpose /lua.wetgenes.tardis.m4.v3 /lua.wetgenes.tardis.m4_stack/lua.wetgenes.tardis.plane /lua.wetgenes.tardis.plane.new/lua.wetgenes.tardis.q4 /lua.wetgenes.tardis.q4.get_yaw_pitch_roll /lua.wetgenes.tardis.q4.get_yaw_pitch_roll_in_radians /lua.wetgenes.tardis.q4.identity /lua.wetgenes.tardis.q4.mix /lua.wetgenes.tardis.q4.new /lua.wetgenes.tardis.q4.prerotate /lua.wetgenes.tardis.q4.prerrotate /lua.wetgenes.tardis.q4.reverse /lua.wetgenes.tardis.q4.rotate /lua.wetgenes.tardis.q4.rrotate /lua.wetgenes.tardis.q4.set /lua.wetgenes.tardis.q4.set_yaw_pitch_roll /lua.wetgenes.tardis.q4.set_yaw_pitch_roll_in_radians /lua.wetgenes.tardis.q4.setrot /lua.wetgenes.tardis.q4.setrrot /lua.wetgenes.tardis.smoothstep /lua.wetgenes.tardis.step /lua.wetgenes.tardis.type/lua.wetgenes.tardis.v1 /lua.wetgenes.tardis.v1.add /lua.wetgenes.tardis.v1.cross /lua.wetgenes.tardis.v1.distance /lua.wetgenes.tardis.v1.dot /lua.wetgenes.tardis.v1.identity /lua.wetgenes.tardis.v1.len /lua.wetgenes.tardis.v1.lenlen /lua.wetgenes.tardis.v1.mul /lua.wetgenes.tardis.v1.normalize /lua.wetgenes.tardis.v1.oo /lua.wetgenes.tardis.v1.scale /lua.wetgenes.tardis.v1.sub/lua.wetgenes.tardis.v2 /lua.wetgenes.tardis.v2.add /lua.wetgenes.tardis.v2.cross /lua.wetgenes.tardis.v2.distance /lua.wetgenes.tardis.v2.dot /lua.wetgenes.tardis.v2.identity /lua.wetgenes.tardis.v2.len /lua.wetgenes.tardis.v2.lenlen /lua.wetgenes.tardis.v2.mul /lua.wetgenes.tardis.v2.new /lua.wetgenes.tardis.v2.normalize /lua.wetgenes.tardis.v2.oo /lua.wetgenes.tardis.v2.scale /lua.wetgenes.tardis.v2.sub/lua.wetgenes.tardis.v3 /lua.wetgenes.tardis.v3.add /lua.wetgenes.tardis.v3.angle /lua.wetgenes.tardis.v3.cross /lua.wetgenes.tardis.v3.distance /lua.wetgenes.tardis.v3.dot /lua.wetgenes.tardis.v3.identity /lua.wetgenes.tardis.v3.len /lua.wetgenes.tardis.v3.lenlen /lua.wetgenes.tardis.v3.mul /lua.wetgenes.tardis.v3.new /lua.wetgenes.tardis.v3.normalize /lua.wetgenes.tardis.v3.oo /lua.wetgenes.tardis.v3.scale /lua.wetgenes.tardis.v3.sub/lua.wetgenes.tardis.v4 /lua.wetgenes.tardis.v4.add /lua.wetgenes.tardis.v4.distance /lua.wetgenes.tardis.v4.dot /lua.wetgenes.tardis.v4.identity /lua.wetgenes.tardis.v4.len /lua.wetgenes.tardis.v4.lenlen /lua.wetgenes.tardis.v4.mul /lua.wetgenes.tardis.v4.new /lua.wetgenes.tardis.v4.normalize /lua.wetgenes.tardis.v4.oo /lua.wetgenes.tardis.v4.scale /lua.wetgenes.tardis.v4.sub /lua.wetgenes.tardis.v4.to_v3/lua.wetgenes.tasks /lua.wetgenes.tasks.add_global_thread /lua.wetgenes.tasks.add_id /lua.wetgenes.tasks.add_memo /lua.wetgenes.tasks.add_task /lua.wetgenes.tasks.add_thread /lua.wetgenes.tasks.claim_global /lua.wetgenes.tasks.client /lua.wetgenes.tasks.client_code /lua.wetgenes.tasks.cocall /lua.wetgenes.tasks.create /lua.wetgenes.tasks.create_colinda /lua.wetgenes.tasks.del_global_thread /lua.wetgenes.tasks.del_id /lua.wetgenes.tasks.del_memo /lua.wetgenes.tasks.del_task /lua.wetgenes.tasks.del_thread /lua.wetgenes.tasks.delete /lua.wetgenes.tasks.do_memo /lua.wetgenes.tasks.eject_global /lua.wetgenes.tasks.fetch_name /lua.wetgenes.tasks.global_code /lua.wetgenes.tasks.http /lua.wetgenes.tasks.http_code /lua.wetgenes.tasks.receive /lua.wetgenes.tasks.run_task /lua.wetgenes.tasks.send /lua.wetgenes.tasks.sqlite /lua.wetgenes.tasks.sqlite_code /lua.wetgenes.tasks.thread_code /lua.wetgenes.tasks.update/lua.wetgenes.tasks_msgp /lua.wetgenes.tasks_msgp.addr_to_ip_port /lua.wetgenes.tasks_msgp.addr_to_list /lua.wetgenes.tasks_msgp.clean_name /lua.wetgenes.tasks_msgp.ip6_to_addr /lua.wetgenes.tasks_msgp.ipsniff /lua.wetgenes.tasks_msgp.list_to_addr /lua.wetgenes.tasks_msgp.msgp_code /lua.wetgenes.tasks_msgp.pack/lua.wetgenes.tsv /lua.wetgenes.tsv.close /lua.wetgenes.tsv.create /lua.wetgenes.tsv.flush /lua.wetgenes.tsv.load/lua.wetgenes.txt /lua.wetgenes.txt.diff /lua.wetgenes.txt.diff.find /lua.wetgenes.txt.diff.match /lua.wetgenes.txt.diff.split /lua.wetgenes.txt.diff.trim /lua.wetgenes.txt.edit /lua.wetgenes.txt.lex /lua.wetgenes.txt.lex_js /lua.wetgenes.txt.lex_lua /lua.wetgenes.txt.undo/lua.wetgenes.txt.utf /lua.wetgenes.txt.utf.char /lua.wetgenes.txt.utf.charpattern /lua.wetgenes.txt.utf.chars /lua.wetgenes.txt.utf.length /lua.wetgenes.txt.utf.map_latin0_to_unicode /lua.wetgenes.txt.utf.map_unicode_to_latin0 /lua.wetgenes.txt.utf.size /lua.wetgenes.txt.utf.string/lua.wetgenes.txt.words /lua.wetgenes.txt.words.load /lua.wetgenes.txt.words.transform /prefabs /rules /setup /setup_menu /update

code.swankyquant.algorithm

SwankyQuant

To use this code remember to include it only once with SWANKYQUANT_C defined or no code will be generated. For example.

#define SWANKYQUANT_C
#include "swankyquant.h"

...

swanky_quant( input, length, 256, output, palette, 6 );

swanky_quant_remap( input, length, 256, output, palette, width, 6 );

The remap step is unnecessary unless you want your output image dithered.

SwankyQuant is a palette selection algorithm made of a combination of simple actions, it requires a weighted compare function between two colours and everything else is brute force selection based on this compare. Since this compare is only used for yes/no logic then a 4d distance squared between two 32bit colours is the default. Unlike the alternatives we fully support alpha in out palettes.

The trick that makes this possible is using a byte per pixel thinking buffer. Since you are presumably intending to remap the original image into a buffer exactly like this I do not consider this an excessive extra resource, especially since this buffer is also the output indexed image when we are finished.

This buffer allows us to keep track of which bucket we have assigned to each pixel, this combined with multiple image passes allows pixels to jump from bucket to bucket until the allocation of pixels to available buckets is reasonably optimal. We don't actually pick a palette we just sort pixels into buckets with other pixels of a similar colour. When finished the average colour of each bucket is the resulting palette.

Essentially we skip the generate a palette step and instead remap the image repeatedly with the output palette automatically effected by every pixels decision. Giving nice simple feedback until we hit a stable optimum solution.

In order to reduce the number of image passes (each one is expensive) we use an adjustable weight on the decision to jump so that early passes have more of an effect and later passes cleanup any mistakes, this combined with a reasonable starting state (map by luminescence) helps to reduce the cost of multiple passes and brute force searches to an acceptable level.

Due to the brute force compares, generating a smaller palette is faster than a larger palette. In Swanky Paint we are much more interested in 16/32 colour palettes than 256 colour palettes so this is an additional advantage.

If the input contains only a handful of unique colours then we are very likely to pick these exact colours provided there is enough room for them all in the output palette.

REFERENCE LINKS TO OTHER ALGORITHMS

  1. http://www.imagemagick.org/script/quantize.php
  2. https://www.researchgate.net/publication/232079905_Kohonen_neural_networks_for_optimal_colour_quantization
  3. https://scientificgems.wordpress.com/stuff/neuquant-fast-high-quality-image-quantization/

In comparison to the above I would list the following pros and cons.

SWANKYQUANT PROS
================

    . Is simple to understand and tweak.

    . Works with 32bit alpha.

    . Works well with a small output palette.

    . Will pick every distinct input if palette size allows.


SWANKYQUANT CONS
================

    . Uses output memory as a thinking buffer.

    . Is slower for large images and 256 colour palettes.


For large images I would recommend scaling the image down in size then using the smaller image to generate the palette. Less precise but a huge performance gain. This is the logic I use in Swanky Paint and the grd library when loading larger images.

code.swankyquant.color_distance

Compare two colors and return a distance value. This is non linear, as we do not need to bother with the sqrt since the numbers are only used for comparison.

code.swankyquant.color_distance_weight

Compare how close a match it would be if we added our color(weighted) to a bucket.

Each bucket is 5 doubles and contains an rgba accumulator in [0][1][2][3] and a number of samples in [5] Doubles must be used rather than floats or we will encounter number overflow for images that are larger than 256x256 pixels.

(A float or int version for smaller images might be worthwhile.)

The weight should be a natural 1.0 but since we want to encourage early bucket jumping we fudge it high at the start and then lower it on later passes to bring stability to the feedback system. This is simply to reduce the number of passes over the data required to get good results.

This function also accounts for most of the thinking time so could/should be optimised more.

code.swankyquant.swanky_quant

Reduce input rgba data to the requested number of index colors(2-256)

reads data from input[4*length]

writes data to output[length] and palette[4*colors]

Make sure this memory is available.

Quality is the number of passes and 6 or more is recommended for good results.

code.swankyquant.swanky_quant_remap

Perform a final remap on a swanky_quant output image with an optional amount of ordered dithering.

dither = 0  ==   1 bit pattern  ( no dithering )
dither = 1  ==   3 bit patterns
dither = 2  ==   5 bit patterns
dither = 3  ==   9 bit patterns
dither = 4  ==  17 bit patterns ( recommended dithering )
dither = 5  ==  33 bit patterns
dither = 6  ==  65 bit patterns ( maximum dithering )

width is the width of the image, we need to know this so we can dither nicely.

All other values are the same as used in the swanky_quant function call.

draw

draw()

Draw called every frame, there may be any number of updates between each draw but hopefully we are looking at one update followed by a draw, if you have an exceptionally fast computer then we may even get 0 updates between some draws.

entities

entities.reset()

empty the list of entites to update and draw

entities.caste(caste)

get the list of entities of a given caste, eg "bullets" or "enemies"

entities.add(it,caste)
entities.add(it)

add a new entity of caste or it.caste to the list of things to update

entities.call(fname,...)

for every entity call the function named fname like so itfname


entities.get(name)

get a value previously saved, this is an easy way to find a unique entity, eg the global space but it can be used to save any values you wish not just to bookmark unique entities.

entities.set(name,value)

save a value by a unique name

entities.manifest(name,value)

get a value previously saved, or initalize it to the given value if it does not already exist. The default value is {} as this is intended for lists.


entities.systems

A table to register or find a global system, these are not cleared by reset and should not contain any state data, just functions to create the actual entity or initialise data.


entities.tiles

These functions are called as we generate a level from ascii, every value in the tile legend data is checked against all the strings in entities.tiles and if it matches it calls that function which is then responsible for adding the appropriate collision and drawing code to make that tile actually add something to the level.

The basic values of tile.tile and tile.back are used to write graphics into the two tile layers but could still be caught here if you need to.

Multiple hooks may get called for a single tile, think of each string as a flag to signal that something happens and its value describes what happens.

entities.systems

A global table for entity systems to live in.

entities.systems_call(fname,...)

Call the named function on any systems that currently exist. For instance entities.systems_call("load") is used at the bottom of this file to prepare graphics of registered systems.

entities.systems.item

item = entities.systems.item.add()

items, can be used for general things, EG physics shapes with no special actions

entities.systems.level

entities.systems.level.setup(level)

reset and setup everything for this level idx

entities.systems.menu

menu = entities.systems.menu.setup()

Create a displayable and controllable menu system that can be fed chat data for user display.

After setup, provide it with menu items to display using menu.show(items) then call update and draw each frame.

entities.systems.player

entities.systems.player.controls(it,fast)

Handle player style movement, so we can reuse this code for player style monsters. it is a player or monster, fast lets us tweak the speed and defaults to 1

movement controls are set in it

it.move which is "left" or "right" to move left or right it.jump which is true if we should jump

entities.systems.score

score = entities.systems.score.setup()

Create entity that handles the score hud update and display

entities.systems.space

space = entities.systems.space.setup()

Create the space that simulates all of the physics.

graphics

define all graphics in this global, we will convert and upload to tiles at setup although you can change tiles during a game, we try and only upload graphics during initial setup so we have a nice looking sprite sheet to be edited by artists

hardware

select the hardware we will need to run this code, eg layers of graphics, colors to use, sprites, text, sound, etc etc.

Here we have chosen the default 320x240 setup.

lua.glslang

Manage string embedding and the glsl compiler and language options.

This is somewhat separate to the main GLES code and can be used without linking to any system dependent GL libs.

lua.glslang.lint_gles2

verr,ferr = glslang.lint_gles2(vcode,fcode)

Try and compile a vertex/fragment shader pair and return any errors.

returns nil,nil on success or an error string if either shader fails to compile.

Note that the glslang compile step seems rather slow, not sure what it gets up to but do not consider using this if speed is important.

lua.glslang.parse_chunks

shaders=glslang.shader_chunks(text,filename,headers,flags)

    load multiple shader chunks from a single file and return a lookup
    table of name=code for each shader we just loaded. These can then be
    compiled or whatever.
    
    set flags.headers_only to true if you only care about parsing headers
    for later inclusion and do not want to parse shader chunks.
    

#SHADER "nameofshader"

    is used at the start of a line to say which chunk the following text
    should go into. This is technically the same as #header but makes it
    explicit that this should be all the code for a shader rather than just
    a piece.

#HEADER "nameofheader"

    can be used to define part of a shader, which can later be included in
    another shader by using

#INCLUDE "nameofheader"

    Will insert the chunk of text previously defined as a #SHADER or #HEADER

#SHADER or #HEADER

    without a name can be used to ignore the next part of a file, any text
    at the start of a file before the first #SHADER or #HEADER is also
    ignored. This enables these chunks to exist inside comments in a lua or
    whatever file.

lua.glslang.pp

code,err = glslang.pp(code,err)

Preprocess a vertex/fragment and return the result.

returns nil,error on error

lua.glslang.replace_include

process #include statements in src with strings found in the headers table

lua.glslang.yank_shader_versions

parse a shader source and yank any #version out of the source and into a table this allows multiple attempts at compiling the same source using different #versions

lua.wetgenes

local wetgenes=require("wetgenes")

Simple generic functions that are intended to be useful for all wetgenes.* modules.

Probably best to cherry pick a few functions you need and export then like so.

local export,lookup,deepcopy=require("wetgenes"):export("export","lookup","deepcopy")

lua.wetgenes.bullet

local bullet=require("wetgenes.bullet")

We use bullet as the local name of this library.

A lua binding to the Bullet Physics library

lua.wetgenes.bullet.body.cgroup

body:cgroup(bits)
bits=body:cgroup()

Set or get body cgroup bits. You have 31 bits, so use 0x7fffffff to set all. These provide simple yes/no collision control between bodies.

cgroup bits are all the groups this body belongs to.
cmask bits are all the groups this body colides with.

lua.wetgenes.bullet.body.change_shape

body:change_shape(shape)
body:change_shape(shape,mass)

Change the shape assoctiated with this body and optionally change the mass.

lua.wetgenes.bullet.body.cmask

body:cmask(bits)
bits=body:cmask()
body:cmask(0x7fffffff)

Set or get body cmask bits. You have 31 bits, so use 0x7fffffff to set all. This body will only colide with another body if the other bodys cgroup has a bit set that is also set in our cmask.

cgroup bits are all the groups this body belongs to.
cmask bits are all the groups this body colides with.

lua.wetgenes.bullet.body.force

body:force(fx,fy,fz)
body:force(fx,fy,fz,lx,ly,lz)

Apply force fx,fy,fz at world relative location (subtract origin of object) lx,ly,lz which will default to 0,0,0 if not given.

lua.wetgenes.bullet.body.gravity

body:gravity(x,y,z)
x,y,z = body:gravity()

Set or get body gravity vector. Fidling with this may be the easiest way for a player to move an object around, it certainly makes it easier to create "magnetic fields" to hover objects above the ground.

lua.wetgenes.bullet.body.impulse

body:impulse(fx,fy,fz)
body:impulse(fx,fy,fz,lx,ly,lz)

Apply impulse fx,fy,fz at world relative location (subtract origin of object) lx,ly,lz which will default to 0,0,0 if not given.

lua.wetgenes.bullet.body.overlaps

body:overlaps()

Get list of bodys that overlap with a ghost body object.

lua.wetgenes.bullet.body.support

x,y,z=body:support(nx,ny,nz)

Get world location of support point in given direction.

EG the world location that is touching the floor when the direction is up.

lua.wetgenes.bullet.world

world=bullet.world()

Create the world you will be simulating physics in.

lua.wetgenes.bullet.world.body

body = world:body("rigid",shape,mass,x,y,z,cgroup,cmask)
body = world:body({name="rigid",shape=shape,mass=mass.pos=V3(0)})

Create a body.

lua.wetgenes.bullet.world.body.active

b = body:active( true )
b = body:active( false )
b = body:active()

get/set the active state of an object

lua.wetgenes.bullet.world.body.angular_factor

x,y,z = body:angular_factor( x , y , z )
x,y,z = body:angular_factor( r )
r = ( body:angular_factor( r ) )

get/set the angular factor of an object (which disables rotation when zero)

lua.wetgenes.bullet.world.body.angular_velocity

x,y,z = body:angular_velocity( x,y,z )
x,y,z = body:angular_velocity()

get/set the body angular velocity

lua.wetgenes.bullet.world.body.ccd

r,t = body:ccd( radius,threshold )
r,t = body:ccd()

get/set the continuos collision detection radius,threshold values

lua.wetgenes.bullet.world.body.custom_material_callback

b = body:custom_material_callback( b )
b = body:custom_material_callback()

get/set the body custom_material_callback flag

When set we run a custom callback to try and smooth mesh collisions.

lua.wetgenes.bullet.world.body.damping

l,a = body:damping( linear , angular )
l,a = body:damping()

get/set the body damping

lua.wetgenes.bullet.world.body.factor

x,y,z = body:factor( x , y , z )
x,y,z = body:factor( r )
r = ( body:factor( r ) )

get/set the linear factor of an object (which disables movement when zero)

lua.wetgenes.bullet.world.body.friction

l,a,s = body:friction( linear , angular , spinning )
l,a,s = body:friction()

get/set the body friction

lua.wetgenes.bullet.world.body.restitution

r = body:transform( r )
r = body:transform()

get/set the body restitution

lua.wetgenes.bullet.world.body.transform

px,py,pz,qx,qy,qz,qw = body:transform()
px,py,pz,qx,qy,qz,qw = body:transform(px,py,pz)
px,py,pz,qx,qy,qz,qw = body:transform(px,py,pz,qx,qy,qz,qw)

get/set the body transform. Position and Rotation Quaternion.

lua.wetgenes.bullet.world.body.velocity

x,y,z = body:velocity( x,y,z )
x,y,z = body:velocity()

get/set the body velocity

lua.wetgenes.bullet.world.contacts

local contacts,csiz=world:contacts()
local contacts,csiz=world:contacts(min_dist)
local contacts,csiz=world:contacts(min_dist,min_impulse)

Fetch all contacts in the world that are the same or closer than min_dist which defaults to 0 and hit the same or harder than min_impulse which also defaults to 0. This helps filter out uninteresting collisions before we process them.

csiz, the second return allows us to put more info into each chunk in the future, it will probably be 10 but may grow if it turns out that more contact info for each point would help.

This returns a list of contacts. Each contact is an array that consists of.

a_body,
b_body,

and then 1 or more chunks of csiz (which is currently 10) numbers representing

ax,ay,az,	-- world position on a_body
bx,by,bz,	-- world position on b_body
nx,ny,nz,	-- world normal on b_body
impulse,	-- impulse applied by collision

So you can find the two bodys in contact[1] and contact[2] but are then expected to loop over the rest of the array as chunks of csiz like so.

for idx=3,#contact,csiz do
    local pos_a={ contact[idx+0] , contact[idx+1] , contact[idx+2] }
    local pos_b={ contact[idx+3] , contact[idx+4] , contact[idx+5] }
    local nrm_b={ contact[idx+6] , contact[idx+7] , contact[idx+8] }
    local impulse=contact[idx+9]
    ...
end

This is intended to be processed and interesting collisions handled or saved for later.

lua.wetgenes.bullet.world.gravity

world:gravity(x,y,z)

x,y,z = world:gravity()

Set or get world gravity vector. Recommended gravity is 0,-10,0

lua.wetgenes.bullet.world.ray_test

local test={
    mode="closest",
    ray={{}0,0,0,{1,1,1}},
}
test=world:ray_test(test)

if world:ray_test(opts).hit then ... end

Perform a ray test between the two ray vectors provided in the test table. fills in hit={...} if we hit something with details of the hit.

Always returns the test table that was passed in, with modifications that provide the result. Be carefull about reusing this table it is safest to create a new one for each ray_test call.

lua.wetgenes.bullet.world.status

print( world:status() )

Return a debug string about allocated objects in this world.

lua.wetgenes.bullet.world.step

world:step(seconds,maxsteps,fixedstep)

world:step(seconds,0,seconds)

world.maxsteps and world.fixedstep will be used as defaults if the second and third values are not provided.

Move the physics forward in time by the given amount in seconds.

maxsteps is maximum amount of steps to take during this call and defaults to 1.

fixedstep is how many seconds to step forward at a time for stable simulation and defaults to 1/60

To force a step forward of a given amount of time use a maxsteps of 0.

lua.wetgenes.chipmunk

local chipmunk=require("wetgenes.chipmunk")

We use chipmunk as the local name of this library.

A lua binding to the Chipmunk2D physics library chipmunk-physics.net

lua.wetgenes.chipmunk.arbiter.ignore

return arbiter:ignore()

Ignore this collision, from now until the shapes separate.

lua.wetgenes.chipmunk.arbiter.points

points=arbiter:points()
points=arbiter:points(points)

Get and/or Set the points data for this arbiter.

lua.wetgenes.chipmunk.arbiter.surface_velocity

vx,vy=arbiter:surface_velocity()
vx,vy=arbiter:surface_velocity(vx,vy)

Get and/or Set the surface velocity for this arbiter.

lua.wetgenes.chipmunk.body

body=chipmunk.body(mass,inertia)

Create a dynamic body, with the given mass and inertia.

You will need to add the body to a space before it exists so it is normally preferable to use the space:body function which will call this function and then automatically add the body into the space.

body=chipmunk.body("kinematic")

Create a kinematic body, these are bodies that we can move around, by setting its velocity, but are not effected by collisions with other bodies. EG a moving platform.

body=chipmunk.body("static")

Create a static body, mostly you can just use space.static as the default static body but you may create more if you wish to group your static shapes into multiple bodies.

lua.wetgenes.chipmunk.body.angle

a=body:angle()
a=body:angle(a)

Get and/or Set the rotation angle in radians for this body.

lua.wetgenes.chipmunk.body.angular_velocity

a=body:angular_velocity()
a=body:angular_velocity(a)

Get and/or Set the angular velocity in radians for this body.

lua.wetgenes.chipmunk.body.apply_force

body:apply_force(fx,fy,px,py)
body:apply_force(fx,fy,px,py,"world")

Apply a force to this body at a specific point, the point can be in world coordinates if you include the "world" flag but defaults to local object coordinates.

lua.wetgenes.chipmunk.body.apply_impulse

body:apply_impulse(ix,iy,px,py)
body:apply_impulse(ix,iy,px,py,"world")

Apply a force to this body at a specific point, the point can be in world coordinates if you include the "world" flag but defaults to local object coordinates.

lua.wetgenes.chipmunk.body.center_of_gravity

vx,vy=body:center_of_gravity()
vx,vy=body:center_of_gravity(vx,vy)

Get and/or Set the center of gravity for this body.

lua.wetgenes.chipmunk.body.force

vx,vy=body:force()
vx,vy=body:force(vx,vy)

Get and/or Set the force for this body. This is reset back to 0 after each step.

lua.wetgenes.chipmunk.body.mass

m=body:mass()
m=body:mass(m)

Get and/or Set the mass for this body.

lua.wetgenes.chipmunk.body.moment

m=body:moment()
m=body:moment(m)

Get and/or Set the moment for this body.

lua.wetgenes.chipmunk.body.position

vx,vy=body:position()
vx,vy=body:position(vx,vy)

Get and/or Set the position for this body.

lua.wetgenes.chipmunk.body.position_func

body:position_func(position_callback)
body:position_func()

Set or clear the position callback update function for this body.

position_callback(body)

body.delta_time

This callback will be called with the above values set into body, you can adjust these and return true to perform a normal position update but with these new values.

Alternatively you can update the bodys position directly and return false so the normal position update code will not be run.

lua.wetgenes.chipmunk.body.shape

shape=body:shape(form,...)

Add a new shape to this body, returns the shape for further modification.

lua.wetgenes.chipmunk.body.torque

a=body:torque()
a=body:torque(a)

Get and/or Set the torque for this body.

lua.wetgenes.chipmunk.body.type

t=body:type()
t=body:type(t)

Get and/or Set the type for this body.

lua.wetgenes.chipmunk.body.velocity

vx,vy=body:velocity()
vx,vy=body:velocity(vx,vy)

Get and/or Set the velocity for this body.

lua.wetgenes.chipmunk.body.velocity_func

body:velocity_func(velocity_callback)
body:velocity_func()

Set or clear the velocity callback update function for this body.

velocity_callback(body)

body.gravity_x
body.gravity_y
body.damping
body.delta_time

This callback will be called with the above values set into body, you can adjust these and return true to perform a normal velocity update but with these new values.

IE you can choose a new gravity vector for this body which is the simplest change to make.

Alternatively you can update the bodys velocity directly and return false so the normal velocity update code will not be run.

lua.wetgenes.chipmunk.constraint

constraint=chipmunk.constraint(abody,bbody,form,...)

Create a constraint between two bodies.

You will need to add the constraint to a space before it has any effect so it is normally preferable to use the space:constraint function which will call this function and then automatically add the constraint into the space.

constraint=chipmunk.constraint(abody,bbody,"pin_join",ax,ay,bx,by)

form of "pin_joint" ...

constraint=chipmunk.constraint(abody,bbody,"slide_joint",ax,ay,bx,by,fl,fh)

form of "slide_joint" ...

constraint=chipmunk.constraint(abody,bbody,"pivot_joint",x,y)
constraint=chipmunk.constraint(abody,bbody,"pivot_joint",ax,ay,bx,by)

form of "pivot_joint" ...

constraint=chipmunk.constraint(abody,bbody,"groove_joint",ax,ay,bx,by,cx,cy)

form of "groove_joint" ...

constraint=chipmunk.constraint(abody,bbody,"damped_spring",ax,ay,bx,by,fl,fs,fd)

form of "damped_spring" ...

constraint=chipmunk.constraint(abody,bbody,"damped_rotary_spring",fa,fs,fd)

form or "damped_rotary_spring" ...

constraint=chipmunk.constraint(abody,bbody,"rotary_limit_joint",fl,fh)

form of "rotary_limit_joint" ...

constraint=chipmunk.constraint(abody,bbody,"ratchet_joint",fp,fr)

form of "ratchet_joint" ...

constraint=chipmunk.constraint(abody,bbody,"gear_joint",fp,fr)

form of "gear_joint" ...

constraint=chipmunk.constraint(abody,bbody,"simple_motor",fr)

form of "simple_motor" ...

lua.wetgenes.chipmunk.constraint.collide_bodies

v=constraint:collide_bodies()
v=constraint:collide_bodies(v)

Get and/or Set the max collide bodies flag for this constraint.

lua.wetgenes.chipmunk.constraint.error_bias

v=constraint:error_bias()
v=constraint:error_bias(v)

Get and/or Set the error bias for this constraint.

lua.wetgenes.chipmunk.constraint.max_bias

v=constraint:max_bias()
v=constraint:max_bias(v)

Get and/or Set the max bias for this constraint.

lua.wetgenes.chipmunk.constraint.max_force

v=constraint:max_force()
v=constraint:max_force(v)

Get and/or Set the max force for this constraint.

lua.wetgenes.chipmunk.shape

shape=chipmunk.shape(body,form...)

Create a shape, added to the given body. Shapes are always added to a body but must be added to a space before they have any effect. So it is normally preferable to use the body:shape function which will automatically add the shape into the space that the body belongs to.

shape=chipmunk.shape(space.static,form...)

Create a static shape in world space. We use space.static as the body.

shape=chipmunk.shape(body,"circle",radius,x,y)

Form of "circle" needs a radius and a centre point.

shape=chipmunk.shape(body,"segment",ax,ay,bx,by,radius)

Form of "segment" needs two points and a radius.

shape=chipmunk.shape(body,"poly",{x1,y1,x2,y2,...},radius)

Form of "poly" is a generic polygon defined by a table of points.

shape=chipmunk.shape(body,"box",minx,miny,maxx,maxy,radius)

Form of "box" needs two points for opposite corners, lowest pair followed by highest pair and a radius. The radius should be 0 unless you want rounded corners

lua.wetgenes.chipmunk.shape.bounding_box

min_x,min_y,max_x,max_y=shape:bounding_box()

Get the current bounding box for this shape.

lua.wetgenes.chipmunk.shape.collision_type

f=shape:collision_type()
f=shape:collision_type(f)

Get and/or Set the collision type for this shape.

The f argument can be a string in which case it will be converted to a number via the space:type function.

lua.wetgenes.chipmunk.shape.elasticity

f=shape:elasticity()
f=shape:elasticity(f)

Get and/or Set the elasticity for this shape.

lua.wetgenes.chipmunk.shape.filter

f=shape:filter()
f=shape:filter(f)

Get and/or Set the filter for this shape.

lua.wetgenes.chipmunk.shape.friction

f=shape:friction()
f=shape:friction(f)

Get and/or Set the friction for this shape.

lua.wetgenes.chipmunk.shape.query_point

item = shape:query_point(x,y)

Find the nearest point on the shape from the point at x,y.

returns a table with the following info or nil for no hit

it.shape		-- the shape
it.point_x		-- the point of contact (x)
it.point_y		-- the point of contact (y)
it.distance		-- the distance to the point of contact
it.gradient_x	-- the normalised vector to collision (x)
it.gradient_y	-- the normalised vector to collision (y)

lua.wetgenes.chipmunk.shape.query_segment

it = shape:query_segment(sx,sy,ex,ey,r)

Find the hitpoint along this raycast segment, from (sx,sy) to (ex,ey) with a radius of r.

Returns a table with the following info or nil for no hit

it.shape		-- the shape
it.point_x		-- the point of contact (x)
it.point_y		-- the point of contact (y)
it.normal_x		-- the normal at contact (x)
it.normal_y		-- the normal at contact (y)
it.alpha		-- how far along the segment the contact happened (0 to 1)

lua.wetgenes.chipmunk.shape.radius

radius=shape:radius()
radius=shape:radius(radius)

Get and/or Set the radius for this shape. Setting is unsafe and may break the physics simulation.

lua.wetgenes.chipmunk.shape.sensor

f=shape:sensor()
f=shape:sensor(f)

Get and/or Set the sensor flag for this shape.

lua.wetgenes.chipmunk.shape.surface_velocity

vx,vy=shape:surface_velocity()
vx,vy=shape:surface_velocity(vx,vy)

Get and/or Set the surface velocity for this shape.

lua.wetgenes.chipmunk.space

space=chipmunk.space()

Create the space you will be simulating physics in.

lua.wetgenes.chipmunk.space.add

space:add(body)
space:add(shape)
space:add(constraint)

Add a body/shape/constraint to the space.

lua.wetgenes.chipmunk.space.add_handler

space:add_handler(handler,id1,id2)
space:add_handler(handler,id1)
space:add_handler(handler)

Add collision callback handler, for the given collision types.

The handler table will have other values inserted in it and will be used as an arbiter table in callbacks. So always pass in a new one to this function. There does not seem to be a way to free handlers so be careful what you add.

id1,id2 can be a string in which case it will be converted to a number via the space:type function.

lua.wetgenes.chipmunk.space.collision_bias

v=space:collision_bias()
v=space:collision_bias(v)

Get and/or Set the colision bias for this space.

lua.wetgenes.chipmunk.space.collision_persistence

v=space:collision_persistence()
v=space:collision_persistence(v)

Get and/or Set the collision persistence for this space.

lua.wetgenes.chipmunk.space.collision_slop

v=space:collision_slop()
v=space:collision_slop(v)

Get and/or Set the colision slop for this space.

lua.wetgenes.chipmunk.space.contains

space:contains(body)
space:contains(shape)
space:contains(constraint)

Does the space contain this body/shape/constraint, possibly superfluous as we can check our own records.

lua.wetgenes.chipmunk.space.damping

v=space:damping()
v=space:damping(v)

Get and/or Set the damping for this space.

lua.wetgenes.chipmunk.space.gravity

vx,vy=space:gravity()
vx,vy=space:gravity(vx,vy)

Get and/or Set the gravity vector for this space.

lua.wetgenes.chipmunk.space.idle_speed_threshold

v=space:idle_speed_threshold()
v=space:idle_speed_threshold(v)

Get and/or Set the idle speed threshold for this space.

lua.wetgenes.chipmunk.space.iterations

v=space:iterations()
v=space:iterations(v)

Get and/or Set the iterations for this space.

lua.wetgenes.chipmunk.space.locked

v=space:locked()

Get the locked state for this space, if true we cannot change shapes.

lua.wetgenes.chipmunk.space.query_bounding_box

array = space:query_bounding_box(lx,ly,hx,hy,group,categories,mask)

Find the shapes that are within this bounding box (lx,ly) to (hx,hy). Use group,categories and mask to filter the results.

Returns an array of shapes.

lua.wetgenes.chipmunk.space.query_point

array = space:query_point(x,y,d,group,categories,mask)

Find the shapes that are within d distance from the point at x,y. Use group,categories and mask to filter the results.

Returns an array of hit data, with each item containing the following.

it.shape		-- the shape
it.point_x		-- the point of contact (x)
it.point_y		-- the point of contact (y)
it.distance		-- the distance to the point of contact
it.gradient_x	-- the normalised vector to collision (x)
it.gradient_y	-- the normalised vector to collision (y)

lua.wetgenes.chipmunk.space.query_point_nearest

item = space:query_point_nearest(x,y,d,group,categories,mask)

Find the nearest shape that is within d distance from the point at x,y. Use group,categories and mask to filter the results.

returns a table with the following info or nil for no hit

it.shape		-- the shape
it.point_x		-- the point of contact (x)
it.point_y		-- the point of contact (y)
it.distance		-- the distance to the point of contact
it.gradient_x	-- the normalised vector to collision (x)
it.gradient_y	-- the normalised vector to collision (y)

lua.wetgenes.chipmunk.space.query_segment

array = space:query_segment(sx,sy,ex,ey,r,group,categories,mask)

Find the shapes that are along this raycast segment, from (sx,sy) to (ex,ey) with a radius of r. Use group,categories and mask to filter the results.

Returns an array of hit data, with each item containing the following.

it.shape		-- the shape
it.point_x		-- the point of contact (x)
it.point_y		-- the point of contact (y)
it.normal_x		-- the normal at contact (x)
it.normal_y		-- the normal at contact (y)
it.alpha		-- how far along the segment the contact happened (0 to 1)

lua.wetgenes.chipmunk.space.query_segment_first

it = space:query_segment_first(sx,sy,ex,ey,r,group,categories,mask)

Find the shapes that are along this raycast segment, from (sx,sy) to (ex,ey) with a radius of r. Use group,categories and mask to filter the results.

Returns a table with the following info or nil for no hit

it.shape		-- the shape
it.point_x		-- the point of contact (x)
it.point_y		-- the point of contact (y)
it.normal_x		-- the normal at contact (x)
it.normal_y		-- the normal at contact (y)
it.alpha		-- how far along the segment the contact happened (0 to 1)

lua.wetgenes.chipmunk.space.query_shape

array = space:query_shape(shape)

Find the shapes that intersect with the given shape.

Returns an array of hit data, with each item containing the following.

it.shape		-- the shape
it.normal_x		-- the normal at contact (x)
it.normal_y		-- the normal at contact (y)
it.contacts		-- array of contact points -> {ax,ay,bx,by,distance,etc...}

lua.wetgenes.chipmunk.space.reindex

space:reindex(shape)
space:reindex(body)
space:reindex()

Reindex the shapes, either a specific shape, all the shapes in a body or just all the static shapes.

lua.wetgenes.chipmunk.space.remove

space:remove(body)
space:remove(shape)
space:remove(constraint)

Remove a body/shape/constraint from this space.

lua.wetgenes.chipmunk.space.sleep_time_threshold

v=space:sleep_time_threshold()
v=space:sleep_time_threshold(v)

Get and/or Set the sleep time threshold for this space.

lua.wetgenes.chipmunk.space.step

space:step(time)

Run the simulation for time in seconds. EG 1/60.

lua.wetgenes.chipmunk.space.type

number = space:type(name)
name = space:type(number)

Manage collision types, pass in a string and always get a number out. This number is consistent only for this space.

Alternatively pass in a number and get a string or nil as a result.

lua.wetgenes.csv

local wcsv = require("wetgenes.csv")

Load and save csv, prefrably using tab sperators.

The following need to be escaped with a \ when used in each column.

\n for newline,
\t for tab,
\r for carriage return,
\\ for backslash.

and when using commas a , must be placed inside a quoted string with a double "" to escape " within this string.

This is intended for "small" csv files that fit in memory so does not stream or try and do anything clever to reduce memory overheads.

lua.wetgenes.csv.build

Build csv data into a string from a simple table of lines where each line is a table of cells.

text = wcsv.build(lines)
text = wcsv.build(lines,opts)

lua.wetgenes.csv.doquote

Wrap a string in quotes and escape any " within that string using csv rules.

lua.wetgenes.csv.map

Use the first line to map all other lines into named keys, an empty string will map to nil. This will return an array of items that is smaller than the array of lines by at least one as we also trim trailing empty objects.

items = wcsv.map(lines)
items = wcsv.map(wcsv.parse(text))

lua.wetgenes.csv.parse

Parse csv data from a chunk of text. Returns a simple table of lines where each line is a table of cells. An empty or missing string indicates an empty cell. The second return can be ignored or used to build a csv in a similar format to the one we read.

lines,opts = wcsv.parse(text)
lines,opts = wcsv.parse(text,opts)

Opts can be used to control how the parsing is performed pass in a seperator value to contol how a line is split.

lines,opts = wcsv.parse(text,{seperator=","})

Note that we also return the seperator we used within the second return and will guess the right one using the first line if one is not given.

lua.wetgenes.csv.unquote

Remove quotes from a strine and unescape any "" within that string. If the string is not in quotes then we return it as is.

lua.wetgenes.deepcompare

deepcompare(a,b)

Returns true if a==b , this iterates and recurses into tables.

lua.wetgenes.deepcopy

deepcopy(tab)

Create and return a new table containing the same data as the input. If any of the table values (not keys) are tables then these are also duplicated, recursively.

If this is called with a value that is not a table then that value is just returned so it's safe to call on values without checking them.

lua.wetgenes.export

... = wetgenes.export(table,...)

Export multiple names from this table as multiple returns, can be used to pull functions out of this module and into locals like so

local export,lookup,deepcopy=require("wetgenes"):export("export","lookup","deepcopy")

Or copy it into other modules to provide them with the same functionality.

M.lookup=require("wetgenes").lookup

lua.wetgenes.gamecake.framebuffers

Deal with FrameBuffers as render targets and textures. Color and Depth buffers need to be allocated and managed.

So we need to be baked within an oven so we will talk about the return from the bake function rather than the module function.

local framebuffers=oven.rebake("wetgenes.gamecake.framebuffers")

local fbo=framebuffers.create(256,256,0)	-- a 256x256 texture only
local fbo=framebuffers.create(256,256,-1)	-- a 256x256 depth only
local fbo=framebuffers.create(256,256,1)	-- a 256x256 texture and depth
local fbo=framebuffers.create()				-- 0x0 and we will resize later

lua.wetgenes.gamecake.framebuffers.create

local fbo=framebuffers.dirty()
local fbo=framebuffers.dirty(x,y)
local fbo=framebuffers.dirty(x,y,framebuffers.NEED_TEXTURE_AND_DEPTH)
local fbo=framebuffers.dirty(0,0,0,{
    depth_format={gl.DEPTH_COMPONENT32F,gl.DEPTH_COMPONENT,gl.FLOAT},
    texture_format={gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE},
    TEXTURE_MIN_FILTER=gl.LINEAR,
    TEXTURE_MAG_FILTER=gl.LINEAR,
    TEXTURE_WRAP_S=gl.CLAMP_TO_EDGE,
    TEXTURE_WRAP_T=gl.CLAMP_TO_EDGE,
}) -- note this table will be returned as the fbo

Create a new framebuffer object and optionally provide an inital size and depth. The depth can use -1,0,1 or the following verbose flags framebuffers.NEED_DEPTH,framebuffers.NEED_TEXTURE or framebuffers.NEED_TEXTURE_AND_DEPTH to request a depth buffer(1,-1) or not(0).

Finally you can pass in a table to be returned as the fbo that contains defaults or set defaults in the fbo that is returned.

fbo.depth_format={gl.DEPTH_COMPONENT32F,gl.DEPTH_COMPONENT,gl.FLOAT}

Can be used to control exactly how a depth buffer is allocated with gl.TexImage2D when you care about that sort of thing, IE hardware issues.

fbo.texture_format={gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE}

Can be used to control exactly how a texture buffer is allocated with gl.TexImage2D when you care about that sort of thing, IE hardware issues.

fbo.TEXTURE_MIN_FILTER=gl.LINEAR
fbo.TEXTURE_MAG_FILTER=gl.LINEAR
fbo.TEXTURE_WRAP_S=gl.CLAMP_TO_EDGE
fbo.TEXTURE_WRAP_T=gl.CLAMP_TO_EDGE

These can be used to control default TexParameters in the fbo.

fbo.no_uptwopow=true

By deafult we will use power of 2 sizes for the fbo that fit the requested size. This disables that and doing so will of course cause problems with some hardware. Generally if you avoid mipmaps it probably wont be a problem.

See #lua.wetgenes.gamecake.framebuffers.fbo for all the functions you can call on the fbo returned.

lua.wetgenes.gamecake.framebuffers.dirty

framebuffers.dirty()

Mark all framebuffer objects as dirty by setting fbo.dirty to be true. We do not do anything with this flag but it is used in external code and this is a useful helper function to set the flag.

lua.wetgenes.gamecake.framebuffers.fbo.bind_depth

fbo:bind_depth()

BindTexture the depth texture part of this fbo.

If there is no texture we will bind 0.

lua.wetgenes.gamecake.framebuffers.fbo.bind_depth_snapshot

fbo:bind_depth_snapshot()

BindTexture the depth snapshot texture part of this fbo.

If there is no snapshot texture we will bind 0.

lua.wetgenes.gamecake.framebuffers.fbo.bind_frame

fbo:bind_depth()

BindFramebuffer the framebuffer of this fbo.

If there is no framebuffer we will bind 0.

lua.wetgenes.gamecake.framebuffers.fbo.bind_texture

fbo:bind_texture()

BindTexture the rgba texture part of this fbo.

If there is no texture we will bind 0.

lua.wetgenes.gamecake.framebuffers.fbo.bind_texture_snapshot

fbo:bind_texture_snapshot()

BindTexture the rgba snapshot texture part of this fbo.

If there is no snapshot texture we will bind 0.

lua.wetgenes.gamecake.framebuffers.fbo.check

fbo:check()

Check and allocatie if missing and needed (eg depth texture may not be needed) all our openGL buffers.

lua.wetgenes.gamecake.framebuffers.fbo.download

fbo:download()
fbo:download(w,h,x,y)

Read back color data from a framebuffer and return it in an RGBA PREMULT grd object (which is probably what it is).

If a width,height is given then we will read the given pixels only from the x,y location.

lua.wetgenes.gamecake.framebuffers.fbo.free_depth

fbo:free_depth()

Free the depth texture only, is safe to call if there is no depth buffer.

lua.wetgenes.gamecake.framebuffers.fbo.free_frame

fbo:free_frame()

Free the frame buffer only, is safe to call if there is no frame buffer.

lua.wetgenes.gamecake.framebuffers.fbo.free_snapshot

fbo:free_snapshot()

Free the snapshot buffers, fbo.texture_snapshot and fbo.depth_snapshot if they exist.

lua.wetgenes.gamecake.framebuffers.fbo.free_texture

fbo:free_texture()

Free the rgba texture only, is safe to call if there is no rgba buffer.

lua.wetgenes.gamecake.framebuffers.fbo.mipmap_depth

fbo:mipmap_depth()

Build mipmaps for our depth buffer if it exists and set TEXTURE_MIN_FILTER to LINEAR_MIPMAP_LINEAR so it will be used.

It is possible this may fail (hardware issues) and the TEXTURE_MIN_FILTER be reset to gl.NEAREST along with a flag to stop us even trying in the future,

lua.wetgenes.gamecake.framebuffers.fbo.mipmap_texture

fbo:mipmap_texture()

Build mipmaps for our texture buffer if it exists and set TEXTURE_MIN_FILTER to LINEAR_MIPMAP_LINEAR so it will be used.

lua.wetgenes.gamecake.framebuffers.fbo.pingpong

fbo:pingpong(fbout,shadername,callback)
framebuffers.pingpong({fbin1,fbin2},fbout,shadername,callback)

Render from one or more fbos into another using a fullscreen shader.

Sometime you need to repeatedly copy a texture back and though applying a shader, this is the function for you.

The textures will be bound to tex1,tex2,tex3,etc and the uvs supplied in a_texcoord with a_vertex being set to screen coords so can be used as is.

lua.wetgenes.gamecake.framebuffers.fbo.render_start

fbo:render_start()


Start rendering into this fbo.

Push old matrix and set the matrix mode to MODELVIEW

Set fbo.view and reset the gl state.

lua.wetgenes.gamecake.framebuffers.fbo.render_stop

fbo:render_stop()

Stop rendering into this fbo and restore the last fbo so these calls can be nested.

Restore the old view and old gl state.

Pop old matrix and set the matrix mode to MODELVIEW

lua.wetgenes.gamecake.framebuffers.fbo.resize

fbo:resize(w,h,d)

Change the size of our buffers, which probably means free and then reallocate them.

The w,h,d use the same rules as framebuffer.create

lua.wetgenes.gamecake.framebuffers.fbo.snapshot

fbo:snapshot()

Take a current snapshot copy of the texture and depth if they exist, store them in fbo.texture_snapshot and fbo.depth_snapshot for later binding.

lua.wetgenes.gamecake.framebuffers.start

framebuffers.start()

Called as part of the android life cycle, since we auto reallocate this does not actually have to do anything. But may do a forced resize in the future if that turns out to be more hardware compatible.

lua.wetgenes.gamecake.framebuffers.stop

framebuffers.stop()

Called as part of the android life cycle, we go through and call fbo.clean on each fbo to free the opengl resources.

lua.wetgenes.gamecake.fun.chatdown.chat.get_tag

tag_value = chat:get_tag(tag_name)

The same as chats:get_tag but the subject of this chat is the default root.

lua.wetgenes.gamecake.fun.chatdown.chat.replace_tags

output = chat:replace_tags(input)

The same as chats:replace_tags but the subject of this chat is the default root.

lua.wetgenes.gamecake.fun.chatdown.chat.set_tag

tag_value = chat:set_tag(tag_name,tag_value)

The same as chats:set_tag but the subject of this chat is the default root.

lua.wetgenes.gamecake.fun.chatdown.chat.set_tags

chat:set_tags(tags)

Set all the values in the given table of {tag_name=tag_value} pairs.

lua.wetgenes.gamecake.fun.chatdown.chat.set_topic

chat:set_topic(topic_name)

Set the current topic for this chat object, information about this topic and its gotos are built from and stored in this chat object.

chat.topic_name

Will be set to the given topic name.

We merge all gotos found in this topic and all topic parents by iterating over the dotnames. We only use add each topic once and each topic may have a bit of logic that decides if it should be displayed.

<topic_name?logic_test

So this would goto the topic_name if the logic_test passes. The logic test is written simmilar to a url query after the question mark comes a number of tests that are then & or | together in left to right order (no operator precedence).

<topic_name?count<10&seen==false

So this would display the goto option if count is less than 10 and seen is set to false. These variables we are testing are tag_names and default to the current subject chat but could reference other subjects by explicitly including a root.

Available logic tests are

name==value
name=value

True if the tag is set to this value.

name!=value

True if the tag is not set to this value.

name<value

True if the tag is less than this value (numeric test).

name>value

True if the tag is more than this value (numeric test).

name<=value

True if the tag is less than or equal to this value (numeric test).

name>=value

True if the tag is more than or equal to this value (numeric test).

All of these tests can be preceded by a ! to negate them so

name!=vale
!name==value

Are both a test for inequality.

Multiple tests can be joined together by & (and) or | (or) this logic will be applied to a running total moving from left to right as the values are evaluated with the final value deciding if this goto will be displayed.

lua.wetgenes.gamecake.fun.chatdown.chats.changes

chats.changes(chat,change,...)

chats.changes(chat,"subject")
chats.changes(chat,"topic",topic)
chats.changes(chat,"goto",goto)
chats.changes(chat,"tag",tag_name,tag_value)

This is a callback hook, replace to be notified of changes and possibly alter then, by default we print debuging information. Replace this function with an empty function to prevent this eg

chats.changes=function()end

lua.wetgenes.gamecake.fun.chatdown.chats.get_subject

chat = chats:get_subject(subject_name)
chat = chats:get_subject()

Get the chat for the given subject or the chat for the last subject selected with set_subject if no subject_name is given.

lua.wetgenes.gamecake.fun.chatdown.chats.get_tag

tag_value = chats:get_tag(tag_name,subject_name)

Get the tag_value for the given tag_name which can either be "tag_root/tag_name" or "tag_name". The subject_name is the default root to use if no tag_root is given in the tag_name.

lua.wetgenes.gamecake.fun.chatdown.chats.replace_tags

output = chats:replace_tags(input,subject_name)

Tags in the input text can be wrapped in {tag_name} and will be replaced with the appropriate tag_value. This is done recursively so tag_values can contain references to other tags. If a tag does not exist then it will not expand and {tag_name} will remain in the output text.

Again if any tag name does not contain an explicit root then subject_name will be used as the default chat subject.

lua.wetgenes.gamecake.fun.chatdown.chats.set_subject

chat = chats:set_subject(subject_name)

Set the current subject for this chats object, this subject becomes the chat that you will get if you call get_subject with no arguments.

lua.wetgenes.gamecake.fun.chatdown.chats.set_tag

tag_value = chats:set_tag(tag_name,tag_value,subject_name)

Alter the value of the given tag_name. If the value string begins with a "+" or a "-" Then the values will be treated as numbers and added or subtracted from the current value. This allows for simple incremental flag values.

Again if the tag name does not contain an explicit root then subject_name will be used as the default chat subject.

lua.wetgenes.gamecake.fun.chatdown.dotnames

for part_name in chatdown.dotnames(full_name) do
    print(part_name)
end

Iterate all dotnames so if given "aa.bb.cc" we would iterate through "aa.bb.cc" , "aa.bb" and "aa". This is used to inherit data using just a naming convention.

lua.wetgenes.gamecake.fun.chatdown.parse

rawsubjects = chatdown.parse(text)

Parse text from flat text chatdown format into heirachical chat data, which we refer to as rawsubjects, something that can be output easily as json.

This gives us a readonly rawsubjects structure that can be used to control what text is displayed during a chat session.

This is intended to be descriptive and logic less, any real logic should be added using a real language that operates on this rawsubjects and gets triggered by the names used. EG, filter out gotos unless certain complicated conditions are met or change topics to redirect to an alternative.

A self documented example of chatdown formated text can be found in lua.wetgenes.gamecake.fun.chatdown.text

lua.wetgenes.gamecake.fun.chatdown.setup

chats = chatdown.setup_chats(chat_text,changes)

parse and initialise state data for every subjects chunk creating a global chats with a chat object for each subject.

lua.wetgenes.gamecake.fun.chatdown.setup_chat

chat = chatdown.setup_chat(chats,subject_name)

Setup the initial chat state for a subject. This is called automatically by chatdown.setup and probably should not be used elsewhere.

lua.wetgenes.gamecake.fun.chatdown.text

Here is some example chatdown formatted text full of useful information, it it is intended to be a self documented example.


- This is a single line comment
-- This is the start of a multi-line comment

All lines are now comment lines until we see a line that begins with a 
control character leading white space is ignored. If for some reason 
you need to start a text line with a special character then it can be 
escaped by preceding it with a #

What follows is a list of these characters and a brief description 
about the parser state they switch to.

    1. - (text to ignore)
    
        A single line comment that does not change parser state and 
        only this line will be ignored so it can be inserted inside 
        other chunks without losing our place.

    2. -- (text to ignore)
    
        Begin a comment chunk, this line and all lines that follow this 
        line will be considered comments and ignored until we switch to 
        a new parser state.

    3. #subject_name

        Begin a new subject chunk, all future topic,goto or tag chunks will 
        belong to this subject.
        
        The text that follows this until the next chunk is the long 
        description intended for when you examine the character.
        
        Although it makes sense for a subject chunk to belong to one 
        character it could also a group conversation with tags being 
        set to change the current talker as the conversation flows.
        
        subject names have simple cascading inheritance according to their 
        name with each level separated by a dot. A chunk named a.b.c 
        will inherit data from any chunks defined for a.b and a in that 
        order of priority.

    4. >topic_name
    
        Begin a topic chunk, all future goto or tag chunks will belong 
        to this topic, the lines that follow are how the character 
        responds when questioned about this topic followed by one or 
        more gotos as possible responses that will lead you onto 
        another topic.
        
        Topics can be broken into parts, to create a pause, by using an 
        unnamed goto followed by an unnamed topic which will both 
        automatically be given the same generated name and hence linked 
        together.
        
    5. <goto_topic_name
    
        Begin a goto chunk, all future tag chunks will belong to this 
        goto, this is probably best thought of as a question that will 
        get a reply from the character. This is a choice made by the 
        player that causes a logical jump to another topic.
        
        Essentially this means GOTO another topic and there can be 
        multiple GOTO options associated with each topic which the 
        reader is expected to choose between.
        
    6. =set_tag_name to this value
    
        If there is any text on the rest of this line then it will be 
        assigned to the tag without changing the current parse state so 
        it can be used in the middle of another chunk without losing 
        our place.
        
        This single line tag assignment is usually all you need. 
        Alternatively, if there is no text on the rest of this first 
        line, only white space, then the parse state will change and 
        text on all following lines will be assigned to the named tag.
        
        This assignment can happen at various places, for instance if 
        it is part of the subject then it will be the starting 
        value for a tag but if it is linked to a topic or goto then the 
        value will be a change as the conversation happens. In all 
        cases the tags are set in a single batch as the state changes 
        so the placement and order makes no difference.
        
        Tags can be used inside text chunks or even GOTO labels by 
        tightly wrapping with {} eg {name} would be replaced with the 
        value of name. Tags from other subjects can be referenced by 
        prefixing the tag name with the subject name followed by a forward 
        slash like so {subject/tag}
                

The hierarchy of these chunks can be expressed by indentation as all 
white space is ignored and combined into a single space. Each SUBJECT will 
have multiple TOPICs associated with it and each TOPIC will have 
multiple GOTOs as options to jump between TOPICs. TAGs can be 
associated with any of these 3 levels and will be evaluated as the 
conversation flows through these points.

So the chunk hierarchy expressed using indentation to denote children 
of.

    SUBJECT
        TAG
        GOTO
            TAG
        TOPIC
            TAG
            GOTO
                TAG

The GOTO chunks in the root SUBJECT chunk are used as prototypes so if a 
GOTO is used in multiple topics its text can be placed within a GOTO 
inside the main SUBJECT chunk rather than repeated constantly. This will 
then be inherited by a GOTO with no text. An alternative to this 
shorthand is to assign an oft-used piece of text to a tag and reference 
that in each topic instead.

SUBJECTs and TOPICs also have simple inheritance based on their names this 
enables the building of a prototype which is later expanded. Each 
inheritance level is separated by a dot so aa.bb.cc will inherit from 
aa.bb and aa with the data in the longer names having precedence. This 
inheritance is additive only so for instance a TAG can not be unset and 
would have to be changed to another value by aa.bb.cc if it existed in 
aa.bb or aa.

In practise this means
<br/>
<br/>

lua.wetgenes.gamecake.fun.yarn.cells

cells = require("wetgenes.gamecake.fun.yarn.cells").create(items)

This module contains only one function which can be used to create an cells instance and the rest of this documentation concerns the return from this create function, not the module itself.

lua.wetgenes.gamecake.fun.yarn.items

items = require("wetgenes.gamecake.fun.yarn.items").create()

This module contains only one function which can be used to create an items instance and the rest of this documentation concerns the return from this create function, not the module itself.

lua.wetgenes.gamecake.fun.yarn.items.cells

items.cells

We automatically create a cells object bound to this set of items, this cells object should be used to define all your custom game cells.

lua.wetgenes.gamecake.fun.yarn.items.create

item = items.create()
item = items.create({})
item = items.create({},metatable)

Create a single item, optionally pass in a base item table that will be turned into a proper item (using setmetatable to add methods). This should always be a new table and will also be returned. If no metatable is provided then items.metatable will be used.

lua.wetgenes.gamecake.fun.yarn.items.create_pages

items.pages

We automatically create a pages object bound to this set of items, this pages object should be used to define all your custom game pages.

This can be considered a level and you may need multiple pages which are moved in and out of items.pages

lua.wetgenes.gamecake.fun.yarn.items.destroy

item = items.destroy(item)
item = item:destroy()

Destroy an item, remove it from the master table dump so it will be garbage collected.

lua.wetgenes.gamecake.fun.yarn.items.find

child_item = item:find(keyname)

Get the first child item that has a [keyname] value in it. All child items are searched, but this is not recursive.

returns nil if no child item is found.

lua.wetgenes.gamecake.fun.yarn.items.get_big

big_item = item:get_big()

Get the first big item from this container, returns nil if we do not contain a big item.

lua.wetgenes.gamecake.fun.yarn.items.insert

item = item:insert(parent)

Insert this item into the given parent. Item will automatically be removed from its current parent. If the item is_big then it will be inserted into the front of the list otherwise it will go at the end. This is to help with finding big items, since there should only be one per container we only have to check the first child.

lua.wetgenes.gamecake.fun.yarn.items.iterate_dotnames

for name,tail in items.iterate_dotnames(names) do ... end

Iterator over a names string, start with the full string and cut off the tail on each iteration. This is used for simple inheritance merging of named prefabs and rules or anything else.

Second return value is the tail of the string or the string if not tail.

for example the following input string

"one.two.three.four"

would get you the following iteration loops, one line per loop

"one.two.three.four" , "four"
"one.two.three"      , "three"
"one.two"            , "two"
"one"                , "one"

lua.wetgenes.gamecake.fun.yarn.items.iterate_parents

for it in item:iterate_parents() do
    ...
end

Iterate over the parent chain going upwards. The first iteration is the parent of this object and so on.

lua.wetgenes.gamecake.fun.yarn.items.prefabs

items.prefabs

We automatically create a prefabs object bound to this set of items, this prefabs object should be used to define all your custom game prefabs.

lua.wetgenes.gamecake.fun.yarn.items.remove

item = item:remove()

Remove this item from its parents table or do nothing if the item does not have a parent.

lua.wetgenes.gamecake.fun.yarn.items.rules

items.rules

We automatically create a rules object bound to this set of items, this rules object should be used to define all your custom game rules.

lua.wetgenes.gamecake.fun.yarn.pages

pages = require("wetgenes.gamecake.fun.yarn.pages").create(items)

This module contains only one function which can be used to create an pages instance and the rest of this documentation concerns the return from this create function, not the module itself.

lua.wetgenes.gamecake.fun.yarn.prefabs

prefabs = require("wetgenes.gamecake.fun.yarn.prefabs").create(items)

This module contains only one function which can be used to create an prefabs instance and the rest of this documentation concerns the return from this create function, not the module itself.

lua.wetgenes.gamecake.fun.yarn.prefabs.set

prefab = prefabs:get(name)
prefab = prefabs:get(name,prefab)

Build and return a table with all prefab values inherited from all its parents. Optionally pass in a prefab to override values and also have it returned.

If name doesn't exist at any level and a table is not passed in then nil will be returned.

Names are hierarchical, separated by dots, see items.iterate_dotnames

lua.wetgenes.gamecake.fun.yarn.rules

rules = require("wetgenes.gamecake.fun.yarn.rules").create(items)

This module contains only one function which can be used to create an rules instance and the rest of this documentation concerns the return from this create function, not the module itself.

lua.wetgenes.gamecake.fun.yarn.rules.apply

item = rules.apply(item,method,...)

item.rules must be a list of rule names and the order in which they should be applied to this item.

Call the given method in each rule with the item and the remaining arguments.

If the method returns a value then no more methods will be applied even if more rules are listed.

We always return the passed in item so that calls can be chained.

item = item:apply(method,...)

This function is inserted into the items.metatable so it can be called directly from an item.

lua.wetgenes.gamecake.fun.yarn.rules.can

yes = rules.can(item,method)

Returns true if any rule in this item has the given method.

yes = item:can(method)

This function is inserted into the items.metatable so it can be called directly from an item.

lua.wetgenes.gamecake.fun.yarn.rules.set

rule = rules.set(rule)

Set this base rule into the name space using rule.name which must be a string.

Multiple rules can be applied to an item and each rule will be applied in the order listed.

A rule is a table of named functions that can be applied to an item.

rule.setup(item)

Must setup the item so that it is safe to call the other rules on it.

rule.clean(item)

Should cleanup anything that needs cleaning.

rule.tick(item)

Should perform a single time tick update on the item.

lua.wetgenes.gamecake.oven

oven=require("wetgenes.gamecake.oven").bake(opts)

The oven module must be baked so only exposes a bake function.

All the other functions are returned from within the bake function.

possible ENV settings

gamecake_tongue=english
gamecake_flavour=sdl

lua.wetgenes.gamecake.oven.bake

oven=wetgenes.gamecake.oven.bake(opts)

Bake creates an instance of a lua module bound to a state. Here we are creating the main state that other modules will then bind to.

We call each state an OVEN to fit into the gamecake naming scheme then we bake a module in this oven to bind them to the common state.

Think of it as a sub version of require, so require gets the global pointer for a module and bake is used to get the a module bound to an oven.

By using this bound state we reduce the verbosity of connecting modules and sharing state between them.

lua.wetgenes.gamecake.toaster

oven=require("wetgenes.gamecake.toaster").bake(opts)

A cut down oven without opengl or even file access intended to be used in a sub process or task.

lua.wetgenes.gamecake.toaster.bake

oven=wetgenes.gamecake.toaster.bake(opts)

Bake creates an instance of a lua module bound to an oven state. Here we are creating the main state that other modules will then bind to.

Modules are then bound together using rebake...

b=oven.rebake(nameb)
c=oven.rebake(namec)

All of these will be connected by the same oven and circular dependencies should work with the caveat that just because you have the table for a baked module does not mean that it has all been filled in yet.

lua.wetgenes.gamecake.toaster.newticks

ticks=require("wetgenes.gamecake.toaster").newticks(rate,jump)

create a ticks time controller for updates.

rate is time between steps , jump is how far behind we should get before giving up ( eg callback takes longer than rate allows ) these values are in seconds and default to 1/60 and 1 respectively.

Then we perform one or more update steps like so

ticks.step( callback ) -- callback may be called zero or more times

After that we should wait a bit (maybe draw a frame) and then call again.

lua.wetgenes.gamecake.widgets

local widgets=oven.rebake("wetgenes.gamecake.widgets")

A collection of widgets, rendered using gles2 code and controlled using the mouse, keyboard or a joystick. EG click fire and move left/right to adjust a slider value.

Widgets must be created and bound to an oven, using the oven.rebake function.

This has undergone a number of rewrites as we try to simplify the widget creation and layout process. Eventually we ended up with a fixed size system of widget placement so every widget must have a known size in advance, however we allow scaling to occur so for instance building a 256x256 widget does not mean that it has to be displayed at 256x256 it just means it will be square.

The basic layout just lets you place these widgets in other widgets as left to right lines. So as long as you get your sizes right you can easily place things just using a list and without keeping track of the current position.

Other layout options are available, such as absolute positioning for full control and we have simple custom skin versions of the buttons as well rather than the built in skins.

All value data is handled by data structures that contain ranges and resolutions for data allowing the same data to be bound to multiple display widgets. For instance the same data can be linked to the position of a slider as well as the content of a text display. I think the kids call this sort of thing an MVC pattern but that's a terribly dull name.

Swanky paint is probably the most advanced used of the widgets so far but I suspect we will be making a simple text editor in the near future. Designed for advanced in game tweaking of text files.

lua.wetgenes.gamecake.widgets.button

local master=oven.rebake("wetgenes.gamecake.widgets").setup()
local widget=master:add{class="button",...}

A button for pressing and such.

lua.wetgenes.gamecake.widgets.button.setup

see lua.wetgenes.gamecake.widgets.meta.setup for generic options

As a button we always need to be solid so this is forced to true.

Also cursor will be set to "hand" if it is not already set so you can tell it is a button when you hover over it.

lua.wetgenes.gamecake.widgets.button.update

this function will also call lua.wetgenes.gamecake.widgets.meta.update

If we have a data assigned to this button then make sure that the displayed text is up to date. We should really hook into the data so any change there is copied here instead?

lua.wetgenes.gamecake.widgets.center

local master=oven.rebake("wetgenes.gamecake.widgets").setup()
local widget=master:add{class="center",...}

A layout class for very centered children.

lua.wetgenes.gamecake.widgets.center.layout

this function will also call lua.wetgenes.gamecake.widgets.meta.layout

Place any children in the center of this widget. Multiple children will overlap so probably best to only have one child.

lua.wetgenes.gamecake.widgets.center.setup

see lua.wetgenes.gamecake.widgets.meta.setup for generic options

If not explicetly set we will use a size of "full" ie the size of parent as that is probably how this class will always be used.

lua.wetgenes.gamecake.widgets.checkbox

local master=oven.rebake("wetgenes.gamecake.widgets").setup()
local widget=master:add{class="checkbox",...}

A button that can be used to display and toggle a single bit of data.

lua.wetgenes.gamecake.widgets.checkbox.setup

see lua.wetgenes.gamecake.widgets.meta.setup for generic options

As a button we always need to be solid so this is forced to true.

cursor will be set to "hand" if it is not already set so you can tell it is a button when you hover over it.

data_mask defaults to 1 and represents the bit (or bits) that should be tested and toggled in the data. The default of 1 and assuming your data starts at 0 means that the data will toggle between 0 and 1 using this checkbox.

text_false defaults to " " and is the text that will be displayed when a data_mask test is false.

text_true defaults to "X" and is the text that will be displayed when a data_mask test is true.

lua.wetgenes.gamecake.widgets.checkbox.update

this function will also call lua.wetgenes.gamecake.widgets.meta.update

If we have a data assigned to this checkbox then make sure that the displayed text is up to date. We should really hook into the data so any change there is copied here instead?

We use data_mask to check a single bit and then set the text to either text_false or text_true depending on the result.

lua.wetgenes.gamecake.widgets.data

local master=oven.rebake("wetgenes.gamecake.widgets").setup()
local data=master.new_data{}

A number or string that can be shared between multiple widgets given basic limits and watched for changes.

This alows the same data to be linked and displayed in multiple widgets simultaneously.

lua.wetgenes.gamecake.widgets.data.data_snap

given the parents size and our relative position/size within it update dat.num and return a new position (for snapping)

lua.wetgenes.gamecake.widgets.drag

local master=oven.rebake("wetgenes.gamecake.widgets").setup()
local widget=master:add{class="drag",...}

A button to drag arround.

lua.wetgenes.gamecake.widgets.paragraph

local master=oven.rebake("wetgenes.gamecake.widgets").setup()
local widget=master:add{class="paragraph",...}

A layout class for a paragraph of wordwrapped text that ignores quantity of whitespace and possibly child widgets insereted into the text and apropriate control points.

We will be the full width of our parent and as tall as we need to be to fit the given text.

lua.wetgenes.gamecake.widgets.setup

master=oven.rebake("wetgenes.gamecake.widgets").setup()

master=oven.rebake("wetgenes.gamecake.widgets").setup(
    {font="Vera",text_size=16,grid_size=32,skin=0} )

Create a master widget, this widget which is considered the root of your GUI. It will be filled with functions/data and should contain all the functions you need to add data and widgets.

You can pass in these configuration values in a table, the example shown above has soom good defaults.

font="Vera"

The default font to use, this must have already been loaded via wetgenes.gamecake.fonts functions.

text_size=16

The default pixel height to render text at.

grid_size=32

The size in pixels that we try and create buttons at.

lua.wetgenes.gamecake.zone.scene

zone_scene = require("wetgenes.gamecake.zone.scene")

Manage a simple structure to help group, update and draw discrete game objects.

This module contains only one function which can be used to create a scene instance and the rest of this documentation concerns the return from this create function, not the module

scene = zone_scene.create()
scene = zone_scene.create( { sortby={"first","second",...} } )

Create and return a scene object. A base object can be passed in and will be filled in and returned. This can used to supply a sortby table to help control the order of updates of different castes.

If passed in sortby is a table of [caste_name]=weight values to help control the order of updates by caste and make it consistent. For instance you might find it useful to force monsters to update before the player.

lua.wetgenes.gamecake.zone.scene.add

scene:add(it)
scene:add(it,caste)
scene:add(it,caste,boot)

Add a new item of caste or it.caste to the list of things to update.

The optional boot table contains initialisation/reset values and will be remembered in item.boot. If boot.id is given then we will remember this item with a call to scene.set(id,it)

The actual act of initalising the item from the boot table is left to custom code which ideally should initalize it and then just call scene.add(it) as the auto shortcuts are unnecesary.

lua.wetgenes.gamecake.zone.scene.call

scene:call(fname,...)

If fname is a string then that method will be invoked for every item where it exists like so. Only the first item of each caste is tested, if the function exists there then it is expected to exist for all items of a given caste. This enables us to skip entire castes whilst still making all functions optional.

if it[fname] then it[fname](it,...) end

if fname is a function then it will result in every item geting called with that function like so.

fname(it,...)

The calls are always made backwards through the table so that an item can choose to delete itself.

Finally we return the number of calls we made so you can keep track of currently active items.

lua.wetgenes.gamecake.zone.scene.caste

scene:caste(caste)

Get the list of items of a given caste, eg "bullets" or "enemies"

This list will be created if it does not already exist.

scene.sortby is used to keep this list in order and an empty system will be autocreated if needed.

lua.wetgenes.gamecake.zone.scene.find_uid

local it = scene:find_uid( uid )

Return the item with the given uid or nil if no such item has been remembered or a nil uid has been passed in.

lua.wetgenes.gamecake.zone.scene.forget_uid

local it = scene:forget_uid( {uid=uid} )

Remove the item from the map of uids. Returns the item or nil if uid was invalid unset or our map was not pointing to the correct item.

local it = scene:forget_uid( scene.find_uid( uid ) )

Chain with find_uid to forget an item by uid and this is safe even if the item does not exist.

lua.wetgenes.gamecake.zone.scene.generate_uid

local uid = scene:generate_uid()

local uid = scene:generate_uid(uid)

Simple unique incremental IDs for items to be used instead of pointers, starts at 1 and goes up as items are added.

Ideally you will also need extra code for compacting these ids ( probably as an export, renumber, import cycle ) to stop them getting huge and breaking. So a save/load system which is out of scope for this code.

Generally, unless we are creating and destroying millions of items we will run out of memory way before this number gets too big.

If a uid is passed in then we will return uid+1 and continue on upwards for subsequent calls.

The point of uids is so we can refer to and lazy link items as weak values making it easy to delete an item without worrying too much about where it has been used. So instead of putting the item table inside another item table we can use a uid reference instead.

Good for serialising data as well.

lua.wetgenes.gamecake.zone.scene.remember_uid

local it = scene:remember_uid( {} )

Remember an item in the uids table, generating a uid and setting it.uid to this value if one does not already exist.

lua.wetgenes.gamecake.zone.scene.remove

scene:remove(it)

Remove this item, this is slightly expensive as we need to search in a table to find it before calling table.remove which then has to shuffle the table to fill in the hole.

With very dynamic items it can be faster to allocate all the items you need at the start and then flag them on/off rather than add and remove dynamically.

It may make more sense to create a system which handles its own list of objects, such as particles. Then only use the items to keep track of a master particles item that contains many particles and can add/remove/recycle as it sees fit.

lua.wetgenes.gamecake.zone.scene.reset

scene:reset()

Empty the list of items to update and draw, this does not reset the systems table that should be modified with the insert and remove functions.

lua.wetgenes.gamecake.zone.scene.sortby_update

scene:sortby_update(newtab)

A function that takes the array part of newtab and reverses the key=value so a simple order list can be provided without any explicit weights. The first caste name in the array gets a weight of 1, second 2 and so on.

Newtab is coppied into scene.sortby for use a s aweight lookuptable of name to weight.

If newtab is not provided then scene.sortby is used by default.

lua.wetgenes.gamecake.zone.scene.status

print( scene:status() )

Return a debug string giving details about the system order and current number of items of each caste.

lua.wetgenes.gamecake.zone.scene.systems

scene.systems={name=system,[1]=system}

A sorted table and lookup by caste name of each system. Table is sorted so it will be traversed backwards, backwards traversal allows the current item to delete itself.

lua.wetgenes.gamecake.zone.scene.systems.call

scene:systems_call(fname,...)

For every system call the function called fname like so.

system[fname](system,...)

Returns the number of calls made, which will be the number of systems that had an fname function to call.

If fname is a function then it will be called as if it was a method.

lua.wetgenes.gamecake.zone.scene.systems.cocall

scene:systems_cocall(fname,...)

For every system call the function called fname inside a coroutine like so.

system[fname](system,...)

This function can yield and should do so if it is waiting for another system to do something. All coroutines will be run in a round robin style until they all complete.

Returns the number of calls made, which will be the number of systems that had an fname function to call.

If fname is a function then it will be called as if it was a method.

lua.wetgenes.gamecake.zone.scene.systems.insert

scene:systems_insert(system)

Insert a new system replacing any system of the same caste. system.caste should be set to the caste of the system for this to work.

lua.wetgenes.gamecake.zone.scene.systems.remove

system = scene:systems_remove(caste)

Remove and return the system of the given caste.

lua.wetgenes.gamecake.zone.scene.values

zone_scene = require("wetgenes.gamecake.zone.scene")

values = zone_scene.create_values()

Create and return a values object.

This is an array of objects representing the main object in values[1] and future predictions in values[2],values[3] etc etc.

The key values in the higher numbers overide key values in the lower numbers so essentially only changes need to be written into the predicted slots.

lua.wetgenes.gamecake.zone.scene.values.get

value=values:get(key)
value=values:get(key,topidx)

Get the current value for this key by searching from the top of the stack to the bottom and returning the first non nil value we find.

If topidx is given then get the value at this idx, this would normally be negative in which it counts back from the end. So it is easy to time travel back a frame into the cached values with -1 as the idx.

lua.wetgenes.gamecake.zone.scene.values.manifest

value=values:manifest(key,value)

Get the current value for this key if there is no current value then set the current value.

This uses values:get and values:set to perform these actions.

lua.wetgenes.gamecake.zone.scene.values.new

values2 = values:new()

Create and return a new values object with a single slot containing an empty object.

lua.wetgenes.gamecake.zone.scene.values.push

values:push()

Add a new slot to the end of the values array. Future values will be writen into this new slot.

lua.wetgenes.gamecake.zone.scene.values.set

values:set(key,value)

If this is different from the current value then write the value into the key of the object at the top of the stack. Hence future gets will get this new value.

lua.wetgenes.gamecake.zone.scene.values.tween

value=values:tween(key,tween)

Tween between the current value(1) and the previous value(0).

A tween of 0 gets the previous value, a tween of 1 gets the current value and any other tween will get a mix between the two if that is possible.

We can only mix numbers or tardis values, other values will round to either 0 or 1 whichever is closest and then get that whole value.

lua.wetgenes.gamecake.zone.scene.values.twrap

value=values:twrap(key,nmax,tween)

Tween wrap between the current value and the previous value.

Result will be in rang of 0>= n <nmax , blended in the shortest direction.

nmax may be a number or a tardis value for nmax per dimension

A tween of 0 gets the previous value, a tween of 1 gets the current value and any other tween will get a mix between the two if that is possible.

We can only mix numbers or tardis values, other values will round to either 0 or 1 whichever is closest and then get that whole value.

lua.wetgenes.gamecake.zone.system.items

Generic game objects, IE things that exist in game and can be interacted with by the players.

Some times these exist in world, sometimes they exist in bags or inventory etc so are not visible world objects.

As such this item always exists here and will be moved in and out of world objects as necessary.

lua.wetgenes.grd

local wgrd=require("wetgenes.grd")

We use wgrd as the local name of this library.

Handle bitmap creation, loading, saving and blitting. The bitmap and the colormap for indexed bitmaps are represented by the same data structure which describes a continuous chunk of memory with optional ability to select an area of a larger chunk using simple byte spans.

Swanky Paint uses this to manage its bitmaps and its also used to convert art into data at build time for use in the GameCake engine. The PageCake engine uses this for image management, creating live thumbnails and so on.

We load and save jpeg, png and gif. The png lib contains extensions for apng which allows animation chunks. Animations are contained in the Z (depth) dimension of the grd.

The following are possible format options that we support. Most of them are OpenGL friendly.

wgrd.FMT_U8_RGBA

32 bits per pixel with a byte order of red, green, blue, alpha and a little endian U32 of ABGR. We prefer this byte order because OpenGL.

wgrd.FMT_U8_ARGB

32 bits per pixel with a byte order of alpha, red, green, blue and a little endian U32 of BGRA.

wgrd.FMT_U8_RGB

24 bits per pixel with a byte order of red, green, blue.

wgrd.FMT_U8_INDEXED

8 bits per pixel which indexes a wgrd.FMT_U8_RGBA palette.

wgrd.FMT_U8_LUMINANCE

8 bits per pixel, grey scale only.

wgrd.FMT_U8_ALPHA

8 bits per pixel, alpha only.

wgrd.FMT_U16_RGBA_5551

16 bits per pixel with 5 bits each of red,green,blue and 1 bit of alpha packed into a single U16.

wgrd.FMT_U16_RGBA_4444

16 bits per pixel with 4 bits each of red,green,blue,alpha packed into a single U16.

wgrd.FMT_U16_RGBA_5650

16 bits per pixel with 4 bits of red, 5 bits of green and 4 bits of blue packed into a single U16.

wgrd.FMT_U8_RGBA_PREMULT
wgrd.FMT_U8_ARGB_PREMULT
wgrd.FMT_U8_INDEXED_PREMULT
wgrd.FMT_U16_RGBA_5551_PREMULT
wgrd.FMT_U16_RGBA_4444_PREMULT
wgrd.FMT_U16_RGBA_5650_PREMULT

Are all just pre-multiplied alpha versions of the base format described above.

Check this link out for why pre-multiplied alpha is a good idea for any image that will be used as a texture http://blogs.msdn.com/b/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx

wgrd.GRD_FMT_HINT_PNG
wgrd.GRD_FMT_HINT_JPG
wgrd.GRD_FMT_HINT_GIF

These are used to choose a specific file format when loading or saving.

lua.wetgenes.grd.adjust_contrast

ga:adjust_contrast(sub,con)

sub is the middle grey value, probably 127, and con is the amount of contrast.

A con of 0 should have no effect, a con of -1 will be a flat grey and a con of 1 will give a huge contrast increase.

lua.wetgenes.grd.adjust_hsv

ga:adjust_hsv(hue,saturation,value)

Add hue and adjust -1 to +1 in for saturation and value.

lua.wetgenes.grd.adjust_rgb

ga:adjust_rgb(red,green,blue)

Adjust -1 to +1 in for each RGB component.

lua.wetgenes.grd.attr_redux

g:attr_redux(cw,ch,num,sub,bak)

Perform attribute clash simulation on an indexed image.

cw,ch are the width and height of each character we are simulating, 8x8 is the right size for spectrum attrs but could be 4x8 for c64 multicolor mode.

num is the number of colors allowed within this area, so 2 for spectrum mode.

sub is the size of sub pallete groups, eg 16 in nes mode or 8 in spectrum mode, EG bright simulation in spectrum mode requires all colors in a attr block to be from the bright palette or the dark palette no mixing so this forces that grouping. Set to 0 or 256 and this restriction will be disabled.

bak is the index of the background color that is shared across all characters, set to -1 if there is no shared background color.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.blit

g:blit(gb,x,y,cx,cy,cw,ch)

Blit a 2D area from one grd into another.

gb is the grd to blit from.

x,y is the location to blit too.

cx,cy,cw,ch is a clip area that should be applied to gb before it is blitted. EG to specify an area within gb. If not provided it will default to the entirety of gb,

g (destination) must be FMT_U8_RGBA and gb (source) must be FMT_U8_RGBA_PREMULT this function will blend the images using normal alpha blending.

This is not overly optimised but should be reasonably fast.

lua.wetgenes.grd.clear

g:clear(color)

Fill this grd with a single color, the color passed in depends on the format of the grd, it could be an index value for 8bit images or a 32bit value for rgba images.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.clip

gr=g:clip(x,y,z,w,h,d)

create a clipped window into this grd

the actual data is still stored in the original, so any changes there will effect the newly returned grd

x,y,z are the staring pixel and w,h,d are the width height and depth in pixels.

If you intend to use this clipped area for an extended period of time then you should duplicate this grd once you do this.

This returns a new grd with gr.parent set to g (the original grd)

This is a very shallow dangerous copy and should only really be used for temporary actions.

lua.wetgenes.grd.convert

g:convert(fmt)

Convert this grd to a new format, eg start with an 8 bit indexed grd and convert it to 32 bit like by passing in wgrd.FMT_U8_RGBA as the fmt.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.copy_data

g:copy_data(gb)

Copy all of the bitmap data from gb into g.

lua.wetgenes.grd.copy_data_layer

g:copy_data_layer(gb,z,zb)

Copy one layer (frame) of the bitmap data from gb into g. z is the depth of the layer to copy into zb is the depth of the layer to copy from.

lua.wetgenes.grd.create

ga=wgrd.create(gb)

Duplicate the grd.

ga=wgrd.create(format,width,height,depth)

Create a grd in the given format with the given width height and depth.

ga=wgrd.create(filename,opts)

Load an image from the file system.

ga=wgrd.create()

Create a blank grd of 0 dimensions.

This is usually the only wgrd function you would need to call as once you have a grd you can use the : calling convention to modify it. The other functions will be shown as examples using the : calling convention.

wgrd.create():load(opts)

For instance could be used if you wish to perform a more esoteric load than from the file system.

Returns nil,error if something goes wrong so can be used with assert otherwise returns a grd object.

lua.wetgenes.grd.create_convert

g:create_convert(fmt)

Like convert but returns a new grd rather than converting in place.

lua.wetgenes.grd.create_normal

gr=g:create_normal()

convert a greyscale height map into an rgb normal map using the sobel filter.

lua.wetgenes.grd.destroy

g:destroy()

Free the grd and associated memory. This will of course be done automatically by garbage collection but you can force it explicitly using this function.

lua.wetgenes.grd.duplicate

ga = g:duplicate()

Create a duplicate of this grd and return it.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.fillmask

ga:fillmask(gb,seedx,seedy)

Fill gb with a fillmask version of ga that starts the floodfill at seedx,seedy

lua.wetgenes.grd.flipx

g:flipx()

This function flips the image reversing the x axis.

lua.wetgenes.grd.flipy

g:flipy()

This function flips the image reversing the y axis.

Some image formats and rendering engines like to use upside down images so this is rather useful.

lua.wetgenes.grd.info

g:info()

This function looks at the userdata stored in g[0] and fills in the g table with its values. So it refreshes the width height etc values to reflect any changes. This should not need to be called explicitly as it is called whenever we change anything.

lua.wetgenes.grd.load

g:load(opts)

Load an image from memory or file system depending on settings in opts.

opts.fmt

Lets you choose an image format, the strings "jpg","png" or "gif" will be converted to the appropriate wgrd.FMT_HINT_* value.

opts.data

Flags this as a load from memory and provides the data string to load from.

opts.filename

Flags this as a load the file system and provides the file name to open.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.load_data

g:load_data(datastring,format)

Load an image from memory.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.load_file

g:load_file(filename,format)

Load an image from the file system.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.paint

g:paint(gb,x,y,cx,cy,cw,ch,mode,trans,color)

Blit a 2D area from one grd into another using dpaint style paint modes.

Both grids must be indexed - FMT_U8_INDEXED

gb is the grd to blit from.

x,y is the location to blit too.

cx,cy,cw,ch is a clip area that should be applied to gb before it is blitted. EG to specify an area within gb. If not provided it will default to the entirety of gb,

mode is one of the following

PAINT_MODE_TRANS

Skip the transparent color.

GRD_PAINT_MODE_COLOR

Skip the transparent color and make every solid pixel the same color.

GRD_PAINT_MODE_COPY

Copy the entire area.

GRD_PAINT_MODE_XOR

XOR the values. (Can be used to find differences in an image)

GRD_PAINT_MODE_ALPHA

Skip the transparent colors as defined in the palette.

trans is the index of the transparent color, bground color, for use in the appropriate modes.

color is the index of the drawing color, foreground color, for use in the appropriate modes.

This is not overly optimised but should be reasonably fast.

lua.wetgenes.grd.palette

g:palette(x,w)
g:palette(x,w,"")
g:palette(x,w,tab)
g:palette(x,w,str)
g:palette(x,w,grd)

These are the same as g:pixels() but refer to the palette information which is stored as a 1 pixel high 256 pixel wide rgba image. The use of "" to read a string of bytes and passing in either a table of numerical values or string of bytes to write into the palette is the same system as used with pixels.

lua.wetgenes.grd.pixels

g:pixels(x,y,w,h)
g:pixels(x,y,z,w,h,d)

Read the area of pixels as a table of numerical values, the amount of numbers you get per pixel depends on the format of the grd.

g:pixels(x,y,w,h,"")
g:pixels(x,y,z,w,h,d,"")

Read the area of pixels as a string of byte values, the amount of bytes you get per pixel depends on the format of the grd. Note the passing in of an empty string to indicate that you with to receive a string.

g:pixels(x,y,w,h,tab)
g:pixels(x,y,z,w,h,d,tab)

Write the area of pixels from a table of numerical values which is provided in tab, the amount of numbers you need to provide per pixel depends on the format of the grd.

g:pixels(x,y,w,h,str)
g:pixels(x,y,z,w,h,d,str)

Write the area of pixels from a string of bytes which is provided in str, the amount of bytes you need to provide per pixel depends on the format of the grd.

g:pixels(x,y,w,h,grd)
g:pixels(x,y,z,w,h,d,grd)

Write the area of pixels from a grd which is provided in grd. use clip/layer functions to select a portion of a larger grd.

As you can see depending on the arguments given this does one of two things, read some pixels or write some pixels. The area that is to be used is provided first, as a 2d(x,y,w,h) or 3d(x,y,z,w,h,d) area. To read or write the entire 2d image or the first frame of an animation use (0,0,g.width,g.height)

Returns nil,error if something goes wrong so can be used with assert otherwise returns the requested data.

lua.wetgenes.grd.quant

g:quant(num)

Convert to an 8bit indexed image containing a palette of the requested size.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.remap

ga:remap(gb)

Fill gb with a remaped version of ga, each pixel is mapped to the closest palette entry.

lua.wetgenes.grd.reset

g:reset()

Reset the grd which will now be a blank image of 0 dimensions.

Returns nil,error if something goes wrong so can be used with assert otherwise returns g so that we can chain the result.

lua.wetgenes.grd.resize

g:resize(w,h,d)

Resize the image to the given dimensions, this does not scale the image data so instead each pixel will be in the same place after the resize. This gives a crop effect when shrinking and extra blank area at the bottom right when growing. Useful if for instance you want to upload a texture to OpenGL and need to change the size to be a power of two in width and height so you can mipmap it.

lua.wetgenes.grd.save

g:save(opts)

Save an image to memory or filesytem depending on settings in opts.

opts.fmt

Lets you choose an image format, the strings "jpg","png" or "gif" will be converted to the appropriate wgrd.FMT_HINT_* value.

We will guess opts.fmt from the file name extension if it is not provided and a file name is.

opts.filename

Flags this as a load the file system and provides the file name to write to. If no filename is given then we will be saving into memory and be returning that data string as the first return value.

Returns nil,error if something goes wrong so can be used with assert.

If no file name is given then we return the data string that we saved.

lua.wetgenes.grd.scale

g:scale(w,h,d)

Scale the image to the given dimensions, this is currently using a terrible scale filter that is only any good at halving or doubling the size.

This should only be used to create mipmaps until it is replaced with a better scale filter.

lua.wetgenes.grd.shrink

g:shrink(area)

area is an {x=0,y=0,z=0,w=100,h=100,d=100} style table specifying a 3D area, set {z=0,d=1} for a 2D area.

You should set this to the full size of the image.

This function looks at the pixels in that area and shrinks each edge inwards if it is fully transparent then return this new area in the same table that was passed in.

You can then use this information to crop this image resulting in a smaller sized grd containing all the solid pixels.

lua.wetgenes.grd.slide

g:slide(dx,dy,dz)

Slide the image along the x,y,z axis by the given amounts. The image wraps around the edges so no pixels are lost just moved around.

lua.wetgenes.grd.sort_cmap

ga:sort_cmap()

Sort cmap into a "good" order and remap the image.

lua.wetgenes.grd.stream

stream=g:stream(filename)
stream=g:stream({filename=filename,...})

Open a GIF stream, returns a table with the following functions,

stream:write(ga)

Add a frame to the gif, each frame should be the same size and color map.

stream:close()

Close the stream and finalise the GIF.

lua.wetgenes.grd.xor

g:xor(ga)

Set our image data to the XOR of the image/palette data from ga and g.

This is intended to be combined with g:shrink to work out the area of change between the two images.

Both grds must be the same size and format.

lua.wetgenes.grdcanvas

local wgrdcanvas=require("wetgenes.grdcanvas")

We use wgrdcanvas as the local name of this library.

lua.wetgenes.grdhistory

local wgrdhistory=require("wetgenes.grdhistory")

We use wgrdhistory as the local name of this library.

Add extra functionality to wetgenes.grd primarily these are functions that are used by swanky paint to manage its internal data.

lua.wetgenes.grdhistory.history

local history=grdhistory.history(grd)

Create and bind a history object to the given grd object. The history lives inside the grd and can be accesd as grd.history just as the grd can be accessed through the history as history.grd

lua.wetgenes.grdlayers

local wgrdlayers=require("wetgenes.grdlayers")

We use wgrdlayers as the local name of this library.

Add extra functionality to wetgenes.grd primarily these are functions that are used by swanky paint to manage its internal data.

lua.wetgenes.grdpaint

local wgrdpaint=require("wetgenes.grdpaint")

We use wgrdpaint as the local name of this library.

Add extra functionality to wetgenes.grd primarily these are functions that are used by swanky paint to manage its internal data.

Primarily we add a concept of "layers" and "history" these interfaces are added to a grd via a new object that lives inside the grd table and binds them together.

EG grd.history contains history data and functions.

As these are written first for swankypaint they may only work with indexed images and are currently in state of flux so may take a while to settle down.

lua.wetgenes.grdsvg

wgrdsvg=require("wetgenes.grdsvg")

Build svg files from grd data (bitmaps)

lua.wetgenes.grdsvg.string

local svgstring=wgrdsvg.string(grd,opts)

Return an svg formated string that represents the input grd which must be an indexed (8bit) format. Each pixel will be converted into a filled svg rectangle element. Opts can contain the following options to control the generation of the svg file.

opts.skip_transparent_pixels=true

Do not export a rectangle for fully transparent pixels.

opts.scalex=1

Width of each exported pixel.

opts.scaley=1

Height of each exported pixel.

lua.wetgenes.json

local wjson=require("wetgenes.json")

-- or export the main functions like so
local json_encode,json_decode=require("wetgenes.json"):export("encode","decode")

other json encode/decode using pure lua library seemed too slow, here is a fast and loose one lets see if it goes any faster :) should be a direct replacement for JSON4Lua which is what I was using before I profiled where all the time was getting spent...

I needed it to be pure json as I was running it on googles appengine so the lua was actually running in java, no C available.

Anyhow I hope it is useful, in order to get it running faster I cut across some corners so you may find some obscure problems.

lua.wetgenes.json.decode

json_table = wjson.decode(json_string)
json_table = wjson.decode(json_string,opts)

Convert a json string into a lua table.

Set opts.null to wetgenes.json.null (or indeed any other value) if you would like to have this as nulls in your results. By default nulls are replaced with nil and therefore invisible.

Any object key string that looks like a number will be converted to a number. This will probably reverse any numbers we converted to strings when encoding. Set opts.keystring=true to turn off this behaviour.

lua.wetgenes.json.encode

json_string = wjson.encode(json_table)
json_string = wjson.encode(json_table,opts)

Convert a lua table into a json string. Note it must be valid json, primarily make sure that the table is either an array or a dictionary but never both. Note that we can not tell the difference between an empty array and an empty object and will assume it is an object.

An array must have a length>0 and contain an element in the first slot, eg array[1] and only contain numerical integer keys between 1 and the length. This allows for the possibility of some nil holes depending on the length lua returns but holes are not a good idea in arrays in lua. Best to use false or the special wjson.null value and avoid holes.

Also some of the internal lua types will cause errors, eg functions as these can not be converted into json.

include nulls in the output by using wetgenes.json.null

opts is an optional table that can set the following options.

ops.pretty=true
ops.pretty=" "
    Enable pretty printing, line feeds and indents and set each 
    indent level to multiples of the given string or " ".
    
ops.white=true
ops.white=" "
    Enable white space but not lines or indents, just a single space 
    between value assignment to make line wrapping easier.

ops.sort=true
    Sort the keys, so we can create stable output for better diffing.

lua.wetgenes.json_diff

(C) 2024 Kriss Blank and released under the MIT license, see http://opensource.org/licenses/MIT for full license text.

I assume we are not competing in the lua json_diff library world so just call it json_diff

local json_diff=require("wetgenes.json_diff")

When we talk of json objects or json values we mean that the values must be valid json. So no storing of functions/etc or mixxing of tables and objects. Infinite recursion where data links back into itself is also not possible in json so not allowed/expected here.

We assume we have data that could be validly serialised as json but this is not enforced. If you want to be 100% safe then convert your data to json text and back again before handing it to these functions.

If a table has a length of more than 0 then it is considered a json array otherwise it is a json object. An empty table is considered an empty object there is no lua equivalent to an empty json array.

Lua is not good with holes in its arrays, so that is also not suported.

We do try and diff arrays of objects, but, since arrays may shift up and down it would be better if you had object maps of id to data and arrays of ids that references these maps rather than arrays of objects.

Json arrays must be normal lua tables, so first index is 1 not 0 this may cause problems if your data is made of objects that have been accidently converted into arrays. Probably wont have happened but best to be aware of possible sharp edges.

lua.wetgenes.json_diff.apply

apply a diff , please dupe a before handing it to this function as we will be altering it.

lua.wetgenes.json_diff.array_common

Given two arrays of json data, return the length , starta , startb of the longest common subsequence in table indexes or nil if not similar.

lua.wetgenes.json_diff.array_match

Given two arrays of json data, return two synced arrays of arrays where as much json data as possible match in each sub batch.

each of these arrays can be concatonated to create the original array.

When stepping thoigh bothe arrays, matches are shown by the sub array having equality and differences will be insertions or deletions depending on which of the two has the empty array.

EG these two lists

[a,b,c,d,e,f]
[a,b,e,f]

would become

[ [a,b] , [c,d] , [e,f] ]
[ [a,b] , [] , [e,f] ]

The two [a,b] arrays will be equal to each other when tested with a simple == compare as they are references to the same table.

lua.wetgenes.json_diff.array_trim

Given two arrays of json data, return the length at the start and at the end that are the same. This tends to be a good first step when comparing two chunks of text.

lua.wetgenes.json_diff.equal

Compare two json values and return true if they are equal, this may decend into a tree of tables and objects so can be an expensive test.

lua.wetgenes.json_diff.similar

Compare two json values and return true if they are similar arrays or objects, this may descend into a tree of tables and objects so can be an expensive test.

An array or object is similar if it contains at least one value that is the same in both.

Will return false if not given two objects or two arrays.

lua.wetgenes.json_diff.undo

undo a diff which must have been created with the both flag set in order to have undo data available.

lua.wetgenes.json_pack

(C) 2024 Kriss Blank and released under the MIT license, see http://opensource.org/licenses/MIT for full license text.

local json_pack=require("wetgenes.json_pack")

Turn a valid json table into a binary data string and visa versa.

A valid json table...

Does not include functions/userdata/etc.

Does not self reference.

Each table should be an array or an object never both.

May have metatables as long as it is not too funky so added 
function calls for a class should be fine but this will obviously 
be lost. Please test and check outputs if including meta.

So normal json style data.

Currently we are using cmsgpack and zlib, this may be changed if a better way is found.

lua.wetgenes.json_pack.from_data

j=json_pack.from_data(d)

Where j is some json data and d is a binary string of the same data.

lua.wetgenes.json_pack.into_data

d=json_pack.into_data(j)

Where j is some json data and d is a binary string of the same data.

lua.wetgenes.lookup

value = wetgenes.lookup(table,...)

Safe recursive lookup within a table that returns nil if any part of the lookup is nil so we never cause an error but just return nil. This is intended to replace the following sort of code

a = b and b.c and b.c.d and b.c.d.e

To get e only if all of its parent bits exist and not to cause any error if they do not. instead use

a = lookup(b,"c","d","e")

lua.wetgenes.midi.create

m=wmidi.create()

Returns nil,error if something goes wrong so can be used with assert otherwise returns a midi object.

lua.wetgenes.midi.destroy

m:destroy()

Free the midi and associated memory. This will of course be done automatically by garbage collection but you can force it explicitly using this function.

lua.wetgenes.midi.event_to_string

str = m:event_to_string(event)

Convert an event to a single line string for printing to the console.

lua.wetgenes.midi.get

m:get()

get all values for this connection and store them in m

lua.wetgenes.midi.peek

m:peek(it)

Returns a event if there is one or null if none are currently available.

lua.wetgenes.midi.port_create

p = m:port_create(name,caps,type)

Create a port with the given name and capability bits and type.

bits and type are either a number or a table of bitnames.

Returns the number of the port created which should be used in port_destroy or nil if something went wrong.

lua.wetgenes.midi.port_destroy

m:port_destroy(num)

Destroy a previously created port. Returns nil on failure, true on success.

lua.wetgenes.midi.pull

m:pull(it)

Receive an input midi event, blocking until there is one.

Occasionally, for "reasons" this may return nil.

lua.wetgenes.midi.set

m:set()

set all values for this connection from values found in m

lua.wetgenes.midi.string_to_clientport

client,port = m:string_to_clientport(str)

Convert a "client:port" string to two numbers client,port this can either be two decimal numbers or, if a m:scan() has been performed, then a partial case insensitive matching to the name of existing clients and ports may get a port number.

Will return a nil if we can not work out which client or port you mean.

lua.wetgenes.midi.subscribe

m:subscribe{
    source_client=0,	source_port=0,
    dest_client=1,		dest_port=0,
}

m:subscribe{
    source="0:0",
    dest="1:0",
}

Creates a persistent subscription between two ports.

lua.wetgenes.midi.unsubscribe

m:unsubscribe{
    source_client=0,	source_port=0,
    dest_client=1,		dest_port=0,
}

m:unsubscribe{
    source="0:0",
    dest="1:0",
}

Removes a persistent subscription from between two ports.

lua.wetgenes.package

wpackage=require("wetgenes.package")

Some generic lowlevel functions for messing about with how lua works, eg how modules are loaded.

lua.wetgenes.package.reload

local module=wpackage.reload(modulename)

A wrapper for require that forces a very dumb module reload by merging a newly loaded module into the old module table if one already exists this can easily break everything but should mostly work out of dumb luck.

lua.wetgenes.path

Manage file paths under linux or windows, so we need to deal with \ or / and know the root difference between / and C:\

local wpath=require("wetgenes.path")

lua.wetgenes.path.currentdir

Get the current working directory, this requires lfs and if lfs is not available then it will return wpath.root this path will have a trailing separator so can be joined directly to a filename.

wpath.currentdir().."filename.ext"

lua.wetgenes.path.dir

local dir=wpath.dir(path)

This is a small utility function to perform a wpath.resolve then wpath.parse and return the dir component of the result.

lua.wetgenes.path.ext

local ext=wpath.ext(path)

This is a small utility function to perform a wpath.resolve then wpath.parse and return the ext component of the result.

lua.wetgenes.path.folder

local folder=wpath.folder(path)

This is a small utility function to perform a wpath.resolve then wpath.parse and return the folder component of the result.

lua.wetgenes.path.name

local name=wpath.name(path)

This is a small utility function to perform a wpath.resolve then wpath.parse and return the name component of the result.

lua.wetgenes.path.parent

Resolve input and go up a single directory level, ideally you should pass in a directory, IE a string that ends in / or \ and we will return the parent of this directory.

If called repeatedly, then eventually we will return wpath.root

lua.wetgenes.path.parse

split a path into named parts like so

|--------------------------------------------|
|                     path                   |
|-----------------------|--------------------|
|         dir           |        file        |
|----------|------------|----------|---------|
| root [1] | folder [2] | name [3] | ext [4] |
|----------|------------|----------|---------|
| /        | home/user/ | file     | .txt    |
|----------|------------|----------|---------|

this can be reversed with simple joins and checks for nil, note that [1][2][3][4] are forced strings so will be "" rather than nil unlike their named counterparts. This means you may use wpath.join to reverse this parsing.

dir = (root or "")..(folder or "")
file = (name or "")..(ext or "")
path = (dir or "")..(file or "")
path = (root or "")..(folder or "")..(name or "")..(ext or "")
path = [1]..[2]..[3]..[4]
path = wpath.join(it)

if root is set then it implies an absolute path and will be something like C:\ under windows.

lua.wetgenes.path.relative

Build a relative path from point a to point b this will probably be a bunch of ../../../ followed by some of the ending of the second argument.

lua.wetgenes.path.resolve

Join all path segments and resolve them to absolute using wpath.join and wpath.normalize with a prepended wpath.currentdir as necessary.

lua.wetgenes.path.root

local root=wpath.root(path)

This is a small utility function to perform a wpath.resolve then wpath.parse and return the root component of the result.

lua.wetgenes.path.setup

setup for windows or linux style paths, to force one or the other use

wpath.setup("win")
wpath.setup("nix")

We automatically call this at startup and make a best guess, you can revert to this best guess with

wpath.setup()

This is a global setting, so be careful with changes. Mostly its probably best to stick with the best guess unless we are mistakenly guessing windows.

lua.wetgenes.plate.replace_lookup

value=wetgenes.plate.replace_lookup(name,data)

Calls "wetgenes.plate.table_lookup" then performs special formatting on table returns.

Always returns a string or nil, so number values will converted to a string.

lua.wetgenes.plate.replace_lookup_istable

bool=wetgenes.plate.replace_lookup_istable(name,data)

Test if the return from "wplate.table_lookup" is a table.

lua.wetgenes.plate.table_lookup

value=wetgenes.plate.table_lookup(name,data)

look up name inside data and return the value we found if we don't find anything then we return nil

name.name.name syntax may be used to reference tables within tables.

A name that looks like a number may be converted into a number if it doesnt exist as a string key, so "array.1" can be used to return the first item from an array.

lua.wetgenes.rnd64k

rnd = wetgenes.rnd64k(seed)

r	= rnd()		-- a fraction between 0 and 1 inclusive
r	= rnd(a)	-- an integer between 1 and a inclusive
r	= rnd(a,b)	-- an integer between a and b inclusive

a sequence of 65536 numbers starting at seed which should be an integer between 0 and 65535 or a string which will be used to generate this number.

lua.wetgenes.safecall

... = wetgenes.safecall(func,...)

Call a function func(...) wrapped in an xpcall to catch and ignore errors, the errors are printed to stderr with a traceback and the function returns nil on an error.

So provided the function returns not nil on success then you can still tell if the function completed OK. Best to use for things that are OK to fail and the rest of the code will work around it.

lua.wetgenes.safewrap

savefunc = wetgenes.safecall(func)

Wrap a funciton in safecall, so it will never generate errors but can be called as normal.

lua.wetgenes.set_env

gamecake -e" require('wetgenes').savescripts('./') "

Run the above from the command line.

This will export all the gamecake internal strings into the file system it is saved into the current directory so be careful where you run it.

Game Cake checks the files system first so, these files can be modified and they will replace the built in versions.

gamecake -e" require('wetgenes').savescripts('./internal/') "

This is a safer version that will save the files to ./internal/lua/* instead of just ./lua/*

lua.wetgenes.snippets

-- copy all globals into locals, some locals are prefixed with a G to reduce name clashes
local coroutine,package,string,table,math,io,os,debug,assert,dofile,error,_G,getfenv,getmetatable,ipairs,Gload,loadfile,loadstring,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,_VERSION,xpcall,module,require=coroutine,package,string,table,math,io,os,debug,assert,dofile,error,_G,getfenv,getmetatable,ipairs,load,loadfile,loadstring,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,_VERSION,xpcall,module,require

-- grab some util functions
local export,lookup,set_env=require("wetgenes"):export("export","lookup","set_env")

-- single line replacement for the module creation function
local M={} ; package.loaded[(...)]=M ; M.module_name=(...) ; M.export=export


A place to keep bits of code that needs to be copypasta into most modules, for instance above is the current boilerplate code to be used when starting a new module.

lua.wetgenes.spew

local spew=require("wetgenes.spew").connect(oven.tasks)

You must pass in a previously created tasks object that you will be calling update on regually so that our coroutines can run. eg oven.tasks

Connect and talk to the wetgenes spew server using wetgenes.tasks task for meta state and a thread for lowlevel sockets.

You push messages in and can pull messages out or, setup a hook function to auto pull and process messages in our coroutine as they are received.

lua.wetgenes.spew.connect

local spew=require("wetgenes.spew").connect(oven.tasks)
local spew=require("wetgenes.spew").connect(oven.tasks,host)
local spew=require("wetgenes.spew").connect(oven.tasks,host,port)

You must pass in an active tasks object.

Create task and thread connection to the host. host and port default to wetgenes.com and 5223 so can be left blank unless you want to connect to a local host for debugging.

There are now 3 ways to handle msgs

spew.push(msg)

To send a msg

local msg,s=spew.pull()

To receive a message, will return nil if no messages available. The second return value is the input string packet for this decoded message.

spew.hook=function(msg,s) print(msg) end

Set a hook functions to auto pull all available messages durring tasks update. Note that if you do this spew.pull() will no longer work as all messages are auto pulled and sent to this hook function.

Note when receiving a msg you must not alter or cache the table you are given as it is internal data and is reused. You must duplicate it if you want to keep it arround.

lua.wetgenes.tardis

Time And Relative Dimensions In Space is of course the perfect name for a library of matrix based math functions.

local tardis=require("wetgenes.tardis")

This tardis is a lua library for manipulating time and space with numbers. Designed to work as pure lua but with a faster, but less accurate, f32 core by default. ( this core seems to be slightly faster/same speed as vanilla lua but slower than luajit , so is currently disabled )

Recoil in terror as we use two glyph names for classes whilst typing in random strings of numbers and operators that may or may not contain tyops.

v# vector [#]
m# matrix [#][#]
q4 quaternion

Each class is a table of # values [1] to [#] the 2d number streams are formatted the same as opengl (row-major) and metatables are used to provide methods.

The easy way of remembering the opengl 4x4 matrix layout is that the translate x,y,z values sit at 13,14,15 and 4,8,12,16 is normally set to the constant 0,0,0,1 for most transforms.

     | 1  5  9  13 |
     | 2  6  10 14 |
m4 = | 3  7  11 15 |
     | 4  8  12 16 |

This seems to be the simplest (programmer orientated) description of most of the maths used here so go read it if you want to know what the funny words mean.

http://www.j3d.org/matrix_faq/matrfaq_latest.html

lua.wetgenes.tardis.array

Array is the base class for all other tardis classes, it is just a stream of numbers, probably in a table but possibly a chunk of f32 values in a userdata.

lua.wetgenes.tardis.array.__add

r = array.__add(a,b)

Add a to b and return a a.new(result) so the class returned will match the input class of a and neither a or b will be modified.

lua.wetgenes.tardis.array.__div

r = array.__div(a,b)

Replace b with 1/b and then call the appropriate product function depending on the argument classes. Always creates and returns a.new() value.

lua.wetgenes.tardis.array.__eq

r = array.__eq(a,b)

meta to call a:compare(b) and return the result

lua.wetgenes.tardis.array.__mul

r = array.__mul(a,b)

Call the appropriate product function depending on the argument classes. Always creates and returns a.new() value.

lua.wetgenes.tardis.array.__sub

r = array.__sub(a,b)

Subtract b from a and return a a.new(result) so the class returned will match the input class of a and neither a or b will be modified.

lua.wetgenes.tardis.array.__tostring

string = array.__tostring(it)

Convert an array to a string this is called by the lua tostring() function,

lua.wetgenes.tardis.array.__unm

r = array.__unm(a)

Subtract b from 0 and return a a.new(result) so the class returned will match the input class of a but a will not be modified

lua.wetgenes.tardis.array.abs

r=it:abs(r)
r=it:abs(it.new())

Perform math.abs on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.acos

r=it:acos(r)
r=it:acos(it.new())

Perform math.acos on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.add

r=it:add(b,r)
r=it:add(b,it.new())

Add b to it. b may be a number or another array of the same size as this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.asin

r=it:asin(r)
r=it:asin(it.new())

Perform math.asin on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.atan

r=it:atan(r)
r=it:atan(it.new())

Perform math.atan on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.ceil

r=it:ceil(r)
r=it:ceil(it.new())

Perform math.ceil on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.compare

a=a:compare(b)
a=a:compare(1,2,3,4)

Are the numbers in b the same as the numbers in a, this function will return true if they are and false if they are not.

If the arrays are of different lengths then this will return false.

Numbers to test for can be given explicitly in the arguments and we follow the same one level of tables rule as we do with array.set so any class derived from array can be used.

lua.wetgenes.tardis.array.cos

r=it:cos(r)
r=it:cos(it.new())

Perform math.cos on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.exp

r=it:exp(r)
r=it:exp(it.new())

Perform math.exp on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.floor

r=it:floor(r)
r=it:floor(it.new())

Perform math.floor on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.fract

r=it:fract(r)
r=it:fract(it.new())

Return the fractional part of each value using math.modf.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.log

r=it:log(r)
r=it:log(it.new())

Perform math.log on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.max

r=it:max()

Return a single number value that is the maximum of all values in this array.

lua.wetgenes.tardis.array.min

r=it:min()

Return a single number value that is the minimum of all values in this array.

lua.wetgenes.tardis.array.mix

r=a:mix(b,s,r)

Mix values between a and b where a is returned if s=0 and b is returned if s=1

If r is provided then the result is written into r and returned otherwise a is modified and returned.

lua.wetgenes.tardis.array.pow

r=it:pow(p,r)
r=it:pow(p,it.new())

Perform math.pow(it,p) on all values of this array. p may be a number or another array of the same size as this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.product

ma = ma:product(mb)
ma = ma:product(mb,r)

Look at the type and call the appropriate product function, to produce

mb x ma

Note the right to left application and default returning of the leftmost term for chaining. This seems to make the most sense.

If r is provided then the result is written into r and returned otherwise ma is modified and returned.

lua.wetgenes.tardis.array.quantize

r=it:quantize(1/1024,r)
r=it:quantize(s,it.new())

Perform a trunc(v/s)*s on all values of this array. We recomended the use of a power of two, eg 1/1024 rather than 1/1000 if you wanted 3 decimal digits.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.round

r=it:round(r)
r=it:round(it.new())

Perform math.floor( v+0.5 ) on all values of this array. Which will round up or down to the nearest integer.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.scalar

r=a:scalar(s,r)

Multiply all value in array by number.

If r is provided then the result is written into r and returned otherwise a is modified and returned.

lua.wetgenes.tardis.array.set

a=a:set(1,2,3,4)
a=a:set({1,2,3,4})
a=a:set({1,2},{3,4})
a=a:set(function(i) return i end)

Assign some numbers to an array, all the above examples will assign 1,2,3,4 to the first four slots in the given array, as you can see we allow one level of tables. Any class that is based on this array class can be used instead of an explicit table. So we can use a v2 or v3 or m4 etc etc.

if more numbers are given than the size of the array then they will be ignored.

if less numbers are given than the size of the array then the last number will be repeated.

if no numbers are given then nothing will be done

if a function is given it will be called with the index and should return a number.

lua.wetgenes.tardis.array.sin

r=it:sin(r)
r=it:sin(it.new())

Perform math.sin on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.sub

r=it:sub(b,r)
r=it:sub(b,it.new())

Subtract b from it. b may be a number or another array of the same size as this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.tan

r=it:tan(r)
r=it:tan(it.new())

Perform math.tan on all values of this array.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.trunc

r=it:trunc(r)
r=it:trunc(it.new())

Perform math.floor on positive values and math ceil on negative values for all values of this array. So a trunication that will always error towards 0.

If r is provided then the result is written into r and returned otherwise it is modified and returned.

lua.wetgenes.tardis.array.unpack

a1,a2=v2:unpack()
a1,a2,a3=v3:unpack()
a1,a2,a3,a4=v4:unpack()

Return all values in this array. Note this should be used instead of the unpack function for future optimisation safety.

lua.wetgenes.tardis.class

metatable=tardis.class(name,class,...)

Create a new metatable for an object class, optionally inheriting from other previously declared classes.

lua.wetgenes.tardis.line

A 3d space line class.

[1]position , [2]normal

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.line.new

line = tardis.line.new(p,n)

Create a new line and optionally set it to the given values.

lua.wetgenes.tardis.m2

The metatable for a 2x2 matrix class, use the new function to actually create an object.

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.m2.adjugate

m2 = m2:adjugate()
m2 = m2:adjugate(r)

Adjugate this m2.

If r is provided then the result is written into r and returned otherwise m2 is modified and returned.

lua.wetgenes.tardis.m2.cofactor

m2 = m2:cofactor()
m2 = m2:cofactor(r)

Cofactor this m2.

If r is provided then the result is written into r and returned otherwise m2 is modified and returned.

lua.wetgenes.tardis.m2.determinant

value = m2:determinant()

Return the determinant value of this m2.

lua.wetgenes.tardis.m2.inverse

m2 = m2:inverse()
m2 = m2:inverse(r)

Inverse this m2.

If r is provided then the result is written into r and returned otherwise m2 is modified and returned.

lua.wetgenes.tardis.m2.new

m2 = tardis.m2.new()

Create a new m2 and optionally set it to the given values, m2 methods usually return the input m2 for easy function chaining.

lua.wetgenes.tardis.m2.scale

m2 = m2:scale(s)
m2 = m2:scale(s,r)

Scale this m2 by s.

If r is provided then the result is written into r and returned otherwise m2 is modified and returned.

lua.wetgenes.tardis.m2.transpose

m2 = m2:transpose()
m2 = m2:transpose(r)

Transpose this m2.

If r is provided then the result is written into r and returned otherwise m2 is modified and returned.

lua.wetgenes.tardis.m3

The metatable for a 3x3 matrix class, use the new function to actually create an object.

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.m3.adjugate

m3 = m3:adjugate()
m3 = m3:adjugate(r)

Adjugate this m3.

If r is provided then the result is written into r and returned otherwise m3 is modified and returned.

lua.wetgenes.tardis.m3.cofactor

m3 = m3:cofactor()
m3 = m3:cofactor(r)

Cofactor this m3.

If r is provided then the result is written into r and returned otherwise m3 is modified and returned.

lua.wetgenes.tardis.m3.determinant

value = m3:determinant()

Return the determinant value of this m3.

lua.wetgenes.tardis.m3.inverse

m3 = m3:inverse()
m3 = m3:inverse(r)

Inverse this m3.

If r is provided then the result is written into r and returned otherwise m3 is modified and returned.

lua.wetgenes.tardis.m3.new

m3 = tardis.m3.new()

Create a new m3 and optionally set it to the given values, m3 methods usually return the input m3 for easy function chaining.

lua.wetgenes.tardis.m3.scale

m3 = m3:scale(s)
m3 = m3:scale(s,r)

Scale this m3 by s.

If r is provided then the result is written into r and returned otherwise m3 is modified and returned.

lua.wetgenes.tardis.m3.transpose

m3 = m3:transpose()
m3 = m3:transpose(r)

Transpose this m3.

If r is provided then the result is written into r and returned otherwise m3 is modified and returned.

lua.wetgenes.tardis.m3.v3

v3 = m3:v3(n)

Extract and return a "useful" v3 from an m3 matrix. The first vector is the x axis, then y axis , then z axis.

lua.wetgenes.tardis.m4

The metatable for a 4x4 matrix class, use the new function to actually create an object.

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.m4.add

m4 = m4:add(m4b)
m4 = m4:add(m4b,r)

Add m4b this m4.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.adjugate

m4 = m4:adjugate()
m4 = m4:adjugate(r)

Adjugate this m4.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.arotate

m4 = m4:arotate(degrees,v3a)
m4 = m4:arotate(degrees,v3a,r)

Apply a rotation in degres around the given axis to this matrix.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.cofactor

m4 = m4:cofactor()
m4 = m4:cofactor(r)

Cofactor this m4.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.determinant

value = m4:determinant()

Return the determinant value of this m4.

lua.wetgenes.tardis.m4.get_rotation_q4

q4 = m4:get_rotation_q4(r)

Get quaternion rotation from a scale/rot/trans matrix. Note that scale is assumed to be uniform which it usually is. If that is not the case then remove the scale first.

If r is provided then the result is written into r and returned otherwise a new q4 is created and returned.

lua.wetgenes.tardis.m4.get_scale_v3

v3 = m4:get_scale_v3(r)

Get v3 scale from a scale/rot/trans matrix

If r is provided then the result is written into r and returned otherwise a new v3 is created and returned.

lua.wetgenes.tardis.m4.get_translation_v3

v3 = m4:get_translation_v3(r)

Get v3 translation from a scale/rot/trans matrix

If r is provided then the result is written into r and returned otherwise a new v3 is created and returned.

lua.wetgenes.tardis.m4.inverse

m4 = m4:inverse()
m4 = m4:inverse(r)

Inverse this m4.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.m3

m4 = m4:m3()

Grab tthe top,left parts of the m4 matrix as an m3 matrix.

lua.wetgenes.tardis.m4.mix

m4 = m4:mix(m4b,s)
m4 = m4:mix(m4b,s,r)

Lerp from m4 to m4b by s.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.new

m4 = tardis.m4.new()

Create a new m4 and optionally set it to the given values, m4 methods usually return the input m4 for easy function chaining.

lua.wetgenes.tardis.m4.prearotate

m4 = m4:prearotate(degrees,v3a)
m4 = m4:prearotate(degrees,v3a,r)

Pre apply a rotation in degrees around the given axis to this matrix.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.preqrotate

m4 = m4:preqrotate(q)
m4 = m4:preqrotate(q,r)

Pre apply a quaternion rotation to this matrix.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.prerotate

m4 = m4:prerotate(degrees,v3a)
m4 = m4:prerotate(degrees,v3a,r)
m4 = m4:prerotate(degrees,x,y,z)
m4 = m4:prerotate(degrees,x,y,z,r)
m4 = m4:prerotate(q)
m4 = m4:prerotate(q,r)

Pre apply quaternion or angle rotation to this matrix depending on arguments provided.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.prerrotate

m4 = m4:prerrotate(radians,v3a)
m4 = m4:prerrotate(radians,v3a,r)

Pre apply a rotation in radians around the given axis to this matrix.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.prescale

m4 = m4:scale(s)
m4 = m4:scale(s,r)
m4 = m4:scale(x,y,z)
m4 = m4:scale(x,y,z,r)
m4 = m4:scale(v3)
m4 = m4:scale(v3,r)

Pre Scale this m4 by {s,s,s} or {x,y,z} or v3.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.pretranslate

m4 = m4:pretranslate(x,y,z)
m4 = m4:pretranslate(x,y,z,r)
m4 = m4:pretranslate(v3a)
m4 = m4:pretranslate(v3a,r)

Translate this m4 along its global axis by {x,y,z} or v3a.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.pretranslate_v3

m4 = m4:pretranslate_v3(v3a)
m4 = m4:pretranslate_v3(v3a,r)

Translate this m4 along its global axis by v3a.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.qrotate

m4 = m4:qrotate(q)
m4 = m4:qrotate(q,r)

Apply a quaternion rotation to this matrix.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.rotate

m4 = m4:rotate(degrees,v3a)
m4 = m4:rotate(degrees,v3a,r)
m4 = m4:rotate(degrees,x,y,z)
m4 = m4:rotate(degrees,x,y,z,r)
m4 = m4:rotate(q)
m4 = m4:rotate(q,r)

Apply quaternion or angle rotation to this matrix depending on arguments provided.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.rrotate

m4 = m4:rrotate(radians,v3a)
m4 = m4:rrotate(radians,v3a,r)

Apply a rotation in radians around the given axis to this matrix.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.scale

m4 = m4:scale(s)
m4 = m4:scale(s,r)
m4 = m4:scale(x,y,z)
m4 = m4:scale(x,y,z,r)
m4 = m4:scale(v3)
m4 = m4:scale(v3,r)

Scale this m4 by {s,s,s} or {x,y,z} or v3.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.scale_v3

m4 = m4:scale_v3(v3)
m4 = m4:scale_v3(v3,r)

Scale this m4 by {x,y,z} or v3.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.setrot

m4 = m4:setrot(degrees,v3a)

Set this matrix to a rotation matrix around the given normal by the given degrees.

we will automatically normalise v3a if necessary.

lua.wetgenes.tardis.m4.setrrot

m4 = m4:setrrot(radians,v3a)

Set this matrix to a rotation matrix around the given normal by the given radians.

we will automatically normalise v3a if necessary.

lua.wetgenes.tardis.m4.sub

m4 = m4:sub(m4b)
m4 = m4:sub(m4b,r)

Subtract m4b this m4.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.translate

m4 = m4:translate(x,y,z)
m4 = m4:translate(x,y,z,r)
m4 = m4:translate(v3a)
m4 = m4:translate(v3a,r)

Translate this m4 along its local axis by {x,y,z} or v3a.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.translate_v3

m4 = m4:translate_v3(v3a)
m4 = m4:translate_v3(v3a,r)

Translate this m4 along its local axis by v3a.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.transpose

m4 = m4:transpose()
m4 = m4:transpose(r)

Transpose this m4.

If r is provided then the result is written into r and returned otherwise m4 is modified and returned.

lua.wetgenes.tardis.m4.v3

v3 = m4:v3(n)

Extract and return a "useful" v3 from an m4 matrix. The first vector is the x axis, then y axis , then z axis and finally transform.

If n is not given or not a known value then we return the 4th vector which is the "opengl" transform as that is the most useful v3 part of an m4.

lua.wetgenes.tardis.m4_stack

stack = tardis.m4_stack()

create an m4 stack that is very similar to an old school opengl transform stack.

lua.wetgenes.tardis.plane

A 3d space plane class.

[1]position , [2]normal

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.plane.new

plane = tardis.plane.new(p,n)

Create a new plane and optionally set it to the given values.

lua.wetgenes.tardis.q4

The metatable for a quaternion class, use the new function to actually create an object.

We also inherit all the functions from tardis.v4

lua.wetgenes.tardis.q4.get_yaw_pitch_roll

v3 = q4:get_yaw_pitch_roll()

Get a yaw,pitch,roll degree rotation from this quaternion

If r is provided then the result is written into r and returned otherwise a new v3 is created and returned.

lua.wetgenes.tardis.q4.get_yaw_pitch_roll_in_radians

v3 = q4:get_yaw_pitch_roll_in_radians()

Get a yaw,pitch,roll degree rotation from this quaternion

If r is provided then the result is written into r and returned otherwise a new v3 is created and returned.

lua.wetgenes.tardis.q4.mix

q4 = q4:mix(q4b,s)
q4 = q4:mix(q4b,s,r)

Lerp from q4 to q4b by s.

If r is provided then the result is written into r and returned otherwise q4 is modified and returned.

lua.wetgenes.tardis.q4.new

q4 = tardis.q4.new()

Create a new q4 and optionally set it to the given values, q4 methods usually return the input q4 for easy function chaining.

lua.wetgenes.tardis.q4.prerotate

q4 = q4:prerotate(degrees,v3a)
q4 = q4:prerotate(degrees,v3a,r)

Pre apply a degree rotation to this quaternion.

If r is provided then the result is written into r and returned otherwise q4 is modified and returned.

lua.wetgenes.tardis.q4.prerrotate

q4 = q4:prerrotate(radians,v3a)
q4 = q4:prerrotate(radians,v3a,r)

Pre apply a radian rotation to this quaternion.

If r is provided then the result is written into r and returned otherwise q4 is modified and returned.

lua.wetgenes.tardis.q4.reverse

q4 = q4:reverse()
q4 = q4:reverse(r)

Reverse the rotation of this quaternion.

If r is provided then the result is written into r and returned otherwise q4 is modified and returned.

lua.wetgenes.tardis.q4.rotate

q4 = q4:rotate(degrees,v3a)
q4 = q4:rotate(degrees,v3a,r)

Apply a degree rotation to this quaternion.

If r is provided then the result is written into r and returned otherwise q4 is modified and returned.

lua.wetgenes.tardis.q4.rrotate

q4 = q4:rrotate(radians,v3a)
q4 = q4:rrotate(radians,v3a,r)

Apply a radian rotation to this quaternion.

If r is provided then the result is written into r and returned otherwise q4 is modified and returned.

lua.wetgenes.tardis.q4.set

q4 = tardis.q4.set(q4,{0,0,0,1})
q4 = tardis.q4.set(q4,0,0,0,1)
q4 = tardis.q4.set(q4,{"xyz",0,90,0})
q4 = tardis.q4.set(q4,"xyz",0,90,0)
q4 = tardis.q4.set(q4,"xyz",{0,90,0})

If the first item in the stream is not a string then this is just a normal array.set style.

If first parameter of the stream is a string then initialise the quaternion using a simple axis rotation notation Where the string is a list of axis. This string is lower case letters. x y or z and then the following numbers are amount of rotation to apply around that axis in degrees. You should provide as many numbers as letters.

Essentially this gives you a way of initialising quaternion rotations in an easily readable way.

lua.wetgenes.tardis.q4.set_yaw_pitch_roll

q4 = q4:set_yaw_pitch_roll(v3)
q4 = q4:set_yaw_pitch_roll({90,60,30})	-- 30yaw 60pitch 90roll

Set a V3(roll,pitch,yaw) degree rotation into this quaternion

yaw   v[3] is rotation about the z axis and is applied first
pitch v[2] is rotation about the y axis and is applied second
roll  v[1] is rotation about the z axis and is applied last

lua.wetgenes.tardis.q4.set_yaw_pitch_roll_in_radians

q4 = q4:set_yaw_pitch_roll_in_radians(v)

Set a V3(roll,pitch,yaw) radian rotation into this quaternion

yaw   v[3] is rotation about the z axis and is applied first
pitch v[2] is rotation about the y axis and is applied second
roll  v[1] is rotation about the z axis and is applied last

lua.wetgenes.tardis.q4.setrot

q4 = q4:setrot(degrees,v3a)

Set this quaternion to a rotation around the given normal by the given degrees.

lua.wetgenes.tardis.q4.setrrot

q4 = q4:setrrot(radians,v3a)

Set this quaternion to a rotation around the given normal by the given radians.

lua.wetgenes.tardis.smoothstep

f = tardis.step(edge1,edge2,num)

return 0 if num is bellow or equal to edge1. Return 1 if num is the same or higher as edge2 and smoothly interpolate between 0 and 1 for all other values.

lua.wetgenes.tardis.step

i = tardis.step(edge,num)

return 0 if num is bellow edge or 1 if num is the same or higher

lua.wetgenes.tardis.type

name=tardis.type(object)

This will return the type of an object previously registered with class

lua.wetgenes.tardis.v1

The metatable for a 2d vector class, use the new function to actually create an object.

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.v1.add

v1 = v1:add(v1b)
v1 = v1:add(v1b,r)

Add v1b to v1.

If r is provided then the result is written into r and returned otherwise v1 is modified and returned.

lua.wetgenes.tardis.v1.cross

value = v1:cross(v1b)

Extend to 3d then only return z value as x and y are always 0

lua.wetgenes.tardis.v1.distance

value = a:distance(b)

Returns the length of the vector between a and b.

lua.wetgenes.tardis.v1.dot

value = v1:dot(v1b)

Return the dot product of these two vectors.

lua.wetgenes.tardis.v1.lenlen

value = v1:lenlen()

Returns the length of this vector, squared, this is often all you need for comparisons so lets us skip the sqrt.

lua.wetgenes.tardis.v1.mul

v1 = v1:mul(v1b)
v1 = v1:mul(v1b,r)

Multiply v1 by v1b.

If r is provided then the result is written into r and returned otherwise v1 is modified and returned.

lua.wetgenes.tardis.v1.normalize

v1 = v1:normalize()
v1 = v1:normalize(r)

Adjust the length of this vector to 1.

An input length of 0 will remain at 0.

If r is provided then the result is written into r and returned otherwise v1 is modified and returned.

lua.wetgenes.tardis.v1.oo

v1 = v1:oo()
v1 = v1:oo(r)

One Over value. Build the reciprocal of all elements.

If r is provided then the result is written into r and returned otherwise v1 is modified and returned.

lua.wetgenes.tardis.v1.scale

v1 = v1:scale(s)
v1 = v1:scale(s,r)

Scale this v1 by s.

If r is provided then the result is written into r and returned otherwise v1 is modified and returned.

lua.wetgenes.tardis.v1.sub

v1 = v1:sub(v1b)
v1 = v1:sub(v1b,r)

Subtract v1b from v1.

If r is provided then the result is written into r and returned otherwise v1 is modified and returned.

lua.wetgenes.tardis.v2

The metatable for a 2d vector class, use the new function to actually create an object.

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.v2.add

v2 = v2:add(v2b)
v2 = v2:add(v2b,r)

Add v2b to v2.

If r is provided then the result is written into r and returned otherwise v2 is modified and returned.

lua.wetgenes.tardis.v2.cross

value = v2:cross(v2b)

Extend to 3d then only return z value as x and y are always 0

lua.wetgenes.tardis.v2.distance

value = a:distance(b)

Returns the length of the vector between a and b.

lua.wetgenes.tardis.v2.dot

value = v2:dot(v2b)

Return the dot product of these two vectors.

lua.wetgenes.tardis.v2.lenlen

value = v2:lenlen()

Returns the length of this vector, squared, this is often all you need for comparisons so lets us skip the sqrt.

lua.wetgenes.tardis.v2.mul

v2 = v2:mul(v2b)
v2 = v2:mul(v2b,r)

Multiply v2 by v2b.

If r is provided then the result is written into r and returned otherwise v2 is modified and returned.

lua.wetgenes.tardis.v2.new

v2 = tardis.v2.new()

Create a new v2 and optionally set it to the given values, v2 methods usually return the input v2 for easy function chaining.

lua.wetgenes.tardis.v2.normalize

v2 = v2:normalize()
v2 = v2:normalize(r)

Adjust the length of this vector to 1.

An input length of 0 will remain at 0.

If r is provided then the result is written into r and returned otherwise v2 is modified and returned.

lua.wetgenes.tardis.v2.oo

v2 = v2:oo()
v2 = v2:oo(r)

One Over value. Build the reciprocal of all elements.

If r is provided then the result is written into r and returned otherwise v2 is modified and returned.

lua.wetgenes.tardis.v2.scale

v2 = v2:scale(s)
v2 = v2:scale(s,r)

Scale this v2 by s.

If r is provided then the result is written into r and returned otherwise v2 is modified and returned.

lua.wetgenes.tardis.v2.sub

v2 = v2:sub(v2b)
v2 = v2:sub(v2b,r)

Subtract v2b from v2.

If r is provided then the result is written into r and returned otherwise v2 is modified and returned.

lua.wetgenes.tardis.v3

The metatable for a 3d vector class, use the new function to actually create an object.

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.v3.add

v3 = v3:add(v3b)
v3 = v3:add(v3b,r)

Add v3b to v3.

If r is provided then the result is written into r and returned otherwise v3 is modified and returned.

lua.wetgenes.tardis.v3.angle

radians,axis = v3a:angle(v3b)
radians,axis = v3a:angle(v3b,axis)

Return radians and axis of rotation between these two vectors. If axis is given then it must represent a positive world aligned axis normal. So V3(1,0,0) or V3(0,1,0) or V3(0,0,1) only. The point of providing an axis allows the returned angle to be over a 360 degree range rather than flipping the axis after 180 degrees this means the second axis returned value can be ignored as it will always be the axis that is passed in.

lua.wetgenes.tardis.v3.cross

v3 = v3:cross(v3b)
v3 = v3:cross(v3b,r)

Return the cross product of these two vectors.

If r is provided then the result is written into r and returned otherwise v3 is modified and returned.

lua.wetgenes.tardis.v3.distance

value = a:distance(b)

Returns the length of the vector between a and b.

lua.wetgenes.tardis.v3.dot

value = v3:dot(v3b)

Return the dot product of these two vectors.

lua.wetgenes.tardis.v3.lenlen

value = v3:lenlen()

Returns the length of this vector, squared, this is often all you need for comparisons so lets us skip the sqrt.

lua.wetgenes.tardis.v3.mul

v3 = v3:mul(v3b)
v3 = v3:mul(v3b,r)

Multiply v3 by v3b.

If r is provided then the result is written into r and returned otherwise v3 is modified and returned.

lua.wetgenes.tardis.v3.new

v3 = tardis.v3.new()

Create a new v3 and optionally set it to the given values, v3 methods usually return the input v3 for easy function chaining.

lua.wetgenes.tardis.v3.normalize

v3 = v3:normalize()
v3 = v3:normalize(r)

Adjust the length of this vector to 1.

An input length of 0 will remain at 0.

If r is provided then the result is written into r and returned otherwise v3 is modified and returned.

lua.wetgenes.tardis.v3.oo

v3 = v3:oo()
v3 = v3:oo(r)

One Over value. Build the reciprocal of all elements.

If r is provided then the result is written into r and returned otherwise v3 is modified and returned.

lua.wetgenes.tardis.v3.scale

v3 = v3:scale(s)
v3 = v3:scale(s,r)

Scale this v3 by s.

If r is provided then the result is written into r and returned otherwise v3 is modified and returned.

lua.wetgenes.tardis.v3.sub

v3 = v3:sub(v3b)
v3 = v3:sub(v3b,r)

Subtract v3b from v3.

If r is provided then the result is written into r and returned otherwise v3 is modified and returned.

lua.wetgenes.tardis.v4

The metatable for a 4d vector class, use the new function to actually create an object.

We also inherit all the functions from tardis.array

lua.wetgenes.tardis.v4.add

v4 = v4:add(v4b)
v4 = v4:add(v4b,r)

Add v4b to v4.

If r is provided then the result is written into r and returned otherwise v4 is modified and returned.

lua.wetgenes.tardis.v4.distance

value = a:distance(b)

Returns the length of the vector between a and b.

lua.wetgenes.tardis.v4.dot

value = v4:dot(v4b)

Return the dot product of these two vectors.

lua.wetgenes.tardis.v4.lenlen

value = v4:lenlen()

Returns the length of this vector, squared, this is often all you need for comparisons so lets us skip the sqrt.

lua.wetgenes.tardis.v4.mul

v4 = v4:mul(v4b)
v4 = v4:mul(v4b,r)

Multiply v4 by v4b.

If r is provided then the result is written into r and returned otherwise v4 is modified and returned.

lua.wetgenes.tardis.v4.new

v4 = tardis.v4.new()

Create a new v4 and optionally set it to the given values, v4 methods usually return the input v4 for easy function chaining.

lua.wetgenes.tardis.v4.normalize

v4 = v4:normalize()
v4 = v4:normalize(r)

Adjust the length of this vector to 1.

An input length of 0 will remain at 0.

If r is provided then the result is written into r and returned otherwise v4 is modified and returned.

lua.wetgenes.tardis.v4.oo

v4 = v4:oo()
v4 = v4:oo(r)

One Over value. Build the reciprocal of all elements.

If r is provided then the result is written into r and returned otherwise v4 is modified and returned.

lua.wetgenes.tardis.v4.scale

v4 = v4:scale(s)
v4 = v4:scale(s,r)

Scale this v4 by s.

If r is provided then the result is written into r and returned otherwise v4 is modified and returned.

lua.wetgenes.tardis.v4.sub

v4 = v4:sub(v4b)
v4 = v4:sub(v4b,r)

Subtract v4b from v4.

If r is provided then the result is written into r and returned otherwise v4 is modified and returned.

lua.wetgenes.tardis.v4.to_v3

v3 = v4:to_v3()
v3 = v4:to_v3(r)

scale [4] to 1 then throw it away so we have a v3 xyz

If r is provided then the result is written into r and returned otherwise a new v3 is created and returned.

lua.wetgenes.tasks

local tasks=require("wetgenes.tasks").create()

Manage tasks that should be performed on seperate threads so as not to block the main thread.

Manage coroutines that can then easily call into these threads by yeilding

lua.wetgenes.tasks.add_global_thread

tasks:add_global_thread(thread)

This runs an add_thread inside a named thread so all threads are kept together no matter which thread tried to start it.

thread is the same as add_thread

if the thread id already exists then it will not be added again.

lua.wetgenes.tasks.add_id

tasks:add_id(it)

Internal function to manage creation of all objects with unique ids.

lua.wetgenes.tasks.add_memo

local memo=tasks:add_memo({})

Create a memo with a unique auto generated numerical id for linda comunication.

lua.wetgenes.tasks.add_task

local thread=tasks:add_task({
    id="test",
    code=function(linda,task_id,task_idx,task)
        while true do
            local _,memo= linda:receive( 0 , task_id )
            if memo then
                ...
            end
        end
    end,
})

Create a task with various preset values similar to a thread except inside a coroutine on the calling thread. As this function is inside a coroutine you must yield regulary this yield will then continue on the next update. Probably called once ever 60th of a second.

id

A unique id string to be used by lindas when sending messages into this task. The function is expected to sit in an infinite loop testing this linda socket and then yielding if there is nothing to do.

count

The number of tasks to create, they will all use the same instanced code function so should be interchangable and it should not matter which task we are actually running code on. If you expect the task to maintain some state between memos, then this must be 1 .

code

A lua function to run inside a coroutine, this function will recieve tasks.linda (which is a colinda) and the task.id for comunication and an index so we know which of the count tasks we are (mostly for debugging) and finally the task table itself which make sense to share with coroutines.

lua.wetgenes.tasks.add_thread

local thread=tasks:add_thread({
    id="test",
    count=1,
    code=function(linda,task_id,task_idx)
        while true do
            local _,memo= linda:receive( nil , task_id )
            if memo then
                ...
            end
        end
    end,
})

Create a thread with various preset values:

id

A unique id string to be used by lindas when sending messages into this task. The function is expected to sit in an infinite loop waiting on this linda socket.

count

The number of threads to create, they will all use the same instanced code function so should be interchangable and it should not matter which thread we are actually running code on. If you expect the task to maintain some state between memos, then this must be 1 .

code

A lua function to run inside each thread, this function will recieve tasks.linda and the task.id for comunication and an index so we know which of the count threads we are (mostly for debugging)

lua.wetgenes.tasks.claim_global

tasks:claim_global(name,value)

Claim a name using the global linda socket, returns value on success or false on failure.

The value will be associated with the name on success.

This will block waiting on a result but should be fast.

lua.wetgenes.tasks.client

Send and/or recieve a (web)socket client memo result.

returns nil,error if something went wrong or returns result if something went right.

lua.wetgenes.tasks.cocall

require("wetgenes.tasks").cocall(f1,f2,...)
require("wetgenes.tasks").cocall({f1,f2,...})

Manage simple coroutines that can poll each others results and wait on them.

Turn a table of "setup" functions into a table of coroutines that can yield waiting for other coroutines to complete and run them all.

You still need to be carefull with race conditions but it allows you to write code in such away that setup order is no longer important. Setup functions can coroutine.yield waiting for another setup to finish first.

lua.wetgenes.tasks.create

Create a tasks group to contain all associated threads and coroutines along with their comunications.

lua.wetgenes.tasks.create_colinda

local colinda=require("wetgenes.tasks").colinda(linda)

Create a colinda which is a wrapper around a linda providing replacement functions to be used inside a coroutine so it will yield (and assume it will be resumed) rather than wait.

This should be a dropin replacement for a linda and will fallback to normal linda use if not in a coroutine.

If linda is nil then we will create one, the linda used in this colinda can be found in colinda.linda if you need raw access.

What we are doing here is wrapping the send/receive functions so that

colinda:send(time,...)
colinda:recieve(time,...)

will be replaced with functions that call

linda:send(0,...)
linda:recieve(0,...)

and use coroutines.yield to mimic the original timeout value without blocking.

lua.wetgenes.tasks.del_global_thread

tasks:del_global_thread({id="threadname"})

Destroy a given thread.id or all the threads if thread is nil.

lua.wetgenes.tasks.del_id

tasks:del_id(it)

Internal function to manage deletion of all objects with unique ids.

lua.wetgenes.tasks.delete

tasks:delete()

Force stop all threads and delete all data.

Failure to call this will allow any created threads to continue to run until program termination.

lua.wetgenes.tasks.do_memo

result = tasks:do_memo(memo,timeout)
result = tasks:do_memo(memo)

Similar to calling tasks:receive but without the problems that come from me trying to remember how to spell receive and it returns memo.result instead of memo so slightly less mess. This will assert on finding a memo.error so less need to check for errors.

lua.wetgenes.tasks.eject_global

tasks:eject_global(name)

Eject a name using the global linda socket, returns value associated with name on success or false on failure.

The value will no longer be associated with the name when this succeeds.

This will block waiting on a result but should be fast.

lua.wetgenes.tasks.fetch_name

tasks:fetch_global(name)

Fetch value associated with the name using the global linda socket or false on failure. You can not associated nil or false with a global value.

This will block waiting on a result but should be fast.

lua.wetgenes.tasks.global_code

A basic function to handle global memos to get/set data shared amongst multiple tasks.

lua.wetgenes.tasks.http

Create send and return a http memo result.

Returns either the result or nil,error so can be used simply with an assert wrapper.

lua.wetgenes.tasks.receive

memo = tasks:receive(memo,timeout)
memo = tasks:receive(memo)

Recieve a memo with optional timeout.

This is intended to be run from within a coroutine task on the main thread. It will work outside of a task but that will block the main thread waiting for a response.

The memo will be deleted after being recieved (ie we will have called del_memo) so as to free up its comunication id for another memo.

if the memo has not yet been sent or even been through add_memo (we check state for "setup" or nil) then it will be autosent with the same timeout before we try and receive it.

After calling check if memo.error is nil then you will find the result in memo.result

lua.wetgenes.tasks.run_task

tasks:run_task(task)

Resume all the coroutines in this task.

Any errors will be logged with a backtrace.

If the tasks have finished running (returned or crashed) then we will tasks:del_task(task) this task. Check task.id which will be nil after this task has finished.

lua.wetgenes.tasks.send

memo = tasks:send(memo,timeout)
memo = tasks:send(memo)

Send a memo with optional timeout.

This is intended to be run from within a coroutine task on the main thread. It will work outside of a task but that may block the main thread waiting to send.

if memo.id is not set then we will auto call add_memo to create it.

Check memo.error for posible error, this will be nil if everything went OK.

lua.wetgenes.tasks.sqlite

Create send and return a sqlite memo result.

Returns either the result.rows or nil,error so can be used simply with an assert wrapper.

Note that rows can be empty so an additional assert(rows[1]) might be needed to check you have data returned.

lua.wetgenes.tasks.sqlite_code

A basic function to handle sqlite memos.

As we are opening an sqlite database here it wont help much to have more than one thread per database as they will just fight over file access.

lua.wetgenes.tasks.thread_code

Handle global tasks, starting and stopping and preventing the starting of multiple copies of the same task.

lua.wetgenes.tasks.update

tasks:update()

Resume all current coroutines and wait for them to yield.

lua.wetgenes.tasks_msgp

local msgp=require("wetgenes.tasks_msgp")

A stream of lowlevel udp packets with automatic resend ( data will get there eventual ) but hopefully without clogging up an ongoing pulse of smaller packets that contain EG controller state.

We use lua sockets and lanes with some help from wetgenes.tasks to manage the lanes.

Simple UDP data packets with auto resend, little endian with this 6 byte header.

u16		idx			//	incrementing and wrapping idx of this packet
u16		ack			//	we acknowledge all the packets before this idx so please send this one next (or again maybe)
u8		bit			//	which bit this is, all bits should be joined before parsing
u8		bits		//	how many bits in total ( all bits will be in adjacent idxs )
u8		data[*]		//	The payload, if multiple bits then all payloads should be concatenated

A maximum packet size of 63k seems to give good throughput, letting the lower level code split and recombine packets is probably going to be more efficient than us. Note that we care about best case speed, when shit lags and packets drop we care less about performance and more about maintaining a connection with correct state. IE its important that we recover not that we pretend there is no problem. At 255 bits * 63k bit size we can seen a data of about 15.6m.

Technically 63k UDP packets might just get dropped as too big but I suspect modern hardware is not really going to cause problems.

bit/bits only goes up to 255. the 0 value in either of these is reserved as a flag for possible slightly strange packets in the future eg maybe we need a ping? and should be ignored as a bad packet if you do not understand them.

An ack of 0x1234 also implies that 0x9234 to 0x1233 are in the past and 0x1234 to 0x9233 are in the future.

Also if we have nothing new to say after 100ms but have received new packets then we can send a packet with empty data (0 length) as an ack only packet.

When connecting to a port for the first time, the idx value must start at a special number, that number is configurable and should be different for each app. An extra bit of sanity during introductions to indicate that the data stream will be understood by both parties.

Special packets that do not add to the stream of user data but instead are used internally by this protocol.

id		bits	bit
PING	0x00	0x02
PONG	0x00	0x03
HAND	0x00	0x04
SHAKE	0x00	0x05
RESEND	0x00	0x08
PULSE	0x00	0x10

A PING packet will be accepted and acknowledged after handshaking. Sending a PING packet will cause a PONG response with the same data.

A PONG packet will be accepted and acknowledged after handshaking, its data should be the same as the PING it is responding too.

A HAND packet begins handshaking, the payload data is a string array. Consisting of a series of null terminated utf8 strings.

A SHAKE packet ends handshaking The payload data is a string array. Consisting of a series of null terminated utf8 strings.

Both the HAND and the SHAKE packets contain the same payload data which consists of the following utf8 strings, each terminated by a 0 byte.

host name
host ip4
host ip6
host port
client addr

When received, each of the strings should to be clamped to 255 bytes and the values validated or replaced with empty strings before use.

host name is maybe best considered a random string, it could be anything.

host ip4 will be the hosts best guess at their ip4, it is the ip4 they are listening on.

host ip6 will be the hosts best guess at their ip6, it is the ip6 they are listening on.

host port will be the local port the host is listening on, ip4 and ip6, but as they may be port forwarding we might connect on a different port.

client addr is the client ip and port the sender sent this packet too. If ipv4 it will be a string of the format "1.2.3.4:5" and if 1pv6 then "[1::2]:3" So the ip possibly wrapped in square brackets (ipv6) and then a colon followed by the port in url style format.

A RESEND packet consists of a payload of little endian 16bit idxs to packets we would like to be resent to fill in missing data.

A PULSE packet contains user data but does not get resent or acknowledged, its IDX must be set to 0 and this IDX should be ignored when received as this is out of stream data. Pulse packets are small regular packets of user data, eg current client input state. Data sent is included as part of the normal received data stream but there is no guarantee that it will be delivered or when it will be delivered relative to other data. The data must be small enough to fit in a single packet. Think of this as something of a raw UDP packet in terms of how it works.

lua.wetgenes.tasks_msgp.addr_to_ip_port

parse an ip string and port number from an addr/addr+port/addr_list

returns addr,port that we can then use with luasocket

lua.wetgenes.tasks_msgp.addr_to_list

parse an ip address + maybe port encoded as a string into a list of numbers, the length of the list represents the type so

#4 {1,2,3,4} -- ip4
#5 {1,2,3,4,5} -- ip4:port
#8 {1,2,3,4,5,6,7,8} -- ip6
#9 {1,2,3,4,5,6,7,8,9} -- [ip6]:port

Optionally include a numeric port to add/replace in the list after parsing.

lua.wetgenes.tasks_msgp.clean_name

Clean a hostname so it becomes upercase letters and numbers with possible underscores where any other chars would be, eg whitespace.

we also try not to start or end with an _

lua.wetgenes.tasks_msgp.ip6_to_addr

Parse an array of 8 numbers into an ip6 address with :: in the first longest run of zeros if needed and lowercase hex letters.

lua.wetgenes.tasks_msgp.ipsniff

Use ( google by default ) public dns servers to check if we can connect to the internet and if we have ipv4 and/or ipv6 available.

To use alternative dns pass in an ipv4 and ipv6 address as the first two args, eg to use cloudflare.

ipsniff("1.1.1.1","2606:4700:4700::1111")

returns the ipv4,ipv6 address of this host when connecting to that dns or nil if no connection possible.

This result can be used as a bool to indicate working ipv6 or ipv4 internet and is also a best guess as to our ip when connecting to other devices.

Note that this will only work if we are connected to the internet can reach the dns servers etc etc, standard networks can be crazy disclaimer applies.

So great if this works but still need a fallback plan, eg assuming local ipv4 network is available.

lua.wetgenes.tasks_msgp.list_to_addr

Parse an array of numbers into an ip address and maybe port.

#4 {1,2,3,4} -- ip4
#5 {1,2,3,4,5} -- ip4:port
#8 {1,2,3,4,5,6,7,8} -- ip6
#9 {1,2,3,4,5,6,7,8,9} -- [ip6]:port

lua.wetgenes.tasks_msgp.pack

If given aa udp data packet string, convert it to a table.

If given table, convert it to a udp data packet string. little endian

u16		idx			//	incrementing and wrapping idx of this packet
u16		ack			//	we acknowledge all the packets before this idx so please send this one next (or again maybe)
u8		bit			//	which bit this is, all bits should be joined before parsing
u8		bits		//	how many bits in total ( all bits will be in adjacent idxs )
u8		data[*]		//	The payload, if multiple bits then all payloads should be concatenated

lua.wetgenes.tsv

(C) 2020 Kriss Blank under the https://opensource.org/licenses/MIT

local wtsv = require("wetgenes.tsv")

Load and save tsv files https://pypi.org/project/linear-tsv/1.0.0/

The following need to be escaped with a \ when used in each column.

\n for newline,
\t for tab,
\r for carriage return,
\\ for backslash.

When loading we read the entire file and keep all the text in one string with function lookups to cut out sections of that string as needed.

lua.wetgenes.tsv.create

wtsv.create()
wtsv.create({filename="filename.tsv"})
wtsv.create({basedata="1\t2\t3\n4\t5\t6\n"})

Create a tsv, possibly from a datachunk or file

lua.wetgenes.txt.diff

(C) 2020 Kriss Blank and released under the MIT license, see http://opensource.org/licenses/MIT for full license text.

local wtxtdiff=require("wetgenes.txt.diff")

lua.wetgenes.txt.diff.find

Given two tables of strings, return the length , starta , startb of the longest common subsequence in table indexes or nil if not similar.

lua.wetgenes.txt.diff.match

Given two tables of strings, return two tables of strings of the same length where as many strings as possible match.

lua.wetgenes.txt.diff.split

Use the delimiter to split a string into a table of strings such that each string ends in the delimiter (except for possibly the final string) and a table.concat on the result will recreate the input string exactly.

table = wtxtdiff.split(string,delimiter)

String is the string to split and delimiter is a lua pattern so any special chars should be escaped.

for example

st = wtxtdiff.split(s) -- split on newline (default)
st = wtxtdiff.split(s,"\n") -- split on newline (explicit)

st - wtxtdiff.split(s,"%s+") -- split on white space

lua.wetgenes.txt.diff.trim

Given two tables of strings, return the length at the start and at the end that are the same. This tends to be a good first step when comparing two chunks of text.

lua.wetgenes.txt.lex

(C) 2020 Kriss Blank under the https://opensource.org/licenses/MIT


Some useful lex files for other editors to be used as starting points and checking we did not miss anything.

https://github.com/vim/vim/tree/master/runtime/syntax
https://github.com/sublimehq/Packages

lua.wetgenes.txt.undo

(C) 2020 Kriss Blank under the https://opensource.org/licenses/MIT

undo / redo code for a text editor with persistence to disk

persistance to disk is in tsv format filename.txt.undo files where a .undo is added to the end of the file.

see https://pypi.org/project/linear-tsv/1.0.0/ for tsv format the first most column is always a command and the other columns are data needed to apply/reverse this command in theory a .undo file is a total history and as we should only be appending data (lines at a time even) then a file can be recovered from it and it should have limited corruption possibilities when things go wrong.

For security reasons this file may have undos removed as a separate step. That is to say things that where done / pasted accidentality then removed instantly will be purged from its history when performing a file save.

You can be save in the knowledge that any information you undo will not be saved except as temporary crash safe buffers.

The following need to be escaped with a \ when used in each column.

\n for newline,
\t for tab,
\r for carriage return,
\\ for backslash.

lua.wetgenes.txt.utf

(C) 2020 Kriss Blank under the https://opensource.org/licenses/MIT

local wutf = require("wetgenes.txt.utf")

helper functions to help manage a string as a stream of utf8 tokens.

lua.wetgenes.txt.utf.char

string = wutf.char(number)

convert a single unicode value to a utf8 string of 1-4 bytes

lua.wetgenes.txt.utf.charpattern

string:gmatch(wutf.charpattern)

lua pattern to match each utf8 character in a string

lua.wetgenes.txt.utf.chars

string = wutf.chars(number,number,...)
string = wutf.chars({number,number,...})

convert one or more unicode values into a utf8 string

lua.wetgenes.txt.utf.length

unicode = wutf.ncode(string,index)

get the utf8 value at the given code index.

Note that this is slower than wutf.code as we must search the string to find the byte index of the code.

lua.wetgenes.txt.utf.map_unicode_to_latin0

latin0 = wutf.map_unicode_to_latin0[unicode] or unicode

I prefer the coverage of latin0 (ISO/IEC 8859-15) for font layout as it is just a few small differences for western european languages to get most needed glyphs into the first 256 codes.

lua.wetgenes.txt.utf.size

size = wutf.size(string,index)

get the size in bytes of the utf8 value at the given byte index.

size = wutf.size(string)

get the size in bytes of the utf8 value at the start of this string

The return value will be 1-4 as 4 is the biggest utf8 code size.

lua.wetgenes.txt.utf.string

unicode = wutf.code(string,index)

get the utf8 value at the given byte index.

unicode = wutf.code(string)

get the utf8 value at the start of this string

lua.wetgenes.txt.words

(C) 2023 Kriss Blank and released under the MIT license, see http://opensource.org/licenses/MIT for full license text.

local wtxtwords=require("wetgenes.txt.words")

See https://github.com/xriss/engrish for source of words and possible alternative licenses.

lua.wetgenes.txt.words.load

yes = wtxtwords.check(word)

This is a fast check if the word exists.

May call wtxtwords.load() to auto load data.

lua.wetgenes.txt.words.transform

list = wtxtwords.transform(word,count,addletters,subletters)

Returns a table of upto count correctly spelled words that you may have miss spelt given the input word ordered by probability.

If the input word is spelled correctly then it will probably be the first word in this list but that is not guaranteed.

addletters is the maximum number of additive transforms, the higher this number the slower this function and it defaults to 4.

subletters is the maximum number of subtractive transforms and will not have much impact on speed, this defaults to the same value as addletters.

We run subletters subtractive transforms on our starting word and then we scan all possible words and perform addletters number of subtractive transforms on them and see if they match any of the transforms we built from our starting word. A match then means we can add up the number of transforms on both sides and that is how many steps it would take to get from one word to another by adding and subtracting letters.

prefabs

The yarn building blocks, recipes to build items from, multiple rules can be assigned to each item.

setup

Called once to setup things in the first update loop after hardware has been initialised.

setup_menu

menu = setup_menu()

Create a displayable and controllable menu system that can be fed chat data for user display.

After setup, provide it with menu items to display using menu.show(items) then call update and draw each frame.

update

update()

Update and draw loop, called every frame.