diff --git a/spine-c-new/codegen/src/file-writer.ts b/spine-c-new/codegen/src/file-writer.ts deleted file mode 100644 index a3940f53b..000000000 --- a/spine-c-new/codegen/src/file-writer.ts +++ /dev/null @@ -1,229 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { Type, toSnakeCase } from './types'; - -const LICENSE_HEADER = `/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated April 5, 2025. Replaces all prior versions. - * - * Copyright (c) 2013-2025, Esoteric Software LLC - * - * Integration of the Spine Runtimes into software or otherwise creating - * derivative works of the Spine Runtimes is permitted under the terms and - * conditions of Section 2 of the Spine Editor License Agreement: - * http://esotericsoftware.com/spine-editor-license - * - * Otherwise, it is permitted to integrate the Spine Runtimes into software - * or otherwise create derivative works of the Spine Runtimes (collectively, - * "Products"), provided that each user of the Products must obtain their own - * Spine Editor license and redistribution of the Products in any form must - * include this license and copyright notice. - * - * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, - * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/`; - -export class FileWriter { - constructor(private outputDir: string) { - // Clean and recreate output directory - this.cleanOutputDirectory(); - } - - private cleanOutputDirectory(): void { - // Remove existing generated directory if it exists - if (fs.existsSync(this.outputDir)) { - console.log(`Cleaning ${this.outputDir}...`); - fs.rmSync(this.outputDir, { recursive: true, force: true }); - } - - // Recreate the directory - fs.mkdirSync(this.outputDir, { recursive: true }); - } - - async writeType(typeName: string, headerContent: string[], sourceContent: string[]): Promise { - const fileName = toSnakeCase(typeName); - - // Write header file - const headerPath = path.join(this.outputDir, `${fileName}.h`); - const headerGuard = `SPINE_C_${typeName.toUpperCase()}_H`; - - // Check if the header content uses any custom types from extensions.h - const headerString = headerContent.join('\n'); - const needsExtensions = headerString.includes('spine_void') || - headerString.includes('spine_dispose_renderer_object') || - headerString.includes('spine_texture_loader'); - - const headerLines = [ - LICENSE_HEADER, - '', - `#ifndef ${headerGuard}`, - `#define ${headerGuard}`, - '', - '#ifdef __cplusplus', - 'extern "C" {', - '#endif', - '', - '#include "types.h"', - ]; - - // Include extensions.h if needed - if (needsExtensions) { - headerLines.push('#include "../extensions.h"'); - } - - headerLines.push( - '', - ...headerContent, - '', - '#ifdef __cplusplus', - '}', - '#endif', - '', - `#endif // ${headerGuard}` - ); - - fs.writeFileSync(headerPath, headerLines.join('\n')); - - // Write source file (as .cpp since it contains C++ code) - const sourcePath = path.join(this.outputDir, `${fileName}.cpp`); - const sourceLines = [ - LICENSE_HEADER, - '', - ...sourceContent - ]; - - fs.writeFileSync(sourcePath, sourceLines.join('\n')); - } - - async writeEnum(enumName: string, content: string[]): Promise { - const fileName = toSnakeCase(enumName); - const headerPath = path.join(this.outputDir, `${fileName}.h`); - const headerGuard = `SPINE_C_${enumName.toUpperCase()}_H`; - - const headerLines = [ - LICENSE_HEADER, - '', - `#ifndef ${headerGuard}`, - `#define ${headerGuard}`, - '', - '#include "../base.h"', - '', - '#ifdef __cplusplus', - 'extern "C" {', - '#endif', - '', - ...content, - '', - '#ifdef __cplusplus', - '}', - '#endif', - '', - `#endif // ${headerGuard}` - ]; - - fs.writeFileSync(headerPath, headerLines.join('\n')); - } - - async writeMainHeader(classes: Type[], enums: Type[]): Promise { - const mainHeaderPath = path.join(this.outputDir, '..', '..', 'include', 'spine-c.h'); - - // Ensure include directory exists - const includeDir = path.dirname(mainHeaderPath); - if (!fs.existsSync(includeDir)) { - fs.mkdirSync(includeDir, { recursive: true }); - } - - const lines = [ - LICENSE_HEADER, - '', - '#ifndef SPINE_C_H', - '#define SPINE_C_H', - '', - '// Base definitions', - '#include "../src/base.h"', - '', - '// All type declarations and enum includes', - '#include "../src/generated/types.h"', - '', - '// Extension functions', - '#include "../src/extensions.h"', - '', - '// Generated class types' - ]; - - // Add class includes (they contain the actual function declarations) - for (const classType of classes) { - lines.push(`#include "../src/generated/${toSnakeCase(classType.name)}.h"`); - } - - lines.push(''); - lines.push('#endif // SPINE_C_H'); - - fs.writeFileSync(mainHeaderPath, lines.join('\n')); - } - - async writeArrays(header: string[], source: string[]): Promise { - const headerPath = path.join(this.outputDir, 'arrays.h'); - const sourcePath = path.join(this.outputDir, 'arrays.cpp'); - - // Add license header to both files - const headerLines = [LICENSE_HEADER, '', ...header]; - const sourceLines = [LICENSE_HEADER, '', ...source]; - - fs.writeFileSync(headerPath, headerLines.join('\n')); - fs.writeFileSync(sourcePath, sourceLines.join('\n')); - } - - async writeTypesHeader(classes: Type[], enums: Type[]): Promise { - const headerPath = path.join(this.outputDir, 'types.h'); - const lines: string[] = [ - LICENSE_HEADER, - '', - '#ifndef SPINE_C_TYPES_H', - '#define SPINE_C_TYPES_H', - '', - '#ifdef __cplusplus', - 'extern "C" {', - '#endif', - '', - '#include "../base.h"', - '', - '// Forward declarations for all non-enum types' - ]; - - // Forward declare all class types - for (const classType of classes) { - const cTypeName = `spine_${toSnakeCase(classType.name)}`; - lines.push(`SPINE_OPAQUE_TYPE(${cTypeName})`); - } - - lines.push(''); - lines.push('// Include all enum types (cannot be forward declared)'); - - // Include all enum headers - for (const enumType of enums) { - lines.push(`#include "${toSnakeCase(enumType.name)}.h"`); - } - - lines.push(''); - lines.push('// Array specializations'); - lines.push('#include "arrays.h"'); - - lines.push(''); - lines.push('#ifdef __cplusplus'); - lines.push('}'); - lines.push('#endif'); - lines.push(''); - lines.push('#endif // SPINE_C_TYPES_H'); - - fs.writeFileSync(headerPath, lines.join('\n')); - } -} \ No newline at end of file diff --git a/spine-c-new/codegen/src/generators/array-generator.ts b/spine-c-new/codegen/src/generators/array-generator.ts deleted file mode 100644 index 8c4b43bd6..000000000 --- a/spine-c-new/codegen/src/generators/array-generator.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { ArraySpecialization, ClassOrStruct, Method, toSnakeCase, Type } from '../types'; - -export class ArrayGenerator { - private arrayType: ClassOrStruct | undefined; - - constructor(private typesJson: any) { - // Find the Array type definition - for (const header of Object.keys(typesJson)) { - const arrayType = typesJson[header].find((t: Type) => t.kind === 'class' && t.name === 'Array'); - if (arrayType) { - this.arrayType = arrayType; - break; - } - } - } - - /** - * Generates arrays.h and arrays.cpp content - */ - generate(specializations: ArraySpecialization[]): { header: string[], source: string[] } { - const header: string[] = []; - const source: string[] = []; - - if (!this.arrayType) { - console.error('ERROR: Array type not found in spine-cpp types'); - return { header, source }; - } - - // Header file - header.push('#ifndef SPINE_C_ARRAYS_H'); - header.push('#define SPINE_C_ARRAYS_H'); - header.push(''); - header.push('#include "../base.h"'); - header.push('#include "types.h"'); - header.push(''); - header.push('#ifdef __cplusplus'); - header.push('extern "C" {'); - header.push('#endif'); - header.push(''); - - // Source file - source.push('#include "arrays.h"'); - source.push('#include '); - source.push('#include '); - source.push(''); - source.push('using namespace spine;'); - source.push(''); - - // Generate for each specialization - for (const spec of specializations) { - console.log(`Generating array specialization: ${spec.cTypeName}`); - this.generateSpecialization(spec, header, source); - } - - // Close header - header.push('#ifdef __cplusplus'); - header.push('}'); - header.push('#endif'); - header.push(''); - header.push('#endif // SPINE_C_ARRAYS_H'); - - return { header, source }; - } - - private generateSpecialization(spec: ArraySpecialization, header: string[], source: string[]) { - // Opaque type declaration - header.push(`// ${spec.cppType}`); - header.push(`SPINE_OPAQUE_TYPE(${spec.cTypeName})`); - header.push(''); - - // Get Array methods to wrap - const methods = this.arrayType!.members?.filter(m => - m.kind === 'method' - ).filter(m => !m.isStatic && !m.name.includes('operator')) || []; - - // Generate create method (constructor) - header.push(`SPINE_C_EXPORT ${spec.cTypeName} ${spec.cTypeName}_create();`); - source.push(`${spec.cTypeName} ${spec.cTypeName}_create() {`); - source.push(` return (${spec.cTypeName}) new (__FILE__, __LINE__) ${spec.cppType}();`); - source.push('}'); - source.push(''); - - // Generate dispose - header.push(`SPINE_C_EXPORT void ${spec.cTypeName}_dispose(${spec.cTypeName} array);`); - source.push(`void ${spec.cTypeName}_dispose(${spec.cTypeName} array) {`); - source.push(` if (!array) return;`); - source.push(` delete (${spec.cppType}*) array;`); - source.push('}'); - source.push(''); - - // Generate hardcoded get/set methods - header.push(`SPINE_C_EXPORT ${spec.cElementType} ${spec.cTypeName}_get(${spec.cTypeName} array, int index);`); - source.push(`${spec.cElementType} ${spec.cTypeName}_get(${spec.cTypeName} array, int index) {`); - source.push(` if (!array) return ${this.getDefaultValue(spec)};`); - source.push(` ${spec.cppType} *_array = (${spec.cppType}*) array;`); - source.push(` return ${this.convertFromCpp(spec, '(*_array)[index]')};`); - source.push('}'); - source.push(''); - - header.push(`SPINE_C_EXPORT void ${spec.cTypeName}_set(${spec.cTypeName} array, int index, ${spec.cElementType} value);`); - source.push(`void ${spec.cTypeName}_set(${spec.cTypeName} array, int index, ${spec.cElementType} value) {`); - source.push(` if (!array) return;`); - source.push(` ${spec.cppType} *_array = (${spec.cppType}*) array;`); - source.push(` (*_array)[index] = ${this.convertToCpp(spec, 'value')};`); - source.push('}'); - source.push(''); - - // Generate wrapper for each Array method - for (const method of methods) { - this.generateMethodWrapper(spec, method, header, source); - } - - header.push(''); - } - - private generateMethodWrapper(spec: ArraySpecialization, method: Method, header: string[], source: string[]) { - // Skip constructors and destructors - if (method.name === 'Array' || method.name === '~Array') return; - - // Build C function name - const cFuncName = `${spec.cTypeName}_${toSnakeCase(method.name)}`; - - // Convert return type - let returnType = 'void'; - let hasReturn = false; - if (method.returnType && method.returnType !== 'void') { - hasReturn = true; - if (method.returnType === 'T &' || method.returnType === `${spec.elementType} &`) { - // Return by reference becomes return by value in C - returnType = spec.cElementType; - } else if (method.returnType === 'T *' || method.returnType === `${spec.elementType} *`) { - returnType = spec.cElementType; - } else if (method.returnType === 'size_t') { - returnType = 'size_t'; - } else if (method.returnType === 'int') { - returnType = 'int'; - } else if (method.returnType === 'bool') { - returnType = 'bool'; - } else if (method.returnType === `${spec.cppType} *`) { - returnType = spec.cTypeName; - } else { - // Unknown return type - skip this method - console.log(` Skipping Array method ${method.name} - unknown return type: ${method.returnType}`); - return; - } - } - - // Build parameter list - const cParams: string[] = [`${spec.cTypeName} array`]; - const cppArgs: string[] = []; - - if (method.parameters) { - for (const param of method.parameters) { - if (param.type === 'T' || param.type === spec.elementType || - param.type === 'const T &' || param.type === `const ${spec.elementType} &`) { - cParams.push(`${spec.cElementType} ${param.name}`); - cppArgs.push(this.convertToCpp(spec, param.name)); - } else if (param.type === 'size_t') { - cParams.push(`size_t ${param.name}`); - cppArgs.push(param.name); - } else if (param.type === 'int') { - cParams.push(`int ${param.name}`); - cppArgs.push(param.name); - } else { - // Unknown parameter type - skip this method - console.log(` Skipping Array method ${method.name} - unknown param type: ${param.type}`); - return; - } - } - } - - // Generate declaration - header.push(`SPINE_C_EXPORT ${returnType} ${cFuncName}(${cParams.join(', ')});`); - - // Generate implementation - source.push(`${returnType} ${cFuncName}(${cParams.join(', ')}) {`); - source.push(` if (!array) return${hasReturn ? ' ' + this.getDefaultReturn(returnType, spec) : ''};`); - source.push(` ${spec.cppType} *_array = (${spec.cppType}*) array;`); - - const call = `_array->${method.name}(${cppArgs.join(', ')})`; - if (hasReturn) { - if (returnType === spec.cElementType) { - source.push(` return ${this.convertFromCpp(spec, call)};`); - } else { - source.push(` return ${call};`); - } - } else { - source.push(` ${call};`); - } - - source.push('}'); - source.push(''); - } - - private getDefaultValue(spec: ArraySpecialization): string { - if (spec.isPointer) return 'nullptr'; - if (spec.isPrimitive) { - if (spec.cElementType === 'bool') return 'false'; - return '0'; - } - if (spec.isEnum) return '0'; - return '0'; - } - - private getDefaultReturn(returnType: string, spec: ArraySpecialization): string { - if (returnType === 'bool') return 'false'; - if (returnType === 'size_t' || returnType === 'int') return '0'; - if (returnType === spec.cElementType) return this.getDefaultValue(spec); - if (returnType === spec.cTypeName) return 'nullptr'; - return '0'; - } - - private convertFromCpp(spec: ArraySpecialization, expr: string): string { - if (spec.isPointer) { - return `(${spec.cElementType}) ${expr}`; - } - if (spec.isEnum && spec.elementType !== 'PropertyId') { - return `(${spec.cElementType}) ${expr}`; - } - return expr; - } - - private convertToCpp(spec: ArraySpecialization, expr: string): string { - if (spec.isPointer) { - return `(${spec.elementType}) ${expr}`; - } - if (spec.isEnum && spec.elementType !== 'PropertyId') { - return `(${spec.elementType}) ${expr}`; - } - return expr; - } -} \ No newline at end of file diff --git a/spine-c-new/codegen/src/generators/constructor-generator.ts b/spine-c-new/codegen/src/generators/constructor-generator.ts deleted file mode 100644 index 9dc4bcbc2..000000000 --- a/spine-c-new/codegen/src/generators/constructor-generator.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Type, Member, toSnakeCase, toCFunctionName, toCTypeName, Constructor, ClassOrStruct } from '../types'; - -export interface GeneratorResult { - declarations: string[]; - implementations: string[]; -} - -export class ConstructorGenerator { - constructor(private validTypes: Set) {} - - generate(type: ClassOrStruct): GeneratorResult { - const declarations: string[] = []; - const implementations: string[] = []; - - if (!type.members) return { declarations, implementations }; - - const constructors = type.members.filter(m => m.kind === 'constructor'); - const cTypeName = `spine_${toSnakeCase(type.name)}`; - - // Skip constructor generation for abstract types - if (!type.isAbstract) { - // Generate create functions for each constructor - let constructorIndex = 0; - for (const constructor of constructors) { - const funcName = this.getCreateFunctionName(type.name, constructor, constructorIndex); - const params = this.generateParameters(constructor); - - // Declaration - declarations.push(`SPINE_C_EXPORT ${cTypeName} ${funcName}(${params.declaration});`); - - // Implementation - implementations.push(`${cTypeName} ${funcName}(${params.declaration}) {`); - implementations.push(` ${type.name} *obj = new (__FILE__, __LINE__) ${type.name}(${params.call});`); - implementations.push(` return (${cTypeName}) obj;`); - implementations.push(`}`); - implementations.push(''); - - constructorIndex++; - } - } - - // Always generate dispose function - declarations.push(`SPINE_C_EXPORT void ${cTypeName}_dispose(${cTypeName} obj);`); - - implementations.push(`void ${cTypeName}_dispose(${cTypeName} obj) {`); - implementations.push(` if (!obj) return;`); - implementations.push(` delete (${type.name} *) obj;`); - implementations.push(`}`); - implementations.push(''); - - return { declarations, implementations }; - } - - private getCreateFunctionName(typeName: string, constructor: Constructor, index: number): string { - const baseName = `spine_${toSnakeCase(typeName)}_create`; - - if (!constructor.parameters || constructor.parameters.length === 0) { - return baseName; - } - - if (index === 0) { - return baseName; - } - - // Generate name based on parameter types - const paramNames = constructor.parameters - .map(p => this.getParamTypeSuffix(p.type)) - .join('_'); - - return `${baseName}_with_${paramNames}`; - } - - private getParamTypeSuffix(type: string): string { - if (type.includes('float')) return 'float'; - if (type.includes('int')) return 'int'; - if (type.includes('bool')) return 'bool'; - if (type.includes('String') || type.includes('char')) return 'string'; - - // Extract class name from pointers/references - const match = type.match(/(?:const\s+)?(\w+)(?:\s*[*&])?/); - if (match) { - return toSnakeCase(match[1]); - } - - return 'param'; - } - - private generateParameters(constructor: Constructor): { declaration: string; call: string } { - if (!constructor.parameters || constructor.parameters.length === 0) { - return { declaration: 'void', call: '' }; - } - - const declParts: string[] = []; - const callParts: string[] = []; - - for (const param of constructor.parameters) { - const cType = toCTypeName(param.type, this.validTypes); - declParts.push(`${cType} ${param.name}`); - - // Convert C type back to C++ for the call - let callExpr = param.name; - if (param.type === 'const String &' || param.type === 'String') { - callExpr = `String(${param.name})`; - } else if (param.type.includes('*')) { - callExpr = `(${param.type}) ${param.name}`; - } else if (param.type.includes('&')) { - // Handle reference types - need to dereference the pointer - const baseType = param.type.replace(/^(?:const\s+)?(.+?)\s*&$/, '$1').trim(); - callExpr = `*(${baseType}*) ${param.name}`; - } - - callParts.push(callExpr); - } - - return { - declaration: declParts.join(', '), - call: callParts.join(', ') - }; - } -} \ No newline at end of file diff --git a/spine-c-new/codegen/src/generators/enum-generator.ts b/spine-c-new/codegen/src/generators/enum-generator.ts deleted file mode 100644 index a8eaa407b..000000000 --- a/spine-c-new/codegen/src/generators/enum-generator.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Enum, toSnakeCase } from '../types'; - -export class EnumGenerator { - generate(enumType: Enum): string[] { - const lines: string[] = []; - const enumName = `spine_${toSnakeCase(enumType.name)}`; - - lines.push(`typedef enum ${enumName} {`); - - if (enumType.values) { - for (let i = 0; i < enumType.values.length; i++) { - const value = enumType.values[i]; - // Remove redundant enum name prefix from value name if present - let valueName = value.name; - if (valueName.toLowerCase().startsWith(enumType.name.toLowerCase())) { - valueName = valueName.substring(enumType.name.length); - // Remove leading underscore if present after removing prefix - if (valueName.startsWith('_')) { - valueName = valueName.substring(1); - } - } - const cName = `SPINE_${toSnakeCase(enumType.name).toUpperCase()}_${toSnakeCase(valueName).toUpperCase()}`; - - if (value.value !== undefined) { - lines.push(` ${cName} = ${value.value}${i < enumType.values.length - 1 ? ',' : ''}`); - } else { - lines.push(` ${cName}${i < enumType.values.length - 1 ? ',' : ''}`); - } - } - } - - lines.push(`} ${enumName};`); - - return lines; - } -} \ No newline at end of file diff --git a/spine-c-new/codegen/src/generators/method-generator.ts b/spine-c-new/codegen/src/generators/method-generator.ts deleted file mode 100644 index 72065c4b9..000000000 --- a/spine-c-new/codegen/src/generators/method-generator.ts +++ /dev/null @@ -1,378 +0,0 @@ -import { Type, Member, toSnakeCase, toCFunctionName, toCTypeName, Exclusion, Method, ClassOrStruct } from '../types'; -import { isMethodExcluded } from '../exclusions'; -import { GeneratorResult } from './constructor-generator'; - -export class MethodGenerator { - constructor(private exclusions: Exclusion[], private validTypes: Set) { } - - generate(type: ClassOrStruct): GeneratorResult { - const declarations: string[] = []; - const implementations: string[] = []; - - if (!type.members) return { declarations, implementations }; - - const methods = type.members.filter(m => - m.kind === 'method' - ).filter(m => !isMethodExcluded(type.name, m.name, this.exclusions, m)) - .filter(m => !m.isStatic); - - // Check for const/non-const method pairs - const methodGroups = new Map(); - for (const method of methods) { - const key = method.name + '(' + (method.parameters?.map(p => p.type).join(',') || '') + ')'; - if (!methodGroups.has(key)) { - methodGroups.set(key, []); - } - methodGroups.get(key)!.push(method); - } - - // Collect all errors before failing - const errors: string[] = []; - - // Report errors for duplicate methods with different signatures - for (const [signature, group] of methodGroups) { - if (group.length > 1) { - // Check if we have different return types (const vs non-const overloading) - const returnTypes = new Set(group.map(m => m.returnType)); - if (returnTypes.size > 1) { - let error = `\nERROR: Type '${type.name}' has multiple versions of method '${group[0].name}' with different return types:\n`; - error += `This is likely a const/non-const overload pattern in C++ which cannot be represented in C.\n\n`; - - for (const method of group) { - const source = method.fromSupertype ? ` (inherited from ${method.fromSupertype})` : ''; - error += ` - ${method.returnType || 'void'} ${method.name}()${source}\n`; - } - error += `\nC++ pattern detected:\n`; - error += ` T& ${group[0].name}() { return member; } // for non-const objects\n`; - error += ` const T& ${group[0].name}() const { return member; } // for const objects\n`; - error += `\nThis pattern provides const-correctness in C++ but cannot be represented in C.\n`; - error += `Consider:\n`; - error += ` 1. Only exposing the const version in the C API\n`; - error += ` 2. Renaming one of the methods in C++\n`; - error += ` 3. Adding the method to exclusions.txt\n`; - - errors.push(error); - } - } - } - - // If we have errors, throw them all at once - if (errors.length > 0) { - console.error("=".repeat(80)); - console.error("CONST/NON-CONST METHOD CONFLICTS FOUND"); - console.error("=".repeat(80)); - for (const error of errors) { - console.error(error); - } - console.error("=".repeat(80)); - console.error(`Total conflicts found: ${errors.length}`); - console.error("=".repeat(80)); - throw new Error(`Cannot generate C API due to ${errors.length} const/non-const overloaded method conflicts.`); - } - - // For now, continue with the unique methods - const uniqueMethods = methods; - - const cTypeName = `spine_${toSnakeCase(type.name)}`; - - // Track method names to detect overloads - const methodCounts = new Map(); - for (const method of uniqueMethods) { - const count = methodCounts.get(method.name) || 0; - methodCounts.set(method.name, count + 1); - } - - // Track how many times we've seen each method name - const methodSeenCounts = new Map(); - - for (const method of uniqueMethods) { - try { - // Handle getters - if (method.name.startsWith('get') && (!method.parameters || method.parameters.length === 0)) { - const propName = method.name.substring(3); - - // Check if return type is Array - if (method.returnType && method.returnType.includes('Array<')) { - // For Array types, only generate collection accessors - this.generateCollectionAccessors(type, method, propName, declarations, implementations); - } else if (method.name === 'getRTTI') { - // Special handling for getRTTI - make it static - const funcName = toCFunctionName(type.name, 'get_rtti'); - const returnType = 'spine_rtti'; - - declarations.push(`SPINE_C_EXPORT ${returnType} ${funcName}();`); - - implementations.push(`${returnType} ${funcName}() {`); - implementations.push(` return (spine_rtti) &${type.name}::rtti;`); - implementations.push(`}`); - implementations.push(''); - } else { - // For non-Array types, generate regular getter - const funcName = toCFunctionName(type.name, method.name); - const returnType = toCTypeName(method.returnType || 'void', this.validTypes); - - declarations.push(`SPINE_C_EXPORT ${returnType} ${funcName}(${cTypeName} obj);`); - - implementations.push(`${returnType} ${funcName}(${cTypeName} obj) {`); - implementations.push(` if (!obj) return ${this.getDefaultReturn(returnType)};`); - implementations.push(` ${type.name} *_obj = (${type.name} *) obj;`); - - const callExpr = this.generateMethodCall('_obj', method); - implementations.push(` return ${callExpr};`); - implementations.push(`}`); - implementations.push(''); - } - } - // Handle setters - else if (method.name.startsWith('set') && method.parameters && method.parameters.length === 1) { - const funcName = toCFunctionName(type.name, method.name); - const paramType = toCTypeName(method.parameters[0].type, this.validTypes); - - declarations.push(`SPINE_C_EXPORT void ${funcName}(${cTypeName} obj, ${paramType} value);`); - - implementations.push(`void ${funcName}(${cTypeName} obj, ${paramType} value) {`); - implementations.push(` if (!obj) return;`); - implementations.push(` ${type.name} *_obj = (${type.name} *) obj;`); - - const callExpr = this.generateSetterCall('_obj', method, 'value'); - implementations.push(` ${callExpr};`); - implementations.push(`}`); - implementations.push(''); - } - // Handle other methods - else { - // Check if this is an overloaded method - const isOverloaded = (methodCounts.get(method.name) || 0) > 1; - const seenCount = methodSeenCounts.get(method.name) || 0; - methodSeenCounts.set(method.name, seenCount + 1); - - // Generate function name with suffix for overloads - let funcName = toCFunctionName(type.name, method.name); - - // Check for naming conflicts with type names - if (method.name === 'pose' && type.name === 'Bone') { - // Rename bone_pose() method to avoid conflict with spine_bone_pose type - funcName = toCFunctionName(type.name, 'update_pose'); - } - - if (isOverloaded && seenCount > 0) { - // Add parameter count suffix for overloaded methods - const paramCount = method.parameters ? method.parameters.length : 0; - funcName = `${funcName}_${paramCount}`; - } - - const returnType = toCTypeName(method.returnType || 'void', this.validTypes); - const params = this.generateMethodParameters(cTypeName, method); - - declarations.push(`SPINE_C_EXPORT ${returnType} ${funcName}(${params.declaration});`); - - implementations.push(`${returnType} ${funcName}(${params.declaration}) {`); - implementations.push(` if (!obj) return ${this.getDefaultReturn(returnType)};`); - implementations.push(` ${type.name} *_obj = (${type.name} *) obj;`); - - const callExpr = this.generateMethodCall('_obj', method, params.call); - if (returnType === 'void') { - implementations.push(` ${callExpr};`); - } else { - implementations.push(` return ${callExpr};`); - } - implementations.push(`}`); - implementations.push(''); - } - } catch (error) { - console.error(`Error generating method for type ${type.name}::${method.name}:`); - console.error(error); - throw error; - } - } - - return { declarations, implementations }; - - } - - private generateCollectionAccessors(type: Type, method: Method, propName: string, - declarations: string[], implementations: string[]) { - const cTypeName = `spine_${toSnakeCase(type.name)}`; - const propSnake = toSnakeCase(propName); - const arrayMatch = method.returnType!.match(/Array<(.+?)>/); - if (!arrayMatch) return; - - const elementType = arrayMatch[1].trim().replace(/\s*\*$/, ''); - let cElementType: string; - if (elementType === 'int') { - cElementType = 'int'; - } else if (elementType === 'float') { - cElementType = 'float'; - } else if (elementType === 'uint8_t') { - cElementType = 'uint8_t'; - } else if (elementType === 'String') { - cElementType = 'const char *'; - } else if (elementType === 'PropertyId') { - cElementType = 'int64_t'; // PropertyId is just an int - } else { - cElementType = `spine_${toSnakeCase(elementType)}`; - } - - // Get count function - const getCountFunc = `spine_${toSnakeCase(type.name)}_get_num_${propSnake}`; - declarations.push(`SPINE_C_EXPORT int32_t ${getCountFunc}(${cTypeName} obj);`); - - implementations.push(`int32_t ${getCountFunc}(${cTypeName} obj) {`); - implementations.push(` if (!obj) return 0;`); - implementations.push(` ${type.name} *_obj = (${type.name} *) obj;`); - implementations.push(` return (int32_t) _obj->get${propName}().size();`); - implementations.push(`}`); - implementations.push(''); - - // Get array function - const getArrayFunc = `spine_${toSnakeCase(type.name)}_get_${propSnake}`; - declarations.push(`SPINE_C_EXPORT ${cElementType} *${getArrayFunc}(${cTypeName} obj);`); - - implementations.push(`${cElementType} *${getArrayFunc}(${cTypeName} obj) {`); - implementations.push(` if (!obj) return nullptr;`); - implementations.push(` ${type.name} *_obj = (${type.name} *) obj;`); - - // Handle const vs non-const arrays - if (method.isConst || method.returnType!.includes('const')) { - // For const arrays, we need to copy the data or use data() method - implementations.push(` auto& vec = _obj->get${propName}();`); - implementations.push(` if (vec.size() == 0) return nullptr;`); - implementations.push(` return (${cElementType} *) &vec[0];`); - } else { - implementations.push(` return (${cElementType} *) _obj->get${propName}().buffer();`); - } - - implementations.push(`}`); - implementations.push(''); - } - - private generateMethodCall(objName: string, method: Method, args?: string): string { - let call = `${objName}->${method.name}(${args || ''})`; - - // Handle return type conversions - if (method.returnType) { - if (method.returnType === 'const String &' || method.returnType === 'String') { - call = `(const char *) ${call}.buffer()`; - } else if (method.returnType === 'const RTTI &' || method.returnType === 'RTTI &') { - // RTTI needs special handling - return as opaque pointer - call = `(spine_rtti) &${call}`; - } else if (method.returnType.includes('*')) { - const cType = toCTypeName(method.returnType, this.validTypes); - call = `(${cType}) ${call}`; - } else if (method.returnType === 'Color &' || method.returnType === 'const Color &') { - call = `(spine_color) &${call}`; - } else if (method.returnType.includes('&')) { - // For reference returns, take the address - const cType = toCTypeName(method.returnType, this.validTypes); - call = `(${cType}) &${call}`; - } else if (!this.isPrimitiveType(method.returnType) && !this.isEnumType(method.returnType)) { - // For non-primitive value returns (e.g., BoneLocal), take the address - const cType = toCTypeName(method.returnType, this.validTypes); - call = `(${cType}) &${call}`; - } else if (this.isEnumType(method.returnType)) { - // Cast enum return values - const cType = toCTypeName(method.returnType, this.validTypes); - call = `(${cType}) ${call}`; - } - } - - return call; - } - - private generateSetterCall(objName: string, method: Method, valueName: string): string { - const param = method.parameters![0]; - let value = valueName; - - // Convert from C type to C++ - if (param.type === 'const String &' || param.type === 'String') { - value = `String(${valueName})`; - } else if (param.type.includes('Array<')) { - // Array types are passed as void* and need to be cast back - value = `(${param.type}) ${valueName}`; - } else if (param.type.includes('*')) { - value = `(${param.type}) ${valueName}`; - } else if (param.type.includes('&') && !param.type.includes('const')) { - // Non-const reference parameters need to dereference the C pointer - const baseType = param.type.replace(/\s*&\s*$/, '').trim(); - value = `*((${baseType}*) ${valueName})`; - } else if (this.isEnumType(param.type)) { - // Cast enum types - value = `(${param.type}) ${valueName}`; - } - - return `${objName}->${method.name}(${value})`; - } - - private generateMethodParameters(objTypeName: string, method: Method): { declaration: string; call: string } { - const declParts = [`${objTypeName} obj`]; - const callParts: string[] = []; - - if (method.parameters) { - for (const param of method.parameters) { - const cType = toCTypeName(param.type, this.validTypes); - declParts.push(`${cType} ${param.name}`); - - // Convert C type back to C++ for the call - let callExpr = param.name; - if (param.type === 'const String &' || param.type === 'String') { - callExpr = `String(${param.name})`; - } else if (param.type.includes('Array<')) { - // Array types are passed as void* and need to be cast back - callExpr = `(${param.type}) ${param.name}`; - } else if (param.type.includes('*')) { - callExpr = `(${param.type}) ${param.name}`; - } else if (param.type.includes('&')) { - // Handle reference types - const isConst = param.type.startsWith('const'); - const baseType = param.type.replace(/^(?:const\s+)?(.+?)\s*&$/, '$1').trim(); - - // Non-const references to primitive types are output parameters - just pass the pointer - if (!isConst && ['float', 'int', 'double', 'bool'].includes(baseType)) { - callExpr = `*${param.name}`; - } else { - // Const references and non-primitive types need dereferencing - callExpr = `*(${baseType}*) ${param.name}`; - } - } else if (this.isEnumType(param.type)) { - // Cast enum types - callExpr = `(${param.type}) ${param.name}`; - } - - callParts.push(callExpr); - } - } - - return { - declaration: declParts.join(', '), - call: callParts.join(', ') - }; - } - - private getDefaultReturn(returnType: string): string { - if (returnType === 'void') return ''; - if (returnType === 'bool') return 'false'; - if (returnType.includes('int') || returnType === 'float' || returnType === 'double' || returnType === 'size_t') return '0'; - // Check if it's an enum type (spine_* types that are not pointers) - if (returnType.startsWith('spine_') && !returnType.includes('*')) { - // Cast 0 to the enum type - return `(${returnType}) 0`; - } - return 'nullptr'; - } - - private isEnumType(type: string): boolean { - // List of known enum types in spine-cpp - const enumTypes = [ - 'EventType', 'Format', 'TextureFilter', 'TextureWrap', - 'AttachmentType', 'BlendMode', 'Inherit', 'MixBlend', - 'MixDirection', 'Physics', 'PositionMode', 'Property', - 'RotateMode', 'SequenceMode', 'SpacingMode' - ]; - return enumTypes.includes(type); - } - - private isPrimitiveType(type: string): boolean { - return ['int', 'float', 'double', 'bool', 'size_t', 'int32_t', 'uint32_t', - 'int16_t', 'uint16_t', 'uint8_t', 'void'].includes(type); - } -} \ No newline at end of file diff --git a/spine-cpp/spine-cpp/include/spine/Atlas.h b/spine-cpp/spine-cpp/include/spine/Atlas.h index e778c3713..3a847e0ea 100644 --- a/spine-cpp/spine-cpp/include/spine/Atlas.h +++ b/spine-cpp/spine-cpp/include/spine/Atlas.h @@ -96,8 +96,8 @@ namespace spine { TextureWrap vWrap; int width, height; bool pma; - int index; - void *texture; + int index; + void *texture; explicit AtlasPage(const String &inName) : name(inName), format(Format_RGBA8888), minFilter(TextureFilter_Nearest), @@ -108,13 +108,16 @@ namespace spine { class SP_API AtlasRegion : public TextureRegion { public: + AtlasRegion() : TextureRegion(), page(nullptr), name(""), index(0), x(0), y(0) {} + ~AtlasRegion() {} + AtlasPage *page; String name; int index; int x, y; Array splits; Array pads; - Array names; + Array names; Array values; }; @@ -146,6 +149,6 @@ namespace spine { void load(const char *begin, int length, const char *dir, bool createTexture); }; -} +}// namespace spine #endif /* Spine_Atlas_h */ diff --git a/spine-cpp/spine-cpp/include/spine/Color.h b/spine-cpp/spine-cpp/include/spine/Color.h index cf1eceef2..49a121925 100644 --- a/spine-cpp/spine-cpp/include/spine/Color.h +++ b/spine-cpp/spine-cpp/include/spine/Color.h @@ -121,7 +121,7 @@ namespace spine { color.a = len >= 8 ? parseHex(hexString, 3) : 1.0f; } } - + static float parseHex(const char* value, size_t index) { char digits[3]; digits[0] = value[index * 2]; diff --git a/spine-cpp/spine-cpp/include/spine/TransformConstraintData.h b/spine-cpp/spine-cpp/include/spine/TransformConstraintData.h index 310a34ae0..01fc0e4cd 100644 --- a/spine-cpp/spine-cpp/include/spine/TransformConstraintData.h +++ b/spine-cpp/spine-cpp/include/spine/TransformConstraintData.h @@ -41,6 +41,9 @@ namespace spine { class BonePose; class TransformConstraintPose; + class FromProperty; + class ToProperty; + /// Source property for a TransformConstraint. class SP_API FromProperty : public SpineObject { friend class SkeletonBinary; @@ -50,7 +53,7 @@ namespace spine { float _offset; /// Constrained properties. - Array _to; + Array _to; FromProperty(); virtual ~FromProperty(); @@ -85,66 +88,102 @@ namespace spine { class SP_API FromRotate : public FromProperty { public: + FromRotate() : FromProperty() {} + ~FromRotate() {} + float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override; }; class SP_API ToRotate : public ToProperty { public: + ToRotate() : ToProperty() {} + ~ToRotate() {} + float mix(TransformConstraintPose& pose) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; }; class SP_API FromX : public FromProperty { public: + FromX() : FromProperty() {} + ~FromX() {} + float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override; }; class SP_API ToX : public ToProperty { public: + ToX() : ToProperty() {} + ~ToX() {} + float mix(TransformConstraintPose& pose) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; }; class SP_API FromY : public FromProperty { public: + FromY() : FromProperty() {} + ~FromY() {} + float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override; }; class SP_API ToY : public ToProperty { public: + ToY() : ToProperty() {} + ~ToY() {} + float mix(TransformConstraintPose& pose) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; }; class SP_API FromScaleX : public FromProperty { public: + FromScaleX() : FromProperty() {} + ~FromScaleX() {} + float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override; }; class SP_API ToScaleX : public ToProperty { public: + ToScaleX() : ToProperty() {} + ~ToScaleX() {} + float mix(TransformConstraintPose& pose) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; }; class SP_API FromScaleY : public FromProperty { public: + FromScaleY() : FromProperty() {} + ~FromScaleY() {} + float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override; }; class SP_API ToScaleY : public ToProperty { public: + ToScaleY() : ToProperty() {} + ~ToScaleY() {} + float mix(TransformConstraintPose& pose) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; }; class SP_API FromShearY : public FromProperty { public: + FromShearY() : FromProperty() {} + ~FromShearY() {} + float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override; }; class SP_API ToShearY : public ToProperty { public: + ToShearY() : ToProperty() {} + ~ToShearY() {} + float mix(TransformConstraintPose& pose) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; }; @@ -216,14 +255,14 @@ namespace spine { void setClamp(bool clamp); /// The mapping of transform properties to other transform properties. - Array& getProperties(); + Array& getProperties(); private: Array _bones; BoneData* _source; float _offsets[6]; // [rotation, x, y, scaleX, scaleY, shearY] bool _localSource, _localTarget, _additive, _clamp; - Array _properties; + Array _properties; }; } diff --git a/spine-cpp/spine-cpp/include/spine/Vertices.h b/spine-cpp/spine-cpp/include/spine/Vertices.h deleted file mode 100644 index 8b0f37f52..000000000 --- a/spine-cpp/spine-cpp/include/spine/Vertices.h +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated April 5, 2025. Replaces all prior versions. - * - * Copyright (c) 2013-2025, Esoteric Software LLC - * - * Integration of the Spine Runtimes into software or otherwise creating - * derivative works of the Spine Runtimes is permitted under the terms and - * conditions of Section 2 of the Spine Editor License Agreement: - * http://esotericsoftware.com/spine-editor-license - * - * Otherwise, it is permitted to integrate the Spine Runtimes into software - * or otherwise create derivative works of the Spine Runtimes (collectively, - * "Products"), provided that each user of the Products must obtain their own - * Spine Editor license and redistribution of the Products in any form must - * include this license and copyright notice. - * - * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, - * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef Spine_Vertices_h -#define Spine_Vertices_h - -#include - -namespace spine { - class SP_API Vertices : public SpineObject { - public: - Array _bones; - Array _weights; - }; -} - -#endif /* Spine_Vertices_h */ diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp index f75c20ccb..5c52f946f 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp @@ -73,7 +73,6 @@ #include #include #include -#include #include #include #include @@ -85,29 +84,42 @@ using namespace spine; +class SP_API Vertices : public SpineObject { +public: + Array _bones; + Array _weights; +}; + #define SKELETON_JSON_ERROR(root, message, value) \ - do { \ - delete skeletonData; \ - setError(root, message, value); \ - return NULL; \ + do { \ + delete skeletonData; \ + setError(root, message, value); \ + return NULL; \ } while (0) -static FromProperty* fromProperty(const char* type) { +static FromProperty *fromProperty(const char *type) { if (strcmp(type, "rotate") == 0) return new FromRotate(); - else if (strcmp(type, "x") == 0) return new FromX(); - else if (strcmp(type, "y") == 0) return new FromY(); - else if (strcmp(type, "scaleX") == 0) return new FromScaleX(); - else if (strcmp(type, "scaleY") == 0) return new FromScaleY(); - else if (strcmp(type, "shearY") == 0) return new FromShearY(); - else return NULL; + else if (strcmp(type, "x") == 0) + return new FromX(); + else if (strcmp(type, "y") == 0) + return new FromY(); + else if (strcmp(type, "scaleX") == 0) + return new FromScaleX(); + else if (strcmp(type, "scaleY") == 0) + return new FromScaleY(); + else if (strcmp(type, "shearY") == 0) + return new FromShearY(); + else + return NULL; } -static float propertyScale(const char* type, float scale) { +static float propertyScale(const char *type, float scale) { if (strcmp(type, "x") == 0 || strcmp(type, "y") == 0) return scale; - else return 1; + else + return 1; } -SkeletonJson::SkeletonJson(Atlas *atlas) : _attachmentLoader(new (__FILE__, __LINE__) AtlasAttachmentLoader(atlas)), +SkeletonJson::SkeletonJson(Atlas *atlas) : _attachmentLoader(new(__FILE__, __LINE__) AtlasAttachmentLoader(atlas)), _scale(1), _ownsLoader(true) {} SkeletonJson::SkeletonJson(AttachmentLoader *attachmentLoader, bool ownsLoader) : _attachmentLoader(attachmentLoader), @@ -284,8 +296,7 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { skeletonData->_ikConstraints.add(data); skeletonData->_constraints.add(data); - } - else if (strcmp(type, "transform") == 0) { + } else if (strcmp(type, "transform") == 0) { TransformConstraintData *data = new (__FILE__, __LINE__) TransformConstraintData(name); data->setSkinRequired(skinRequired); @@ -351,7 +362,8 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { } if (from->_to.size() > 0) data->_properties.add(from); - else delete from; + else + delete from; } } @@ -372,8 +384,7 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { skeletonData->_transformConstraints.add(data); skeletonData->_constraints.add(data); - } - else if (strcmp(type, "path") == 0) { + } else if (strcmp(type, "path") == 0) { PathConstraintData *data = new (__FILE__, __LINE__) PathConstraintData(name); data->setSkinRequired(skinRequired); @@ -404,8 +415,7 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { skeletonData->_pathConstraints.add(data); skeletonData->_constraints.add(data); - } - else if (strcmp(type, "physics") == 0) { + } else if (strcmp(type, "physics") == 0) { PhysicsConstraintData *data = new (__FILE__, __LINE__) PhysicsConstraintData(name); data->setSkinRequired(skinRequired); @@ -438,8 +448,7 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { skeletonData->_physicsConstraints.add(data); skeletonData->_constraints.add(data); - } - else if (strcmp(type, "slider") == 0) { + } else if (strcmp(type, "slider") == 0) { SliderData *data = new (__FILE__, __LINE__) SliderData(name); data->setSkinRequired(skinRequired); data->_additive = Json::getBoolean(constraintMap, "additive", false); @@ -529,7 +538,8 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { for (Json *entry = slotEntry->_child; entry; entry = entry->_next) { Attachment *attachment = readAttachment(entry, skin, slot->getIndex(), entry->_name, skeletonData); if (attachment) skin->setAttachment(slot->getIndex(), entry->_name, attachment); - else SKELETON_JSON_ERROR(root, "Error reading attachment: ", entry->_name); + else + SKELETON_JSON_ERROR(root, "Error reading attachment: ", entry->_name); } } @@ -550,7 +560,7 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { Attachment *parent = skin->getAttachment(linkedMesh->_slotIndex, linkedMesh->_parent); if (parent == NULL) SKELETON_JSON_ERROR(root, "Parent mesh not found: ", linkedMesh->_parent.buffer()); linkedMesh->_mesh->_timelineAttachment = linkedMesh->_inheritTimelines ? static_cast(parent) - : linkedMesh->_mesh; + : linkedMesh->_mesh; linkedMesh->_mesh->setParentMesh(static_cast(parent)); if (linkedMesh->_mesh->_region != NULL) linkedMesh->_mesh->updateRegion(); } @@ -694,7 +704,7 @@ Attachment *SkeletonJson::readAttachment(Json *map, Skin *skin, int slotIndex, c readVertices(map, path, vertexCount << 1); if (!Json::asArray(Json::getItem(map, "lengths"), path->_lengths)) return NULL; - for (int i = 0; i < (int)path->_lengths.size(); i++) + for (int i = 0; i < (int) path->_lengths.size(); i++) path->_lengths[i] *= scale; const char *color = Json::getString(map, "color", NULL); @@ -749,7 +759,7 @@ void SkeletonJson::readVertices(Json *map, VertexAttachment *attachment, size_t if (!Json::asArray(Json::getItem(map, "vertices"), vertices)) return; if (verticesLength == vertices.size()) { if (_scale != 1) { - for (int i = 0; i < (int)vertices.size(); ++i) + for (int i = 0; i < (int) vertices.size(); ++i) vertices[i] *= _scale; } attachment->getVertices().clearAndAddAll(vertices); @@ -824,7 +834,7 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { } else if (strcmp(timelineMap->_name, "rgb") == 0) { RGBTimeline *timeline = new (__FILE__, __LINE__) RGBTimeline(frames, frames * 3, slotIndex); float time = Json::getFloat(keyMap, "time", 0); - const char* colorStr = Json::getString(keyMap, "color", 0); + const char *colorStr = Json::getString(keyMap, "color", 0); Color color; if (colorStr && strlen(colorStr) >= 6) { color.r = Color::parseHex(colorStr, 0); @@ -839,7 +849,7 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { break; } float time2 = Json::getFloat(nextMap, "time", 0); - const char* colorStr2 = Json::getString(nextMap, "color", 0); + const char *colorStr2 = Json::getString(nextMap, "color", 0); Color newColor; if (colorStr2 && strlen(colorStr2) >= 6) { newColor.r = Color::parseHex(colorStr2, 0); @@ -866,7 +876,7 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { float time = Json::getFloat(keyMap, "time", 0); Color color, color2; Color::valueOf(Json::getString(keyMap, "light", 0), color); - const char* darkStr = Json::getString(keyMap, "dark", 0); + const char *darkStr = Json::getString(keyMap, "dark", 0); if (darkStr && strlen(darkStr) >= 6) { color2.r = Color::parseHex(darkStr, 0); color2.g = Color::parseHex(darkStr, 1); @@ -882,7 +892,7 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { float time2 = Json::getFloat(nextMap, "time", 0); Color newColor, newColor2; Color::valueOf(Json::getString(nextMap, "light", 0), newColor); - const char* darkStr2 = Json::getString(nextMap, "dark", 0); + const char *darkStr2 = Json::getString(nextMap, "dark", 0); if (darkStr2 && strlen(darkStr2) >= 6) { newColor2.r = Color::parseHex(darkStr2, 0); newColor2.g = Color::parseHex(darkStr2, 1); @@ -907,14 +917,14 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { } else if (strcmp(timelineMap->_name, "rgb2") == 0) { RGB2Timeline *timeline = new (__FILE__, __LINE__) RGB2Timeline(frames, frames * 6, slotIndex); float time = Json::getFloat(keyMap, "time", 0); - const char* lightStr = Json::getString(keyMap, "light", 0); + const char *lightStr = Json::getString(keyMap, "light", 0); Color color, color2; if (lightStr && strlen(lightStr) >= 6) { color.r = Color::parseHex(lightStr, 0); color.g = Color::parseHex(lightStr, 1); color.b = Color::parseHex(lightStr, 2); } - const char* darkStr = Json::getString(keyMap, "dark", 0); + const char *darkStr = Json::getString(keyMap, "dark", 0); if (darkStr && strlen(darkStr) >= 6) { color2.r = Color::parseHex(darkStr, 0); color2.g = Color::parseHex(darkStr, 1); @@ -928,14 +938,14 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { break; } float time2 = Json::getFloat(nextMap, "time", 0); - const char* lightStr2 = Json::getString(nextMap, "light", 0); + const char *lightStr2 = Json::getString(nextMap, "light", 0); Color newColor, newColor2; if (lightStr2 && strlen(lightStr2) >= 6) { newColor.r = Color::parseHex(lightStr2, 0); newColor.g = Color::parseHex(lightStr2, 1); newColor.b = Color::parseHex(lightStr2, 2); } - const char* darkStr2 = Json::getString(nextMap, "dark", 0); + const char *darkStr2 = Json::getString(nextMap, "dark", 0); if (darkStr2 && strlen(darkStr2) >= 6) { newColor2.r = Color::parseHex(darkStr2, 0); newColor2.g = Color::parseHex(darkStr2, 1); @@ -1029,7 +1039,7 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { float mix = Json::getFloat(keyMap, "mix", 1), softness = Json::getFloat(keyMap, "softness", 0) * _scale; for (int frame = 0, bezier = 0;; frame++) { timeline->setFrame(frame, time, mix, softness, Json::getBoolean(keyMap, "bendPositive", true) ? 1 : -1, - Json::getBoolean(keyMap, "compress", false), Json::getBoolean(keyMap, "stretch", false)); + Json::getBoolean(keyMap, "compress", false), Json::getBoolean(keyMap, "stretch", false)); Json *nextMap = keyMap->_next; if (!nextMap) { break; @@ -1123,15 +1133,15 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { readTimeline(timelines, keyMap, timeline, 0, constraint->_positionMode == PositionMode_Fixed ? _scale : 1); } else if (strcmp(timelineName, "spacing") == 0) { CurveTimeline1 *timeline = new (__FILE__, __LINE__) PathConstraintSpacingTimeline(frames, frames, - index); + index); readTimeline(timelines, keyMap, timeline, 0, constraint->_spacingMode == SpacingMode_Length || - constraint->_spacingMode == SpacingMode_Fixed - ? _scale - : 1); + constraint->_spacingMode == SpacingMode_Fixed + ? _scale + : 1); } else if (strcmp(timelineName, "mix") == 0) { PathConstraintMixTimeline *timeline = new (__FILE__, __LINE__) PathConstraintMixTimeline(frames, - frames * 3, index); + frames * 3, index); float time = Json::getFloat(keyMap, "time", 0); float mixRotate = Json::getFloat(keyMap, "mixRotate", 1); float mixX = Json::getFloat(keyMap, "mixX", 1); @@ -1307,7 +1317,7 @@ Animation *SkeletonJson::readAnimation(Json *map, SkeletonData *skeletonData) { for (int frame = 0; keyMap != NULL; keyMap = keyMap->_next, frame++) { float delay = Json::getFloat(keyMap, "delay", lastDelay); timeline->setFrame(frame, Json::getFloat(keyMap, "time", 0), - SequenceMode_valueOf(Json::getString(keyMap, "mode", "hold")), Json::getInt(keyMap, "index", 0), delay); + SequenceMode_valueOf(Json::getString(keyMap, "mode", "hold")), Json::getInt(keyMap, "index", 0), delay); lastDelay = delay; } timelines.add(timeline); @@ -1408,7 +1418,7 @@ void SkeletonJson::readTimeline(Array &timelines, Json *keyMap, Curv } void SkeletonJson::readTimeline(Array &timelines, Json *keyMap, CurveTimeline2 *timeline, const char *name1, const char *name2, - float defaultValue, float scale) { + float defaultValue, float scale) { float time = Json::getFloat(keyMap, "time", 0); float value1 = Json::getFloat(keyMap, name1, defaultValue) * scale, value2 = Json::getFloat(keyMap, name2, defaultValue) * scale; for (int frame = 0, bezier = 0;; frame++) {