How do I control the output of a custom post type in the loop?

I assume that you’re making your custom post type in a plugin if you mean for it to work with any theme.

In that case, I would suggest building your templates in your plugin, and call all your meta data there.

Example:

/* Filter the single_template with our custom function*/
add_filter('single_template', 'my_custom_template');

function my_custom_template($single) {

    global $post;

    /* Checks for single template by post type */
    if ( $post->post_type == 'POST TYPE NAME' ) {
        if ( file_exists( PLUGIN_PATH . '/Custom_File.php' ) ) {
            return PLUGIN_PATH . '/Custom_File.php';
        }
    }

    return $single;

}

You can refine that further and add a function to check to see if the theme has single-yourposttype.php and to use that one if it exists instead of your plugin version, allowing for easy overrides by developers. Example:

    $themeurl  = get_theme_file_path("/single-yourposttype.php");
    $pluginurl = plugin_dir_path( dirname( __FILE__ ) ) . 'single-yourposttype.php';

    if( file_exists( $themeurl ) ) {
        include( $themeurl );
    } elseif( file_exists( $pluginurl ) ) {

        require "$pluginurl";
    }

I hope that helps.