the asumptions were of course, incorrect
[convexer.git] / cxr / cxr.h
index bb904c4d00ba8ce0522935f03787d0145e11c4e8..644c8ed83e39381e88ceb5c3beeb4772e29f3be3 100644 (file)
--- a/cxr/cxr.h
+++ b/cxr/cxr.h
@@ -1,11 +1,13 @@
 /*
-                              CONVEXER v0.9
+                              CONVEXER v0.95
 
                A GNU/Linux-first Source1 Hammer replacement
                     built with Blender, for mapmakers
 
                   Copyright (C) 2022 Harry Godden (hgn)
 
+LICENSE: GPLv3.0, please see COPYING and LICENSE for more information
+
    Features:
       - Brush decomposition into convex pieces for well defined geometry
       - Freely form displacements without limits
@@ -13,7 +15,8 @@
       - Compile models and model groups easily
       - It runs at an ok speed!
       - Light patch BSP files; remove unwanted realtime effects
-      - Fastest VTF compressor (thanks to Richgel999 and stb)
+      - Bestest VTF compressor (thanks to Richgel999 and stb)
+      - Pack content automatically
 
    Program structure:
 
@@ -45,7 +48,6 @@
    IMPLEMENTATION
 */
 
-#define CXR_API 
 #define CXR_EPSILON 0.001
 #define CXR_PLANE_SIMILARITY_MAX 0.998
 #define CXR_BIG_NUMBER 1e300
 
 #include <stdio.h>
 #include <math.h>
-#include <stdint.h>
-#include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 
-typedef uint8_t        u8;
-typedef uint16_t       u16;
-typedef uint32_t       u32;
-typedef uint64_t       u64;
-typedef int8_t         i8;
-typedef int16_t        i16;
-typedef int32_t        i32;
-typedef int64_t        i64;
-
-typedef unsigned int uint;
-
-typedef double         v2f[2];
-typedef double         v3f[3];
-typedef double         v4f[4];
-typedef v3f                    m3x3f[3];
-typedef v3f                    m4x3f[4];
-typedef v3f                    boxf[2];
-
+#include "cxr_types.h"
 #include "cxr_math.h"
 #include "cxr_mem.h"
+#include "cxr_log.h"
+
+#ifdef CXR_VALVE_BIN
+ #include "cxr_valve_bin.h"
+#endif
 
 typedef struct cxr_world cxr_world;
 typedef struct cxr_solid cxr_solid;
@@ -98,6 +86,7 @@ typedef struct cxr_tri_mesh cxr_tri_mesh;
 #ifdef CXR_VALVE_MAP_FILE
  typedef struct cxr_vdf cxr_vdf;
  typedef struct cxr_texinfo cxr_texinfo;
+ typedef struct cxr_visgroup cxr_visgroup;
  typedef struct cxr_vmf_context cxr_vmf_context;
 #endif /* CXR_VALVE_MAP_FILE */
 
@@ -146,7 +135,7 @@ struct cxr_static_mesh
    struct cxr_edge
    {
       i32 i0, i1;
-      i32 freestyle;
+      i32 freestyle, sharp;
    }
    *edges;
 
@@ -155,6 +144,7 @@ struct cxr_static_mesh
       i32 index,
           edge_index;
       v2f uv;
+      double alpha;
    }
    *loops;
 
@@ -170,7 +160,7 @@ struct cxr_static_mesh
    struct cxr_material
    {
       i32 res[2];
-      const char *name;
+      char *name;
    }
    *materials;
 
@@ -188,6 +178,7 @@ struct cxr_loop
        edge_index,
        index;
    v2f uv;
+   float alpha;
 };
 
 struct cxr_solid
@@ -226,8 +217,11 @@ struct cxr_mesh
 /* Simple mesh type mainly for debugging */
 struct cxr_tri_mesh
 {
-   v3f *vertices;
+   v3f *vertices,
+       *normals;
+   v2f *uvs;
    v4f *colours;
+
    i32 *indices,
         indices_count,
         vertex_count;
@@ -241,6 +235,11 @@ struct cxr_texinfo
    double winding;
 };
 
+struct cxr_visgroup
+{
+   const char *name;
+};
+
 /* 
  * Simplified VDF writing interface. No allocations or nodes, just write to file
  */
@@ -258,10 +257,14 @@ struct cxr_vmf_context
               *detailvbsp,
               *detailmaterial;
 
+   cxr_visgroup *visgroups;
+   i32 visgroup_count;
+
    /* Transform settings */
    double scale;
    v3f offset;
-   i32 lightmap_scale;
+   i32 lightmap_scale,
+       visgroupid;
 
    /* Current stats */
    i32 brush_count,
@@ -278,7 +281,9 @@ enum cxr_soliderr
    k_soliderr_no_solids,
    k_soliderr_degenerate_implicit,
    k_soliderr_non_coplanar_vertices,
-   k_soliderr_non_convex_poly
+   k_soliderr_non_convex_poly,
+   k_soliderr_bad_result,
+   k_soliderr_invalid_input
 };
 
 /*
@@ -290,8 +295,12 @@ enum cxr_soliderr
   const char *cxr_build_time = __DATE__ " @" __TIME__;
  #endif
 
-static void (*cxr_log_func)(const char *str);
-static void (*cxr_line_func)( v3f p0, v3f p1, v4f colour );
+#if _WIN32 || _WIN64
+#if _WIN64
+#else
+#warning 32 bit is not supported in blender 3.0
+#endif
+#endif
 
 static int cxr_range(int x, int bound)
 {
@@ -367,21 +376,6 @@ static void colour_random_brush(int n, v4f colour)
 
 #ifdef CXR_DEBUG
 
-static void cxr_log( const char *fmt, ... )
-{
-   char buf[512];
-
-   va_list args;
-   va_start( args, fmt );
-   vsnprintf( buf, sizeof(buf)-1, fmt, args );
-   va_end(args);
-
-   if( cxr_log_func )
-      cxr_log_func( buf );
-
-   fputs(buf,stdout);
-}
-
 static void cxr_debug_line( v3f p0, v3f p1, v4f colour )
 {
    if( cxr_line_func )
@@ -489,16 +483,19 @@ CXR_API void cxr_write_test_data( cxr_static_mesh *src )
    }
    fprintf( fp, "};\n" );
 
-   fprintf( fp, "struct cxr_static_loop test_loops[] = {\n" );
+   fprintf( fp, "cxr_static_loop test_loops[] = {\n" );
    for( int i=0; i<src->loop_count; i ++ )
    {
-      fprintf( fp, "   {%d, %d},\n",
+      fprintf( fp, "   {%d, %d, {%f, %f}, %f},\n",
          src->loops[i].index,
-         src->loops[i].edge_index);
+         src->loops[i].edge_index,
+         src->loops[i].uv[0],
+         src->loops[i].uv[1],
+         src->loops[i].alpha );
    }
    fprintf( fp, "};\n" );
 
-   fprintf( fp, "struct cxr_polygon test_polys[] = {\n" );
+   fprintf( fp, "cxr_polygon test_polys[] = {\n" );
    for( int i=0; i <src->poly_count; i++ )
    {
       fprintf( fp, "   {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
@@ -513,18 +510,19 @@ CXR_API void cxr_write_test_data( cxr_static_mesh *src )
    }
    fprintf( fp, "};\n" );
 
-   fprintf( fp, "struct cxr_edge test_edges[] = {\n" );
+   fprintf( fp, "cxr_edge test_edges[] = {\n" );
    for( int i=0; i<src->edge_count; i++ )
    {
-      fprintf( fp, "   {%d, %d, %d},\n",
+      fprintf( fp, "   {%d, %d, %d, %d},\n",
          src->edges[i].i0,
          src->edges[i].i1,
-         src->edges[i].freestyle
+         src->edges[i].freestyle,
+         src->edges[i].sharp
       );
    }
    fprintf( fp, "};\n" );
 
-   fprintf( fp, "struct cxr_static_mesh test_mesh = {\n" );
+   fprintf( fp, "cxr_static_mesh test_mesh = {\n" );
    fprintf( fp, "   .vertices = test_verts,\n" );
    fprintf( fp, "   .loops = test_loops,\n" );
    fprintf( fp, "   .edges = test_edges,\n" );
@@ -621,10 +619,12 @@ static void cxr_mesh_clean_edges( cxr_mesh *mesh )
          {
             cxr_edge *orig_edge = &mesh->edges[ orig_edge_id ];
             edge.freestyle = orig_edge->freestyle;
+            edge.sharp = orig_edge->sharp;
          }
          else
          {
             edge.freestyle = 0;
+            edge.sharp = 0;
          }
 
          cxr_ab_push( &new_edges, &edge );
@@ -711,9 +711,15 @@ static int cxr_mesh_link_loops( cxr_mesh *mesh )
             if( *edge == -1 )
             {
                *edge = i;
-               break;
+               goto next;
             }
          }
+         
+         /* Overflowed edge mapping... Duplicated faces. */
+         free( polygon_edge_map );
+         return 0;
+
+         next:;
       }
    }
    for( int i = 0; i < mesh->abpolys.count; i ++ )
@@ -1001,7 +1007,7 @@ static int *cxr_mesh_reflex_edges( cxr_mesh *mesh )
       edge_tagged[lp->edge_index] = 0;
 
       cxr_polygon *polya = &mesh->polys[ lp->poly_left ],
-                         *polyb = &mesh->polys[ lp->poly_right ];
+                  *polyb = &mesh->polys[ lp->poly_right ];
 
       v4f planeb;
       normal_to_plane(polyb->normal, polyb->center, planeb);
@@ -1320,16 +1326,66 @@ static void cxr_link_manifold(
    struct temp_manifold *manifold
 ){
    cxr_loop **edge_list = malloc( sizeof(*edge_list) * solid->edge_count );
+   int *temp_solid = malloc( solid->count *sizeof(int) );
+   int  temp_solid_len = 0;
 
    int init_reverse = 0;
    int unique_edge_count = 0;
+   
+   /* Try remove splitting faces first */
+   {
+      int split_total = 0;
+      for( int j=0; j<solid->count; j++ )
+      {
+         cxr_polygon *poly = &mesh->polys[ solid_buffer[solid->start+j] ];
+         int interior_count = 0;
+
+         for( int k=0; k<poly->loop_total; k++ )
+         {
+            cxr_loop *loop = &mesh->loops[ poly->loop_start+k ];
+
+            for( int l=0; l<solid->count; l++ )
+               if( loop->poly_right == solid_buffer[solid->start+l] )
+               {
+                  interior_count ++;
+                  goto next;
+               }
 
-   /* Gather list of unique edges */
+            next:;
+         }
+         
+         if( interior_count < poly->loop_total-1 )
+         {
+            split_total ++;
+            continue;
+         }
+         
+         temp_solid[ temp_solid_len ++ ] = solid_buffer[solid->start+j];
+      }
+
+      if( temp_solid_len < 3 || (split_total & 0x2) /* unkown reasons */ )
+      {
+      }
+      else
+      {
+         /* Overwrite original solid */
+         for( int j=0; j<temp_solid_len; j++ )
+            solid_buffer[ solid->start+j ] = temp_solid[ j ];
+
+         solid->count = temp_solid_len;
+      }
+
+      free( temp_solid );
+   }
 
    for( int j=0; j<solid->count; j++ )
    {
       cxr_polygon *poly = &mesh->polys[ solid_buffer[solid->start+j] ];
 
+      /* when discarding, if a face has only one loop that points outwards,
+       * we keep it */
+
+
       for( int k=0; k<poly->loop_total; k++ )
       {
          cxr_loop *loop = &mesh->loops[ poly->loop_start+k ];
@@ -1537,22 +1593,30 @@ static int cxr_build_implicit_geo( cxr_mesh *mesh, int new_polys, int start )
    return 1;
 }
 
-/* 
- * Convexer's main algorithm
- *
- * Return the best availible convex solid from mesh, and patch the existing mesh
- * to fill the gap where the new mesh left it.
- *
- * Returns NULL if shape is already convex or empty.
- * This function will not preserve edge data such as freestyle, sharp etc.
- */
-static cxr_mesh *cxr_pull_best_solid(
-      cxr_mesh *mesh, 
-      int preserve_more_edges,
-      enum cxr_soliderr *err )
+static int cxr_reflex_err( cxr_mesh *mesh )
 {
-   *err = k_soliderr_none;
+   int error = 0;
+   int *reflex_check = cxr_mesh_reflex_edges( mesh );
+
+   v3f *temp = cxr_ab_ptr(mesh->p_abverts, 0);
+
+   for( int i=0; i<mesh->abedges.count; i++ )
+   {
+      if( reflex_check[i] )
+      {
+         cxr_debug_line( temp[mesh->edges[i].i0],
+                         temp[mesh->edges[i].i1],
+                         colour_error );
+         error ++;
+      }
+   }
+
+   free( reflex_check );
+   return error;
+}
 
+static int cxr_non_manifold_err( cxr_mesh *mesh )
+{
    if( !cxr_mesh_link_loops(mesh) )
    {
 #ifdef CXR_DEBUG
@@ -1564,18 +1628,43 @@ static cxr_mesh *cxr_pull_best_solid(
       for( int i=0; i<mesh->abloops.count; i++ )
       {
          cxr_loop *lp = &mesh->loops[i];
+         cxr_edge *edge = &mesh->edges[lp->edge_index];
+         cxr_debug_line( verts[edge->i0], verts[edge->i1], colours_random[1] );
 
          if( lp->poly_left == -1 || lp->poly_right == -1 )
          {
-            cxr_edge *edge = &mesh->edges[lp->edge_index];
             cxr_debug_line( verts[edge->i0], verts[edge->i1], colour_error );
          }
       }
 #endif
+      return 1;
+   }
+
+   return 0;
+}
+
+/* 
+ * Convexer's main algorithm
+ *
+ * Return the best availible convex solid from mesh, and patch the existing mesh
+ * to fill the gap where the new mesh left it.
+ *
+ * Returns NULL if shape is already convex or empty.
+ * This function will not preserve edge data such as freestyle, sharp etc.
+ */
+static cxr_mesh *cxr_pull_best_solid(
+      cxr_mesh *mesh, 
+      int preserve_more_edges,
+      enum cxr_soliderr *err )
+{
+   *err = k_soliderr_none;
+
+   if( cxr_non_manifold_err( mesh ) )
+   {
       *err = k_soliderr_non_manifold;
       return NULL;
    }
-   
+
    int *edge_tagged = cxr_mesh_reflex_edges( mesh );
    int *vertex_tagged = cxr_mesh_reflex_vertices( mesh );
 
@@ -1689,7 +1778,7 @@ static cxr_mesh *cxr_pull_best_solid(
       
       struct temp_manifold manifold;
       cxr_link_manifold( mesh, solid, solid_buffer, &manifold);
-      
+
       if( manifold.status == k_manifold_err )
       {
          *err = k_soliderr_bad_manifold;
@@ -1917,7 +2006,17 @@ static cxr_mesh *cxr_pull_best_solid(
       free(solid_buffer);
       free(candidates);
       free(best_manifold.loops);
-   
+      
+      /*
+       * Do final checks on the mesh to make sure we diddn't introduce any
+       * errors
+       */
+      if( cxr_non_manifold_err( pullmesh ) || cxr_reflex_err( pullmesh ) )
+      {
+         *err = k_soliderr_bad_result;
+         return NULL;
+      }
+
       return pullmesh;
    }
 
@@ -1925,6 +2024,9 @@ static cxr_mesh *cxr_pull_best_solid(
    free(candidates);
    free(best_manifold.loops);
 
+   if( cxr_non_manifold_err( mesh ) || cxr_reflex_err( mesh ) )
+      *err = k_soliderr_bad_result;
+
    return NULL;
 }
 
@@ -1957,6 +2059,7 @@ static cxr_mesh *cxr_to_internal_format(
       lp->index = src->loops[i].index;
       lp->edge_index = src->loops[i].edge_index;
       v2_copy( src->loops[i].uv, lp->uv );
+      lp->alpha = src->loops[i].alpha;
    }
 
    abverts->count = src->vertex_count;
@@ -2050,7 +2153,14 @@ CXR_API void cxr_free_world( cxr_world *world )
 
    cxr_ab_free( &world->abverts );
    cxr_ab_free( &world->absolids );
-   free( world->materials );
+
+   if( world->materials )
+   {
+      for( int i=0; i<world->material_count; i++ )
+         free( world->materials[i].name );
+
+      free( world->materials );
+   }
    free( world );
 }
 
@@ -2078,6 +2188,8 @@ CXR_API cxr_tri_mesh *cxr_world_preview( cxr_world *world )
    out->colours = malloc( sizeof(v4f)*out->vertex_count );
    out->vertices = malloc( sizeof(v3f)*out->vertex_count );
    out->indices = malloc( sizeof(i32)*out->indices_count );
+   out->uvs = NULL;
+   out->normals = NULL;
 
    v3f *overts = out->vertices;
    v4f *colours = out->colours;
@@ -2159,11 +2271,23 @@ CXR_API void cxr_free_tri_mesh( cxr_tri_mesh *mesh )
    free( mesh->colours );
    free( mesh->indices );
    free( mesh->vertices );
+   free( mesh->normals );
+   free( mesh->uvs );
    free( mesh );
 }
 
 CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src, i32 *perrcode )
 {
+   /* Make sure data is in the mesh and isn't empty */
+   if( !src->edge_count || !src->loop_count || !src->poly_count )
+   {
+      cxr_log( "Error %d\n", k_soliderr_invalid_input );
+      if( perrcode )
+         *perrcode = k_soliderr_invalid_input;
+
+      return NULL;
+   }
+
    u32 error = 0x00;
    cxr_world *world = malloc( sizeof(*world) );
    
@@ -2176,6 +2300,13 @@ CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src, i32 *perrcode )
       size_t dsize = sizeof(cxr_material) * src->material_count;
       world->materials = malloc( dsize );
       memcpy( world->materials, src->materials, dsize );
+
+      for( int i=0; i<src->material_count; i++ )
+      {
+         world->materials[i].name = malloc(strlen(src->materials[i].name) +1);
+         strcpy( world->materials[i].name, src->materials[i].name );
+      }
+      world->material_count = src->material_count;
    }
    else world->materials = NULL;
 
@@ -2626,6 +2757,13 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
       }
    }
 
+   /* Collect alphas from loops. This discards hard blend information */
+   for( int i=0; i<mesh->abloops.count; i++ )
+   {
+      cxr_loop *loop = &mesh->loops[i];
+      vertinfo[loop->index].alpha = loop->alpha * 255.0;
+   }
+
    v3f  refv, refu, refn;
    v3_zero(refv); v3_zero(refu); v3_zero(refn);
    
@@ -2726,7 +2864,7 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
     * TODO(harry): Error checking is needed here for bad input data
     */
 
-   int dispedge[16];
+   int dispedge[17];
    v2f corner_uvs[4];
    int dispedge_count;
    int disp_count = 0;
@@ -2828,6 +2966,8 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
 
             if( !newvert )
             {
+               free( graph );
+               free( vertinfo );
                return 0;
             }
          }
@@ -2890,9 +3030,6 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
                   }
                }
 
-#ifdef CXR_DEBUG
-               cxr_log( "Broken displacement!\n" );
-#endif
                free( graph );
                free( vertinfo );
                return 0;
@@ -2944,6 +3081,8 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
             v3_muladds( face_center, refn, 1.5, pn );
             v3_muladds( face_center, refv, 1.5, pv );
             v3_muladds( face_center, refu, 1.5, pu );
+
+            v3_muladds( face_center, refn, 2.0, face_center );
          }
 
          /* Create world coordinates */
@@ -2993,6 +3132,7 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
          
          v3f normals[25];
          double distances[25];
+         double alphas[25];
          
          v3f lside0, lside1, lref, vdelta, vworld;
          double tx, ty;
@@ -3011,12 +3151,14 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
                tx = (double)k/(double)(5-1);
                v3_lerp( lside0, lside1, tx, lref );
                v3_muls( verts[grid[index]], ctx->scale, vworld );
-               v3_add( ctx->offset, vworld, ctx->offset );
+               v3_add( ctx->offset, vworld, vworld );
 
                v3_sub( vworld, lref, vdelta );
                v3_copy( vdelta, normals[index] );
                v3_normalize( normals[index] );
                distances[index] = v3_dot( vdelta, normals[index] );
+
+               alphas[index] = vertinfo[grid[index]].alpha;
             }
          }
 
@@ -3031,7 +3173,6 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
                                             world_corners[side[0]] );
             
             cxr_vdf_kv( output, "material", matptr->name );
-
             cxr_vdf_kaxis( output, "uaxis", 
                   texinfo_shared.uaxis, 
                   texinfo_shared.offset[0], 
@@ -3064,6 +3205,11 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
                   cxr_vdf_karrdouble( output, "row", k, &distances[k*5], 5 );
                cxr_vdf_edon( output );
                
+               cxr_vdf_node( output, "alphas" );
+               for( int k=0; k<5; k++ )
+                  cxr_vdf_karrdouble( output, "row", k, &alphas[k*5], 5 );
+               cxr_vdf_edon( output );
+               
                /*
                 * TODO: This might be needed for the compilers. Opens fine in 
                 * hammer
@@ -3082,11 +3228,6 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
                      "\"row%d\" \"0 0 1 0 0 1 0 0 1 0 0 1 0 0 1\"\n", k );
                cxr_vdf_edon( output );
                
-               cxr_vdf_node( output, "alphas" );
-               for( int k=0; k<5; k++ )
-                  cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0\"\n", k );
-               cxr_vdf_edon( output );
-               
                cxr_vdf_node( output, "triangle_tags" );
                for( int k=0; k<5-1; k++ )
                   cxr_vdf_printf( output, 
@@ -3108,7 +3249,8 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
          cxr_vdf_node( output, "editor");
          cxr_vdf_colour255( output, "color", 
                colours_random[cxr_range(ctx->brush_count,8)]);
-
+         
+         cxr_vdf_ki32( output, "visgroupid", ctx->visgroupid );
          cxr_vdf_ki32( output, "visgroupshown",1);
          cxr_vdf_ki32( output, "visgroupautoshown",1);
          cxr_vdf_edon( output );
@@ -3138,6 +3280,15 @@ CXR_API void cxr_begin_vmf( cxr_vmf_context *ctx, cxr_vdf *output )
    cxr_vdf_edon( output );
 
    cxr_vdf_node( output, "visgroups" );
+
+   for( int i=0; i<ctx->visgroup_count; i++ )
+   {
+      cxr_vdf_node( output, "visgroup" );
+      cxr_vdf_kv( output, "name", ctx->visgroups[i].name );
+      cxr_vdf_ki32( output, "visgroupid", i+1 );
+      cxr_vdf_edon( output );
+   }
+
    cxr_vdf_edon( output );
 
    cxr_vdf_node( output, "viewsettings" );
@@ -3183,7 +3334,10 @@ CXR_API void cxr_push_world_vmf( cxr_world *world, cxr_vmf_context *ctx,
 
       if( solid->displacement )
       {
-         cxr_write_disp( solid->pmesh, world, ctx, output );
+         if( !cxr_write_disp( solid->pmesh, world, ctx, output ) )
+         {
+            cxr_log( "Warning: Invalid displacement\n" );
+         }
          continue;
       }
       
@@ -3242,6 +3396,7 @@ CXR_API void cxr_push_world_vmf( cxr_world *world, cxr_vmf_context *ctx,
       cxr_vdf_colour255( output, "color", 
             colours_random[cxr_range(ctx->brush_count,8)]);
 
+      cxr_vdf_ki32( output, "visgroupid", ctx->visgroupid );
       cxr_vdf_ki32( output, "visgroupshown", 1 );
       cxr_vdf_ki32( output, "visgroupautoshown", 1 );
       cxr_vdf_edon( output );
@@ -3354,5 +3509,6 @@ CXR_API int cxr_lightpatch_bsp( const char *path )
 
    return 1;
 }
+
 #endif /* CXR_VALVE_MAP_FILE */
 #endif /* CXR_IMPLEMENTATION */