576 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			576 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This software is provided 'as-is', without any express or implied
							 | 
						||
| 
								 | 
							
								// warranty.  In no event will the authors be held liable for any damages
							 | 
						||
| 
								 | 
							
								// arising from the use of this software.
							 | 
						||
| 
								 | 
							
								// Permission is granted to anyone to use this software for any purpose,
							 | 
						||
| 
								 | 
							
								// including commercial applications, and to alter it and redistribute it
							 | 
						||
| 
								 | 
							
								// freely, subject to the following restrictions:
							 | 
						||
| 
								 | 
							
								// 1. The origin of this software must not be misrepresented; you must not
							 | 
						||
| 
								 | 
							
								//    claim that you wrote the original software. If you use this software
							 | 
						||
| 
								 | 
							
								//    in a product, an acknowledgment in the product documentation would be
							 | 
						||
| 
								 | 
							
								//    appreciated but is not required.
							 | 
						||
| 
								 | 
							
								// 2. Altered source versions must be plainly marked as such, and must not be
							 | 
						||
| 
								 | 
							
								//    misrepresented as being the original software.
							 | 
						||
| 
								 | 
							
								// 3. This notice may not be removed or altered from any source distribution.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <float.h>
							 | 
						||
| 
								 | 
							
								#define _USE_MATH_DEFINES
							 | 
						||
| 
								 | 
							
								#include <math.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stdarg.h>
							 | 
						||
| 
								 | 
							
								#include "Recast.h"
							 | 
						||
| 
								 | 
							
								#include "RecastAlloc.h"
							 | 
						||
| 
								 | 
							
								#include "RecastAssert.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								/// Allocates and constructs an object of the given type, returning a pointer.
							 | 
						||
| 
								 | 
							
								/// TODO: Support constructor args.
							 | 
						||
| 
								 | 
							
								/// @param[in]		hint	Hint to the allocator.
							 | 
						||
| 
								 | 
							
								template <typename T>
							 | 
						||
| 
								 | 
							
								T* rcNew(rcAllocHint hint) {
							 | 
						||
| 
								 | 
							
									T* ptr = (T*)rcAlloc(sizeof(T), hint);
							 | 
						||
| 
								 | 
							
									::new(rcNewTag(), (void*)ptr) T();
							 | 
						||
| 
								 | 
							
									return ptr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// Destroys and frees an object allocated with rcNew.
							 | 
						||
| 
								 | 
							
								/// @param[in]     ptr    The object pointer to delete.
							 | 
						||
| 
								 | 
							
								template <typename T>
							 | 
						||
| 
								 | 
							
								void rcDelete(T* ptr) {
							 | 
						||
| 
								 | 
							
									if (ptr) {
							 | 
						||
| 
								 | 
							
										ptr->~T();
							 | 
						||
| 
								 | 
							
										rcFree((void*)ptr);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								}  // namespace
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								float rcSqrt(float x)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return sqrtf(x);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// @class rcContext
							 | 
						||
| 
								 | 
							
								/// @par
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// This class does not provide logging or timer functionality on its 
							 | 
						||
| 
								 | 
							
								/// own.  Both must be provided by a concrete implementation 
							 | 
						||
| 
								 | 
							
								/// by overriding the protected member functions.  Also, this class does not 
							 | 
						||
| 
								 | 
							
								/// provide an interface for extracting log messages. (Only adding them.) 
							 | 
						||
| 
								 | 
							
								/// So concrete implementations must provide one.
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// If no logging or timers are required, just pass an instance of this 
							 | 
						||
| 
								 | 
							
								/// class through the Recast build process.
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// @par
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// Example:
							 | 
						||
| 
								 | 
							
								/// @code
							 | 
						||
| 
								 | 
							
								/// // Where ctx is an instance of rcContext and filepath is a char array.
							 | 
						||
| 
								 | 
							
								/// ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath);
							 | 
						||
| 
								 | 
							
								/// @endcode
							 | 
						||
| 
								 | 
							
								void rcContext::log(const rcLogCategory category, const char* format, ...)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (!m_logEnabled)
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
									static const int MSG_SIZE = 512;
							 | 
						||
| 
								 | 
							
									char msg[MSG_SIZE];
							 | 
						||
| 
								 | 
							
									va_list ap;
							 | 
						||
| 
								 | 
							
									va_start(ap, format);
							 | 
						||
| 
								 | 
							
									int len = vsnprintf(msg, MSG_SIZE, format, ap);
							 | 
						||
| 
								 | 
							
									if (len >= MSG_SIZE)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										len = MSG_SIZE-1;
							 | 
						||
| 
								 | 
							
										msg[MSG_SIZE-1] = '\0';
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									va_end(ap);
							 | 
						||
| 
								 | 
							
									doLog(category, msg, len);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcHeightfield* rcAllocHeightfield()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return rcNew<rcHeightfield>(RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								rcHeightfield::rcHeightfield()
							 | 
						||
| 
								 | 
							
									: width()
							 | 
						||
| 
								 | 
							
									, height()
							 | 
						||
| 
								 | 
							
									, bmin()
							 | 
						||
| 
								 | 
							
									, bmax()
							 | 
						||
| 
								 | 
							
									, cs()
							 | 
						||
| 
								 | 
							
									, ch()
							 | 
						||
| 
								 | 
							
									, spans()
							 | 
						||
| 
								 | 
							
									, pools()
							 | 
						||
| 
								 | 
							
									, freelist()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcHeightfield::~rcHeightfield()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									// Delete span array.
							 | 
						||
| 
								 | 
							
									rcFree(spans);
							 | 
						||
| 
								 | 
							
									// Delete span pools.
							 | 
						||
| 
								 | 
							
									while (pools)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										rcSpanPool* next = pools->next;
							 | 
						||
| 
								 | 
							
										rcFree(pools);
							 | 
						||
| 
								 | 
							
										pools = next;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void rcFreeHeightField(rcHeightfield* hf)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcDelete(hf);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcCompactHeightfield* rcAllocCompactHeightfield()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return rcNew<rcCompactHeightfield>(RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void rcFreeCompactHeightfield(rcCompactHeightfield* chf)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcDelete(chf);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcCompactHeightfield::rcCompactHeightfield()
							 | 
						||
| 
								 | 
							
									: width(),
							 | 
						||
| 
								 | 
							
									height(),
							 | 
						||
| 
								 | 
							
									spanCount(),
							 | 
						||
| 
								 | 
							
									walkableHeight(),
							 | 
						||
| 
								 | 
							
									walkableClimb(),
							 | 
						||
| 
								 | 
							
									borderSize(),
							 | 
						||
| 
								 | 
							
									maxDistance(),
							 | 
						||
| 
								 | 
							
									maxRegions(),
							 | 
						||
| 
								 | 
							
									bmin(),
							 | 
						||
| 
								 | 
							
									bmax(),
							 | 
						||
| 
								 | 
							
									cs(),
							 | 
						||
| 
								 | 
							
									ch(),
							 | 
						||
| 
								 | 
							
									cells(),
							 | 
						||
| 
								 | 
							
									spans(),
							 | 
						||
| 
								 | 
							
									dist(),
							 | 
						||
| 
								 | 
							
									areas()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								rcCompactHeightfield::~rcCompactHeightfield()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcFree(cells);
							 | 
						||
| 
								 | 
							
									rcFree(spans);
							 | 
						||
| 
								 | 
							
									rcFree(dist);
							 | 
						||
| 
								 | 
							
									rcFree(areas);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return rcNew<rcHeightfieldLayerSet>(RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcDelete(lset);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcHeightfieldLayerSet::rcHeightfieldLayerSet()
							 | 
						||
| 
								 | 
							
									: layers(),	nlayers() {}
							 | 
						||
| 
								 | 
							
								rcHeightfieldLayerSet::~rcHeightfieldLayerSet()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									for (int i = 0; i < nlayers; ++i)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										rcFree(layers[i].heights);
							 | 
						||
| 
								 | 
							
										rcFree(layers[i].areas);
							 | 
						||
| 
								 | 
							
										rcFree(layers[i].cons);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									rcFree(layers);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcContourSet* rcAllocContourSet()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return rcNew<rcContourSet>(RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								void rcFreeContourSet(rcContourSet* cset)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcDelete(cset);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcContourSet::rcContourSet()
							 | 
						||
| 
								 | 
							
									: conts(),
							 | 
						||
| 
								 | 
							
									nconts(),
							 | 
						||
| 
								 | 
							
									bmin(),
							 | 
						||
| 
								 | 
							
									bmax(),
							 | 
						||
| 
								 | 
							
									cs(),
							 | 
						||
| 
								 | 
							
									ch(),
							 | 
						||
| 
								 | 
							
									width(),
							 | 
						||
| 
								 | 
							
									height(),
							 | 
						||
| 
								 | 
							
									borderSize(),
							 | 
						||
| 
								 | 
							
									maxError() {}
							 | 
						||
| 
								 | 
							
								rcContourSet::~rcContourSet()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									for (int i = 0; i < nconts; ++i)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										rcFree(conts[i].verts);
							 | 
						||
| 
								 | 
							
										rcFree(conts[i].rverts);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									rcFree(conts);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcPolyMesh* rcAllocPolyMesh()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return rcNew<rcPolyMesh>(RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								void rcFreePolyMesh(rcPolyMesh* pmesh)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcDelete(pmesh);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcPolyMesh::rcPolyMesh()
							 | 
						||
| 
								 | 
							
									: verts(),
							 | 
						||
| 
								 | 
							
									polys(),
							 | 
						||
| 
								 | 
							
									regs(),
							 | 
						||
| 
								 | 
							
									flags(),
							 | 
						||
| 
								 | 
							
									areas(),
							 | 
						||
| 
								 | 
							
									nverts(),
							 | 
						||
| 
								 | 
							
									npolys(),
							 | 
						||
| 
								 | 
							
									maxpolys(),
							 | 
						||
| 
								 | 
							
									nvp(),
							 | 
						||
| 
								 | 
							
									bmin(),
							 | 
						||
| 
								 | 
							
									bmax(),
							 | 
						||
| 
								 | 
							
									cs(),
							 | 
						||
| 
								 | 
							
									ch(),
							 | 
						||
| 
								 | 
							
									borderSize(),
							 | 
						||
| 
								 | 
							
									maxEdgeError() {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcPolyMesh::~rcPolyMesh()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcFree(verts);
							 | 
						||
| 
								 | 
							
									rcFree(polys);
							 | 
						||
| 
								 | 
							
									rcFree(regs);
							 | 
						||
| 
								 | 
							
									rcFree(flags);
							 | 
						||
| 
								 | 
							
									rcFree(areas);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rcPolyMeshDetail* rcAllocPolyMeshDetail()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcPolyMeshDetail* dmesh = (rcPolyMeshDetail*)rcAlloc(sizeof(rcPolyMeshDetail), RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									memset(dmesh, 0, sizeof(rcPolyMeshDetail));
							 | 
						||
| 
								 | 
							
									return dmesh;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (!dmesh) return;
							 | 
						||
| 
								 | 
							
									rcFree(dmesh->meshes);
							 | 
						||
| 
								 | 
							
									rcFree(dmesh->verts);
							 | 
						||
| 
								 | 
							
									rcFree(dmesh->tris);
							 | 
						||
| 
								 | 
							
									rcFree(dmesh);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									// Calculate bounding box.
							 | 
						||
| 
								 | 
							
									rcVcopy(bmin, verts);
							 | 
						||
| 
								 | 
							
									rcVcopy(bmax, verts);
							 | 
						||
| 
								 | 
							
									for (int i = 1; i < nv; ++i)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										const float* v = &verts[i*3];
							 | 
						||
| 
								 | 
							
										rcVmin(bmin, v);
							 | 
						||
| 
								 | 
							
										rcVmax(bmax, v);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									*w = (int)((bmax[0] - bmin[0])/cs+0.5f);
							 | 
						||
| 
								 | 
							
									*h = (int)((bmax[2] - bmin[2])/cs+0.5f);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// @par
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// See the #rcConfig documentation for more information on the configuration parameters.
							 | 
						||
| 
								 | 
							
								/// 
							 | 
						||
| 
								 | 
							
								/// @see rcAllocHeightfield, rcHeightfield 
							 | 
						||
| 
								 | 
							
								bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
							 | 
						||
| 
								 | 
							
														 const float* bmin, const float* bmax,
							 | 
						||
| 
								 | 
							
														 float cs, float ch)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcIgnoreUnused(ctx);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									hf.width = width;
							 | 
						||
| 
								 | 
							
									hf.height = height;
							 | 
						||
| 
								 | 
							
									rcVcopy(hf.bmin, bmin);
							 | 
						||
| 
								 | 
							
									rcVcopy(hf.bmax, bmax);
							 | 
						||
| 
								 | 
							
									hf.cs = cs;
							 | 
						||
| 
								 | 
							
									hf.ch = ch;
							 | 
						||
| 
								 | 
							
									hf.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									if (!hf.spans)
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height);
							 | 
						||
| 
								 | 
							
									return true;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* norm)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									float e0[3], e1[3];
							 | 
						||
| 
								 | 
							
									rcVsub(e0, v1, v0);
							 | 
						||
| 
								 | 
							
									rcVsub(e1, v2, v0);
							 | 
						||
| 
								 | 
							
									rcVcross(norm, e0, e1);
							 | 
						||
| 
								 | 
							
									rcVnormalize(norm);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// @par
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// Only sets the area id's for the walkable triangles.  Does not alter the
							 | 
						||
| 
								 | 
							
								/// area id's for unwalkable triangles.
							 | 
						||
| 
								 | 
							
								/// 
							 | 
						||
| 
								 | 
							
								/// See the #rcConfig documentation for more information on the configuration parameters.
							 | 
						||
| 
								 | 
							
								/// 
							 | 
						||
| 
								 | 
							
								/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
							 | 
						||
| 
								 | 
							
								void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
							 | 
						||
| 
								 | 
							
															 const float* verts, int nv,
							 | 
						||
| 
								 | 
							
															 const int* tris, int nt,
							 | 
						||
| 
								 | 
							
															 unsigned char* areas)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcIgnoreUnused(ctx);
							 | 
						||
| 
								 | 
							
									rcIgnoreUnused(nv);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									float norm[3];
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									for (int i = 0; i < nt; ++i)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										const int* tri = &tris[i*3];
							 | 
						||
| 
								 | 
							
										calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
							 | 
						||
| 
								 | 
							
										// Check if the face is walkable.
							 | 
						||
| 
								 | 
							
										if (norm[1] > walkableThr)
							 | 
						||
| 
								 | 
							
											areas[i] = RC_WALKABLE_AREA;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// @par
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// Only sets the area id's for the unwalkable triangles.  Does not alter the
							 | 
						||
| 
								 | 
							
								/// area id's for walkable triangles.
							 | 
						||
| 
								 | 
							
								/// 
							 | 
						||
| 
								 | 
							
								/// See the #rcConfig documentation for more information on the configuration parameters.
							 | 
						||
| 
								 | 
							
								/// 
							 | 
						||
| 
								 | 
							
								/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
							 | 
						||
| 
								 | 
							
								void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
							 | 
						||
| 
								 | 
							
																const float* verts, int /*nv*/,
							 | 
						||
| 
								 | 
							
																const int* tris, int nt,
							 | 
						||
| 
								 | 
							
																unsigned char* areas)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcIgnoreUnused(ctx);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									float norm[3];
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									for (int i = 0; i < nt; ++i)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										const int* tri = &tris[i*3];
							 | 
						||
| 
								 | 
							
										calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
							 | 
						||
| 
								 | 
							
										// Check if the face is walkable.
							 | 
						||
| 
								 | 
							
										if (norm[1] <= walkableThr)
							 | 
						||
| 
								 | 
							
											areas[i] = RC_NULL_AREA;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcIgnoreUnused(ctx);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									const int w = hf.width;
							 | 
						||
| 
								 | 
							
									const int h = hf.height;
							 | 
						||
| 
								 | 
							
									int spanCount = 0;
							 | 
						||
| 
								 | 
							
									for (int y = 0; y < h; ++y)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										for (int x = 0; x < w; ++x)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												if (s->area != RC_NULL_AREA)
							 | 
						||
| 
								 | 
							
													spanCount++;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return spanCount;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/// @par
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// This is just the beginning of the process of fully building a compact heightfield.
							 | 
						||
| 
								 | 
							
								/// Various filters may be applied, then the distance field and regions built.
							 | 
						||
| 
								 | 
							
								/// E.g: #rcBuildDistanceField and #rcBuildRegions
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// See the #rcConfig documentation for more information on the configuration parameters.
							 | 
						||
| 
								 | 
							
								///
							 | 
						||
| 
								 | 
							
								/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
							 | 
						||
| 
								 | 
							
								bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
							 | 
						||
| 
								 | 
							
															   rcHeightfield& hf, rcCompactHeightfield& chf)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									rcAssert(ctx);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									rcScopedTimer timer(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									const int w = hf.width;
							 | 
						||
| 
								 | 
							
									const int h = hf.height;
							 | 
						||
| 
								 | 
							
									const int spanCount = rcGetHeightFieldSpanCount(ctx, hf);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Fill in header.
							 | 
						||
| 
								 | 
							
									chf.width = w;
							 | 
						||
| 
								 | 
							
									chf.height = h;
							 | 
						||
| 
								 | 
							
									chf.spanCount = spanCount;
							 | 
						||
| 
								 | 
							
									chf.walkableHeight = walkableHeight;
							 | 
						||
| 
								 | 
							
									chf.walkableClimb = walkableClimb;
							 | 
						||
| 
								 | 
							
									chf.maxRegions = 0;
							 | 
						||
| 
								 | 
							
									rcVcopy(chf.bmin, hf.bmin);
							 | 
						||
| 
								 | 
							
									rcVcopy(chf.bmax, hf.bmax);
							 | 
						||
| 
								 | 
							
									chf.bmax[1] += walkableHeight*hf.ch;
							 | 
						||
| 
								 | 
							
									chf.cs = hf.cs;
							 | 
						||
| 
								 | 
							
									chf.ch = hf.ch;
							 | 
						||
| 
								 | 
							
									chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									if (!chf.cells)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									memset(chf.cells, 0, sizeof(rcCompactCell)*w*h);
							 | 
						||
| 
								 | 
							
									chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									if (!chf.spans)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
							 | 
						||
| 
								 | 
							
									chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									if (!chf.areas)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									const int MAX_HEIGHT = 0xffff;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// Fill in cells and spans.
							 | 
						||
| 
								 | 
							
									int idx = 0;
							 | 
						||
| 
								 | 
							
									for (int y = 0; y < h; ++y)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										for (int x = 0; x < w; ++x)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											const rcSpan* s = hf.spans[x + y*w];
							 | 
						||
| 
								 | 
							
											// If there are no spans at this cell, just leave the data to index=0, count=0.
							 | 
						||
| 
								 | 
							
											if (!s) continue;
							 | 
						||
| 
								 | 
							
											rcCompactCell& c = chf.cells[x+y*w];
							 | 
						||
| 
								 | 
							
											c.index = idx;
							 | 
						||
| 
								 | 
							
											c.count = 0;
							 | 
						||
| 
								 | 
							
											while (s)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												if (s->area != RC_NULL_AREA)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													const int bot = (int)s->smax;
							 | 
						||
| 
								 | 
							
													const int top = s->next ? (int)s->next->smin : MAX_HEIGHT;
							 | 
						||
| 
								 | 
							
													chf.spans[idx].y = (unsigned short)rcClamp(bot, 0, 0xffff);
							 | 
						||
| 
								 | 
							
													chf.spans[idx].h = (unsigned char)rcClamp(top - bot, 0, 0xff);
							 | 
						||
| 
								 | 
							
													chf.areas[idx] = s->area;
							 | 
						||
| 
								 | 
							
													idx++;
							 | 
						||
| 
								 | 
							
													c.count++;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												s = s->next;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Find neighbour connections.
							 | 
						||
| 
								 | 
							
									const int MAX_LAYERS = RC_NOT_CONNECTED-1;
							 | 
						||
| 
								 | 
							
									int tooHighNeighbour = 0;
							 | 
						||
| 
								 | 
							
									for (int y = 0; y < h; ++y)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										for (int x = 0; x < w; ++x)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											const rcCompactCell& c = chf.cells[x+y*w];
							 | 
						||
| 
								 | 
							
											for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												rcCompactSpan& s = chf.spans[i];
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												for (int dir = 0; dir < 4; ++dir)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													rcSetCon(s, dir, RC_NOT_CONNECTED);
							 | 
						||
| 
								 | 
							
													const int nx = x + rcGetDirOffsetX(dir);
							 | 
						||
| 
								 | 
							
													const int ny = y + rcGetDirOffsetY(dir);
							 | 
						||
| 
								 | 
							
													// First check that the neighbour cell is in bounds.
							 | 
						||
| 
								 | 
							
													if (nx < 0 || ny < 0 || nx >= w || ny >= h)
							 | 
						||
| 
								 | 
							
														continue;
							 | 
						||
| 
								 | 
							
														
							 | 
						||
| 
								 | 
							
													// Iterate over all neighbour spans and check if any of the is
							 | 
						||
| 
								 | 
							
													// accessible from current cell.
							 | 
						||
| 
								 | 
							
													const rcCompactCell& nc = chf.cells[nx+ny*w];
							 | 
						||
| 
								 | 
							
													for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; ++k)
							 | 
						||
| 
								 | 
							
													{
							 | 
						||
| 
								 | 
							
														const rcCompactSpan& ns = chf.spans[k];
							 | 
						||
| 
								 | 
							
														const int bot = rcMax(s.y, ns.y);
							 | 
						||
| 
								 | 
							
														const int top = rcMin(s.y+s.h, ns.y+ns.h);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														// Check that the gap between the spans is walkable,
							 | 
						||
| 
								 | 
							
														// and that the climb height between the gaps is not too high.
							 | 
						||
| 
								 | 
							
														if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
							 | 
						||
| 
								 | 
							
														{
							 | 
						||
| 
								 | 
							
															// Mark direction as walkable.
							 | 
						||
| 
								 | 
							
															const int lidx = k - (int)nc.index;
							 | 
						||
| 
								 | 
							
															if (lidx < 0 || lidx > MAX_LAYERS)
							 | 
						||
| 
								 | 
							
															{
							 | 
						||
| 
								 | 
							
																tooHighNeighbour = rcMax(tooHighNeighbour, lidx);
							 | 
						||
| 
								 | 
							
																continue;
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
															rcSetCon(s, dir, lidx);
							 | 
						||
| 
								 | 
							
															break;
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									if (tooHighNeighbour > MAX_LAYERS)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
							 | 
						||
| 
								 | 
							
												 tooHighNeighbour, MAX_LAYERS);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									return true;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								static int getHeightfieldMemoryUsage(const rcHeightfield& hf)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int size = 0;
							 | 
						||
| 
								 | 
							
									size += sizeof(hf);
							 | 
						||
| 
								 | 
							
									size += hf.width * hf.height * sizeof(rcSpan*);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									rcSpanPool* pool = hf.pools;
							 | 
						||
| 
								 | 
							
									while (pool)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										size += (sizeof(rcSpanPool) - sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL;
							 | 
						||
| 
								 | 
							
										pool = pool->next;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return size;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int size = 0;
							 | 
						||
| 
								 | 
							
									size += sizeof(rcCompactHeightfield);
							 | 
						||
| 
								 | 
							
									size += sizeof(rcCompactSpan) * chf.spanCount;
							 | 
						||
| 
								 | 
							
									size += sizeof(rcCompactCell) * chf.width * chf.height;
							 | 
						||
| 
								 | 
							
									return size;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								*/
							 |