void UI_InitNodes (void) { int i = 0; uiBehaviour_t *current = nodeBehaviourList; /* compute list of node behaviours */ for (i = 0; i < NUMBER_OF_BEHAVIOURS; i++) { registerFunctions[i](current); current++; } /* check for safe data: list must be sorted by alphabet */ current = nodeBehaviourList; assert(current); for (i = 0; i < NUMBER_OF_BEHAVIOURS - 1; i++) { const uiBehaviour_t *a = current; const uiBehaviour_t *b = current + 1; assert(b); if (strcmp(a->name, b->name) >= 0) { #ifdef DEBUG Com_Error(ERR_FATAL, "UI_InitNodes: '%s' is before '%s'. Please order node behaviour registrations by name", a->name, b->name); #else Com_Error(ERR_FATAL, "UI_InitNodes: Error: '%s' is before '%s'", a->name, b->name); #endif } current++; } /* finalize node behaviour initialization */ current = nodeBehaviourList; for (i = 0; i < NUMBER_OF_BEHAVIOURS; i++) { UI_InitializeNodeBehaviour(current); current++; } }
/** * Initializes the inheritance (every node extends the abstract node) * @param behaviour The behaviour to initialize */ static void UI_InitializeNodeBehaviour (uiBehaviour_t* behaviour) { if (behaviour->isInitialized) return; /** @todo check (when its possible) properties are ordered by name */ /* check and update properties data */ if (behaviour->properties) { int num = 0; const value_t* current = behaviour->properties; while (current->string != NULL) { num++; current++; } behaviour->propertyCount = num; } /* everything inherits 'abstractnode' */ if (behaviour->extends == NULL && !Q_streq(behaviour->name, "abstractnode")) { behaviour->extends = "abstractnode"; } if (behaviour->extends) { int i = 0; behaviour->super = UI_GetNodeBehaviour(behaviour->extends); UI_InitializeNodeBehaviour(behaviour->super); while (qtrue) { const size_t pos = virtualFunctions[i]; uintptr_t superFunc; uintptr_t func; if (pos == -1) break; /* cache super function if we don't overwrite it */ superFunc = *(uintptr_t*)((byte*)behaviour->super + pos); func = *(uintptr_t*)((byte*)behaviour + pos); if (func == 0 && superFunc != 0) *(uintptr_t*)((byte*)behaviour + pos) = superFunc; i++; } } /* property must not overwrite another property */ if (behaviour->super && behaviour->properties) { const value_t* property = behaviour->properties; while (property->string != NULL) { const value_t *p = UI_GetPropertyFromBehaviour(behaviour->super, property->string); #if 0 /**< @todo not possible at the moment, not sure its the right way */ const uiBehaviour_t *b = UI_GetNodeBehaviour(current->string); #endif if (p != NULL) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' overwrite another property", property->string, behaviour->name); #if 0 /**< @todo not possible at the moment, not sure its the right way */ if (b != NULL) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' use the name of an existing node behaviour", property->string, behaviour->name); #endif property++; } } /* Sanity: A property must not be outside the node memory */ if (behaviour->properties) { const int size = sizeof(uiNode_t) + behaviour->extraDataSize; const value_t* property = behaviour->properties; while (property->string != NULL) { if (property->type != V_UI_NODEMETHOD && property->ofs + property->size > size) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' is outside the node memory. The C code need a fix.", property->string, behaviour->name); property++; } } behaviour->isInitialized = qtrue; }
/** * @brief Initialize a node behaviour memory, after registration, and before unsing it. * @param behaviour Behaviour to initialize */ void UI_InitializeNodeBehaviour (uiBehaviour_t* behaviour) { if (behaviour->isInitialized) return; /* everything inherits 'abstractnode' */ if (behaviour->extends == NULL && !Q_streq(behaviour->name, "abstractnode")) { behaviour->extends = "abstractnode"; } if (behaviour->extends) { int i = 0; /** TODO Find a way to remove that, if possible */ behaviour->super = UI_GetNodeBehaviour(behaviour->extends); UI_InitializeNodeBehaviour(behaviour->super); while (qtrue) { const size_t pos = virtualFunctions[i]; uintptr_t superFunc; uintptr_t func; if (pos == -1) break; /* cache super function if we don't overwrite it */ superFunc = *(uintptr_t*)((byte*)behaviour->super + pos); func = *(uintptr_t*)((byte*)behaviour + pos); if (func == 0 && superFunc != 0) *(uintptr_t*)((byte*)behaviour + pos) = superFunc; i++; } } /* sort properties by alphabet */ if (behaviour->localProperties) { int i = 0; const value_t* previous; const value_t** oldmemory = behaviour->localProperties; behaviour->localProperties = UI_AllocHunkMemory(sizeof(value_t*) * (behaviour->propertyCount+1), STRUCT_MEMORY_ALIGN, qfalse); if (behaviour->localProperties == NULL) { Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: UI memory hunk exceeded - increase the size"); } previous = NULL; for (i = 0; i < behaviour->propertyCount; i++) { const value_t* better = NULL; const value_t** current; /* search the next element after previous */ for (current = oldmemory; *current != NULL; current++) { if (previous != NULL && Q_strcasecmp(previous->string, (*current)->string) >= 0) { continue; } if (better == NULL || Q_strcasecmp(better->string, (*current)->string) >= 0) { better = *current; } } previous = better; behaviour->localProperties[i] = better; } behaviour->localProperties[behaviour->propertyCount] = NULL; Mem_Free(oldmemory); } /* property must not overwrite another property */ if (behaviour->super && behaviour->localProperties) { const value_t** property = behaviour->localProperties; while (*property) { const value_t *p = UI_GetPropertyFromBehaviour(behaviour->super, (*property)->string); #if 0 /**< @todo not possible at the moment, not sure its the right way */ const uiBehaviour_t *b = UI_GetNodeBehaviour(current->string); #endif if (p != NULL) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' overwrite another property", (*property)->string, behaviour->name); #if 0 /**< @todo not possible at the moment, not sure its the right way */ if (b != NULL) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' use the name of an existing node behaviour", (*property)->string, behaviour->name); #endif property++; } } /* Sanity: A property must not be outside the node memory */ if (behaviour->localProperties) { const int size = sizeof(uiNode_t) + behaviour->extraDataSize; const value_t** property = behaviour->localProperties; while (*property) { if ((*property)->type != V_UI_NODEMETHOD && (*property)->ofs + (*property)->size > size) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' is outside the node memory. The C code need a fix.", (*property)->string, behaviour->name); property++; } } behaviour->isInitialized = qtrue; }