From lordhavoc at icculus.org Thu May 4 19:09:55 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 4 May 2006 19:09:55 -0400 Subject: r702 - trunk Message-ID: <20060504230955.23533.qmail@icculus.org> Author: lordhavoc Date: 2006-05-04 19:09:55 -0400 (Thu, 04 May 2006) New Revision: 702 Modified: trunk/material.c Log: added a hack to detect skybox at load and use texture clamping on it, this hack will be removed when a material language is implemented someday Modified: trunk/material.c =================================================================== --- trunk/material.c 2006-04-18 11:01:00 UTC (rev 701) +++ trunk/material.c 2006-05-04 23:09:55 UTC (rev 702) @@ -9,53 +9,60 @@ char *filename; r->data = material = Mem_Alloc(r->memzone, sizeof(Material)); filename = String_APrintf(r->memzone, "%s.tga", r->name); - material->texture_color = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - String_Free(&filename); - filename = String_APrintf(r->memzone, "%s_norm.tga", r->name); - material->texture_normal = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - String_Free(&filename); - if (!Resource_GetData(material->texture_normal)) + // TODO: eventually add a material language, until then this skybox hack is needed + if (strstr(r->name, "sky")) { - filename = String_APrintf(r->memzone, "%s_bump.tga", r->name); - material->texture_normal = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP | RESOURCEFLAG_BUMPMAPASNORMALMAP, 4); + material->texture_color = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP | RESOURCEFLAG_CLAMP, 0); String_Free(&filename); } - filename = String_APrintf(r->memzone, "%s_gloss.tga", r->name); - material->texture_gloss = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - String_Free(&filename); - filename = String_APrintf(r->memzone, "%s_glow.tga", r->name); - material->texture_glow = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - String_Free(&filename); - filename = String_APrintf(r->memzone, "%s_back.tga", r->name); - material->texture_background = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - String_Free(&filename); - material->specularpower = 8; - // these can be used for High Dynamic Range (HDR), boosting a material's - // specular intensity to allow a gloss texture to have the RGB range 0-4 - // instead of 0-1. - // ambient can be used instead of diffuse and specular to make soft-shaded - // materials like snow which react very little to light direction. - material->ambientintensity = 1; - material->diffuseintensity = 1; - material->specularintensity = 1; - // offset mapping is off by default, - // example values: scale 0.04, bias -0.02 - material->offsetmapping_scale = 0; - material->offsetmapping_bias = 0; + else + { + material->texture_color = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + String_Free(&filename); + filename = String_APrintf(r->memzone, "%s_norm.tga", r->name); + material->texture_normal = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + String_Free(&filename); + if (!Resource_GetData(material->texture_normal)) + { + filename = String_APrintf(r->memzone, "%s_bump.tga", r->name); + material->texture_normal = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP | RESOURCEFLAG_BUMPMAPASNORMALMAP, 4); + String_Free(&filename); + } + filename = String_APrintf(r->memzone, "%s_gloss.tga", r->name); + material->texture_gloss = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + String_Free(&filename); + filename = String_APrintf(r->memzone, "%s_glow.tga", r->name); + material->texture_glow = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + String_Free(&filename); + filename = String_APrintf(r->memzone, "%s_back.tga", r->name); + material->texture_background = Resource_IndexForName(filename, RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + String_Free(&filename); + material->specularpower = 8; + // these can be used for High Dynamic Range (HDR), boosting a material's + // specular intensity to allow a gloss texture to have the RGB range 0-4 + // instead of 0-1. + // ambient can be used instead of diffuse and specular to make soft-shaded + // materials like snow which react very little to light direction. + material->ambientintensity = 1; + material->diffuseintensity = 1; + material->specularintensity = 1; + // offset mapping is off by default, + // example values: scale 0.04, bias -0.02 + material->offsetmapping_scale = 0; + material->offsetmapping_bias = 0; - // if some textures are missing, load default - if (!Resource_GetData(material->texture_color)) - material->texture_color = Resource_IndexForName("engine/default.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - if (!Resource_GetData(material->texture_normal)) - material->texture_normal = Resource_IndexForName("engine/default_norm.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - if (!Resource_GetData(material->texture_gloss)) - material->texture_gloss = 0;//Resource_IndexForName("engine/default_gloss.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - if (!Resource_GetData(material->texture_glow)) - material->texture_glow = Resource_IndexForName("engine/default_glow.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - if (!Resource_GetData(material->texture_background)) - material->texture_background = 0;//Resource_IndexForName("engine/default_back.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); - - // TODO: eventually add a material language + // if some textures are missing, load default + if (!Resource_GetData(material->texture_color)) + material->texture_color = Resource_IndexForName("engine/default.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + if (!Resource_GetData(material->texture_normal)) + material->texture_normal = Resource_IndexForName("engine/default_norm.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + if (!Resource_GetData(material->texture_gloss)) + material->texture_gloss = 0;//Resource_IndexForName("engine/default_gloss.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + if (!Resource_GetData(material->texture_glow)) + material->texture_glow = Resource_IndexForName("engine/default_glow.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + if (!Resource_GetData(material->texture_background)) + material->texture_background = 0;//Resource_IndexForName("engine/default_back.tga", RESOURCETYPE_TEXTURE, RESOURCEFLAG_MIPMAP, 0); + } } void Material_Unload(UNUSED ResourceEntry *r) From lordhavoc at icculus.org Fri May 5 12:23:34 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 5 May 2006 12:23:34 -0400 Subject: r703 - trunk/game Message-ID: <20060505162334.18844.qmail@icculus.org> Author: lordhavoc Date: 2006-05-05 12:23:34 -0400 (Fri, 05 May 2006) New Revision: 703 Modified: trunk/game/g_entity.c trunk/game/g_main.h Log: thanks to painQuin for a patch to handle freed entity timeouts (to give other entities a chance to notice that their reference is dead) Modified: trunk/game/g_entity.c =================================================================== --- trunk/game/g_entity.c 2006-05-04 23:09:55 UTC (rev 702) +++ trunk/game/g_entity.c 2006-05-05 16:23:34 UTC (rev 703) @@ -8,7 +8,9 @@ G_Entity *G_Entity_New(G_Entity *parent, const G_Entity_Class *eclass, const G_Entity_Position *position) { G_Entity *entity; - NUint32 childindex = 0; + Nbool bestfound = false; + Nvec tbest = 0; + NUint32 childindex = 0, bestindex = 0; if (!eclass) return NULL; if (!eclass->codeclass->name) @@ -33,32 +35,56 @@ } if (!position) position = &GS.identityposition; - // TODO: add a timeout after freeing an entity before it will be reused? (if so this will need to scan twice if it can't find one with the timeout) + for (entity = G.entities + G.allocentity;G.allocentity < G_MAX_ENTITIES;G.allocentity++, entity++) { if (!entity->eclass) { - G.allocentity++; - G.numentities = Max(G.numentities, G.allocentity); - memset(entity, 0, sizeof(G_Entity)); - entity->eclass = eclass; - // mark this entity as not being a network related entity - // (if it really is, the network code will change this) - entity->networkindex = -1; - if (parent) + if (G.time - entity->freetime >= FREETIMEOUT) { - entity->owner = parent; - parent->children[childindex] = entity; + // this entity has not been used recently, so anything + // referencing it has probably cleared its references already, + // so it is probably safe to reuse it now + bestfound = true; + bestindex = G.allocentity++; + break; } - entity->position = *position; - if (entity->eclass->modelname && entity->eclass->modelname[0]) - G_Entity_SetModel(entity, entity->eclass->modelname); - entity->lifetime = entity->eclass->lifetime; - return entity; + else if (!foundbest || (entity->freetime < tbest)) + { + // found a free slot that hasn't timed out yet, keep track of + // which one is oldest incase we can't find one + // (this is a dangerous situation but it's even worse to fail) + foundbest = true; + bestindex = G.allocentity; + tbest = entity->freetime; + } } } - Console_Printf("Ran out of entities (%i)\n", G_MAX_ENTITIES); - return NULL; + if (!bestfound) + { + Console_Printf("Ran out of entities (%i)\n", G_MAX_ENTITIES); + return NULL; + } + entity = G.entities + bestindex; + // update entity range to include this newly allocated entity + // (the entity range is used to avoid processing the entire array each + // frame) + G.numentities = Max(G.numentities, bestindex); + memset(entity, 0, sizeof(G_Entity)); + entity->eclass = eclass; + // mark this entity as not being a network related entity + // (if it really is, the network code will change this) + entity->networkindex = -1; + if (parent) + { + entity->owner = parent; + parent->children[childindex] = entity; + } + entity->position = *position; + if (entity->eclass->modelname && entity->eclass->modelname[0]) + G_Entity_SetModel(entity, entity->eclass->modelname); + entity->lifetime = entity->eclass->lifetime; + return entity; } void G_Entity_Spawn(G_Entity *entity) @@ -115,6 +141,7 @@ memset(entity, 0, sizeof(*entity)); // reset allocentity to a level that will find this freshly freed entity G.allocentity = Min(G.allocentity, entitynum); + entity->freetime = G.time; } void G_Entity_RemoveChildren(G_Entity *entity) Modified: trunk/game/g_main.h =================================================================== --- trunk/game/g_main.h 2006-05-04 23:09:55 UTC (rev 702) +++ trunk/game/g_main.h 2006-05-05 16:23:34 UTC (rev 703) @@ -541,9 +541,14 @@ Nvec lifetime; // weapons Nvec attackdelay; + + Nvec freetime; } G_Entity; +// number of seconds before an entity slot will be reused (unless overloaded, in which case the least recently freed entity will be chosen) +#define FREETIMEOUT 0.2 + typedef struct G_Trace { G_Entity *moveentity; From lordhavoc at icculus.org Fri May 5 15:08:10 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 5 May 2006 15:08:10 -0400 Subject: r704 - trunk/game Message-ID: <20060505190810.15480.qmail@icculus.org> Author: lordhavoc Date: 2006-05-05 15:08:10 -0400 (Fri, 05 May 2006) New Revision: 704 Modified: trunk/game/g_entity.c Log: fix for previous patch (oops, I named a variable bestfound but forgot to edit two foundbest references) Modified: trunk/game/g_entity.c =================================================================== --- trunk/game/g_entity.c 2006-05-05 16:23:34 UTC (rev 703) +++ trunk/game/g_entity.c 2006-05-05 19:08:10 UTC (rev 704) @@ -49,12 +49,12 @@ bestindex = G.allocentity++; break; } - else if (!foundbest || (entity->freetime < tbest)) + else if (!bestfound || (entity->freetime < tbest)) { // found a free slot that hasn't timed out yet, keep track of // which one is oldest incase we can't find one // (this is a dangerous situation but it's even worse to fail) - foundbest = true; + bestfound = true; bestindex = G.allocentity; tbest = entity->freetime; } From lordhavoc at icculus.org Fri May 5 15:09:19 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 5 May 2006 15:09:19 -0400 Subject: r705 - trunk Message-ID: <20060505190919.15569.qmail@icculus.org> Author: lordhavoc Date: 2006-05-05 15:09:19 -0400 (Fri, 05 May 2006) New Revision: 705 Modified: trunk/r_main.c trunk/resource.c Log: some warning prints done by painQuin Modified: trunk/r_main.c =================================================================== --- trunk/r_main.c 2006-05-05 19:08:10 UTC (rev 704) +++ trunk/r_main.c 2006-05-05 19:09:19 UTC (rev 705) @@ -1914,17 +1914,29 @@ return; // TODO: verify the resource type is RESOURCETYPE_MODEL model = Resource_GetData(R.entitymodelresource); - if (!model) - return; // TODO: warning + if (!model) { + Console_Printf("R_DrawMesh failed to find model\n"); + return; + } // TODO: verify the resource type is RESOURCETYPE_MATERIAL material = Resource_GetData(materialresource); - if (!material) - return; // TODO: warning - if (meshindex >= model->num_meshes) - return; // TODO: warning + if (!material) { + Console_Printf("R_DrawMesh failed to find material\n"); + return; + } + if (meshindex >= model->num_meshes) { + Console_Printf("R_DrawMesh meshindex out of bounds\n"); + return; + } mesh = model->data_meshes + meshindex; - if (mesh->num_vertices < 1 || mesh->num_triangles < 1) - return; // TODO: warning + if (mesh->num_vertices < 1) { + Console_Printf("R_DrawMesh num_vertices out of range\n"); + return; + } + if (mesh->num_triangles < 1) { + Console_Printf("R_DrawMesh num_triangles out of range\n"); + return; + } R.speeds_data.numdrawmesh_vertices += mesh->num_vertices; R.speeds_data.numdrawmesh_triangles += mesh->num_triangles; switch (R.drawmode) Modified: trunk/resource.c =================================================================== --- trunk/resource.c 2006-05-05 19:08:10 UTC (rev 704) +++ trunk/resource.c 2006-05-05 19:09:19 UTC (rev 705) @@ -178,7 +178,8 @@ switch(r->type) { case RESOURCETYPE_INVALID: - // TODO: error? + Console_Printf("Resource Load: Unknown Resource Type: %i\n", + r->type); break; case RESOURCETYPE_MODEL: Model_Load(r); @@ -220,7 +221,8 @@ switch(r->type) { case RESOURCETYPE_INVALID: - // TODO: error? + Console_Printf("Resource Unload: Unknown Resource Type: %i\n", + r->type); break; case RESOURCETYPE_MODEL: Model_Unload(r); From lordhavoc at icculus.org Fri May 5 15:28:50 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 5 May 2006 15:28:50 -0400 Subject: r706 - trunk/game Message-ID: <20060505192850.18116.qmail@icculus.org> Author: lordhavoc Date: 2006-05-05 15:28:49 -0400 (Fri, 05 May 2006) New Revision: 706 Modified: trunk/game/m_menucore.c trunk/game/m_menucore.h Log: function pointer casts patch from painQuin to hush warnings Modified: trunk/game/m_menucore.c =================================================================== --- trunk/game/m_menucore.c 2006-05-05 19:09:19 UTC (rev 705) +++ trunk/game/m_menucore.c 2006-05-05 19:28:49 UTC (rev 706) @@ -196,10 +196,10 @@ item = Mem_Alloc(Menu.menu_zone, bytes); - item->Frame = Menu_Generic_Frame; + item->Frame = (MenuItemFrame_t)Menu_Generic_Frame; item->MouseMove = Menu_Generic_MouseMoveNonSelectable; - item->KeyEvent = Menu_Generic_KeyPressIgnore; - item->Destroy = Menu_Generic_Destroy; + item->KeyEvent = (MenuItemKeyEvent_t)Menu_Generic_KeyPressIgnore; + item->Destroy = (MenuItemDestroy_t)Menu_Generic_Destroy; item->type = type; @@ -247,11 +247,11 @@ Menu_TextItem *it; it = (Menu_TextItem*)Menu_Generic_Create(parent, MENU_ITEMTYPE_TEXT, x, y, sizeof(Menu_TextItem)); - it->super.Draw = Menu_Text_Draw; + it->super.Draw = (MenuItemDraw_t)Menu_Text_Draw; if (cookie != NULL) { - it->super.MouseMove = Menu_Generic_MouseMoveSelectable; - it->super.KeyEvent = Menu_Text_KeyPress; + it->super.MouseMove = (MenuItemMouseMove_t)Menu_Generic_MouseMoveSelectable; + it->super.KeyEvent = (MenuItemKeyEvent_t)Menu_Text_KeyPress; } it->super.size[0] = 8*strlen(text); it->super.size[1] = 8; @@ -356,9 +356,9 @@ Menu_EditItem *it; it = (Menu_EditItem*)Menu_Generic_Create(parent, MENU_ITEMTYPE_EDIT, x, y, sizeof(Menu_EditItem)); - it->super.Draw = Menu_Edit_Draw; - it->super.MouseMove = Menu_Generic_MouseMoveSelectable; - it->super.KeyEvent = Menu_Edit_KeyPress; + it->super.Draw = (MenuItemDraw_t)Menu_Edit_Draw; + it->super.MouseMove = (MenuItemMouseMove_t)Menu_Generic_MouseMoveSelectable; + it->super.KeyEvent = (MenuItemKeyEvent_t)Menu_Edit_KeyPress; it->super.size[0] = 8*strlen(text); it->super.size[1] = 8; @@ -481,10 +481,10 @@ Menu_ComboItem *it; it = (Menu_ComboItem*)Menu_Generic_Create(parent, MENU_ITEMTYPE_COMBO, x, y, sizeof(Menu_ComboItem)); - it->super.super.Draw = Menu_Combo_Draw; - it->super.super.MouseMove = Menu_Generic_MouseMoveSelectable; - it->super.super.KeyEvent = Menu_Combo_KeyPress; - it->super.super.Destroy = Menu_Combo_Destroy; + it->super.super.Draw = (MenuItemDraw_t)Menu_Combo_Draw; + it->super.super.MouseMove = (MenuItemMouseMove_t)Menu_Generic_MouseMoveSelectable; + it->super.super.KeyEvent = (MenuItemKeyEvent_t)Menu_Combo_KeyPress; + it->super.super.Destroy = (MenuItemDestroy_t)Menu_Combo_Destroy; it->super.super.size[0] = w; it->super.super.size[1] = 8; @@ -558,11 +558,11 @@ Menu_PictureItem *it; it = (Menu_PictureItem*)Menu_Generic_Create(parent, MENU_ITEMTYPE_PICTURE, x, y, sizeof(Menu_PictureItem)); - it->super.Draw = Menu_Picture_Draw; + it->super.Draw = (MenuItemDraw_t)Menu_Picture_Draw; if (command != NULL) { - it->super.MouseMove = Menu_Generic_MouseMoveSelectable; - it->super.KeyEvent = Menu_Picture_KeyPress; + it->super.MouseMove = (MenuItemMouseMove_t)Menu_Generic_MouseMoveSelectable; + it->super.KeyEvent = (MenuItemKeyEvent_t)Menu_Picture_KeyPress; } it->super.size[0] = w; it->super.size[1] = h; @@ -671,9 +671,9 @@ Menu_SliderItem *it; it = (Menu_SliderItem*)Menu_Generic_Create(parent, MENU_ITEMTYPE_SLIDER, x, y, sizeof(Menu_SliderItem)); - it->super.Draw = Menu_Slider_Draw; - it->super.MouseMove = Menu_Generic_MouseMoveSelectable; - it->super.KeyEvent = Menu_Slider_KeyPress; + it->super.Draw = (MenuItemDraw_t)Menu_Slider_Draw; + it->super.MouseMove = (MenuItemMouseMove_t)Menu_Generic_MouseMoveSelectable; + it->super.KeyEvent = (MenuItemKeyEvent_t)Menu_Slider_KeyPress; it->super.size[0] = w; it->super.size[1] = h; @@ -877,11 +877,11 @@ Menu_SubMenu_AddAtFront(parent, &menu->super); } - menu->super.MouseMove = Menu_SubMenu_MouseMove; - menu->super.Frame = Menu_SubMenu_Frame; - menu->super.Draw = Menu_SubMenu_Draw; - menu->super.KeyEvent = Menu_SubMenu_KeyEvent; - menu->super.Destroy = Menu_SubMenu_Destroy; + menu->super.MouseMove = (MenuItemMouseMove_t)Menu_SubMenu_MouseMove; + menu->super.Frame = (MenuItemFrame_t)Menu_SubMenu_Frame; + menu->super.Draw = (MenuItemDraw_t)Menu_SubMenu_Draw; + menu->super.KeyEvent = (MenuItemKeyEvent_t)Menu_SubMenu_KeyEvent; + menu->super.Destroy = (MenuItemDestroy_t)Menu_SubMenu_Destroy; menu->allowclose = true; @@ -1185,8 +1185,8 @@ // init the root menu // FIXME: create the rootmenu using the normal submenu creation function instead? - Menu.rootmenu.super.Frame = Menu_SubMenu_Frame; - Menu.rootmenu.super.MouseMove = Menu_SubMenu_MouseMove; - Menu.rootmenu.super.Draw = Menu_SubMenu_Draw; - Menu.rootmenu.super.KeyEvent = Menu_SubMenu_KeyEvent; + Menu.rootmenu.super.Frame = (MenuItemFrame_t)Menu_SubMenu_Frame; + Menu.rootmenu.super.MouseMove = (MenuItemMouseMove_t)Menu_SubMenu_MouseMove; + Menu.rootmenu.super.Draw = (MenuItemDraw_t)Menu_SubMenu_Draw; + Menu.rootmenu.super.KeyEvent = (MenuItemKeyEvent_t)Menu_SubMenu_KeyEvent; } Modified: trunk/game/m_menucore.h =================================================================== --- trunk/game/m_menucore.h 2006-05-05 19:09:19 UTC (rev 705) +++ trunk/game/m_menucore.h 2006-05-05 19:28:49 UTC (rev 706) @@ -30,6 +30,12 @@ } Menu_ItemType; +typedef void (*MenuItemFrame_t)(void *, Menu_Inheritance *, Ndouble); +typedef void (*MenuItemDraw_t)(void *, Menu_Inheritance *); +typedef Nbool (*MenuItemKeyEvent_t)(void *, NUint, NUint, NUint, Nbool); +typedef void (*MenuItemMouseMove_t)(void *, Menu_Inheritance *); +typedef void (*MenuItemDestroy_t)(void *); + typedef struct Menu_Item { // pass an elapsedtime parameter to make animation-speed changes, etc. possible From painquin at icculus.org Fri May 5 17:32:26 2006 From: painquin at icculus.org (painquin at icculus.org) Date: 5 May 2006 17:32:26 -0400 Subject: r707 - trunk Message-ID: <20060505213226.9503.qmail@icculus.org> Author: painquin Date: 2006-05-05 17:32:26 -0400 (Fri, 05 May 2006) New Revision: 707 Modified: trunk/cvar.c Log: added a check in Cvar_Find to ensure the Cvar Manager is running Modified: trunk/cvar.c =================================================================== --- trunk/cvar.c 2006-05-05 19:28:49 UTC (rev 706) +++ trunk/cvar.c 2006-05-05 21:32:26 UTC (rev 707) @@ -37,13 +37,16 @@ static Shell_SymbolDecl Cvar_Shell_Get_Decl; -//TODO: add checks for .active! static inline Cvar * Cvar_Find( const char *cvarName ) { Cvar *cvar; Hash_Data search; + if( !CvarManager.active ) { + Console_Warning( "The Cvar system has not been initialized!\n" ); + return NULL; + } search.name = cvarName; search.name_len = String_Length (cvarName); From lordhavoc at icculus.org Fri May 5 17:50:55 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 5 May 2006 17:50:55 -0400 Subject: r708 - trunk/game Message-ID: <20060505215055.12561.qmail@icculus.org> Author: lordhavoc Date: 2006-05-05 17:50:55 -0400 (Fri, 05 May 2006) New Revision: 708 Modified: trunk/game/g_entity.c Log: reworked G_Entity_New some more to fix a horrible crash and added more comments Modified: trunk/game/g_entity.c =================================================================== --- trunk/game/g_entity.c 2006-05-05 21:32:26 UTC (rev 707) +++ trunk/game/g_entity.c 2006-05-05 21:50:55 UTC (rev 708) @@ -8,9 +8,8 @@ G_Entity *G_Entity_New(G_Entity *parent, const G_Entity_Class *eclass, const G_Entity_Position *position) { G_Entity *entity; - Nbool bestfound = false; - Nvec tbest = 0; - NUint32 childindex = 0, bestindex = 0; + Nvec tbest; + NUint32 childindex = 0, bestindex, index; if (!eclass) return NULL; if (!eclass->codeclass->name) @@ -36,35 +35,45 @@ if (!position) position = &GS.identityposition; - for (entity = G.entities + G.allocentity;G.allocentity < G_MAX_ENTITIES;G.allocentity++, entity++) + // search for the first available entity slot in an optimized manner. + // G.allocentity tracks the first known gap in the G.entities array, it is + // incremented until a gap is found, and reset when an entity is freed + while (G.allocentity < G_MAX_ENTITIES && G.entities[G.allocentity].eclass) + G.allocentity++; + // if we couldn't find any at all, return NULL + if (G.allocentity >= G_MAX_ENTITIES) { + Console_Printf("Ran out of entities (%i)\n", G_MAX_ENTITIES); + return NULL; + } + // now we know we're sitting at a valid free slot, but we want to choose + // one that hasn't been freed recently as there may still be references + // pointing to it (usually they will be cleared a moment later) + bestindex = G.allocentity; + tbest = G.entities[bestindex].freetime; + for (index = G.allocentity + 1, entity = G.entities + index;index < G_MAX_ENTITIES;index++, entity++) + { if (!entity->eclass) { - if (G.time - entity->freetime >= FREETIMEOUT) + if (entity->freetime == 0 || G.time - entity->freetime >= FREETIMEOUT) { // this entity has not been used recently, so anything // referencing it has probably cleared its references already, // so it is probably safe to reuse it now - bestfound = true; - bestindex = G.allocentity++; + bestindex = index; + tbest = entity->freetime; break; } - else if (!bestfound || (entity->freetime < tbest)) + else if (entity->freetime < tbest) { // found a free slot that hasn't timed out yet, keep track of - // which one is oldest incase we can't find one + // which one is oldest incase we can't find any safe ones // (this is a dangerous situation but it's even worse to fail) - bestfound = true; - bestindex = G.allocentity; + bestindex = index; tbest = entity->freetime; } } } - if (!bestfound) - { - Console_Printf("Ran out of entities (%i)\n", G_MAX_ENTITIES); - return NULL; - } entity = G.entities + bestindex; // update entity range to include this newly allocated entity // (the entity range is used to avoid processing the entire array each From painquin at icculus.org Sun May 7 23:25:24 2006 From: painquin at icculus.org (painquin at icculus.org) Date: 7 May 2006 23:25:24 -0400 Subject: r709 - trunk/game Message-ID: <20060508032524.12773.qmail@icculus.org> Author: painquin Date: 2006-05-07 23:25:23 -0400 (Sun, 07 May 2006) New Revision: 709 Modified: trunk/game/m_menucore.c trunk/game/m_menucore.h Log: menu revisions, Reworked the main menu (not a placeholder anymore), Added a BigText item for menu headings and such, Added menu padding (defaults to 2, menu->padding[axis] = n to change) Modified: trunk/game/m_menucore.c =================================================================== --- trunk/game/m_menucore.c 2006-05-05 21:50:55 UTC (rev 708) +++ trunk/game/m_menucore.c 2006-05-08 03:25:23 UTC (rev 709) @@ -225,12 +225,18 @@ { R_SetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_SetTexture(R.resource_font); - R_DrawString(item->text, 0, item->super.pos[0] + inh->origin[0], item->super.pos[1] + inh->origin[1], 8, 8, Console_DefaultColorTable, Console_DefaultColorTableSize, item->super.parent->selecteditem == &item->super); + R_DrawString(item->text, 0, item->super.pos[0] + inh->origin[0], item->super.pos[1] + inh->origin[1], item->super.size[1], item->super.size[1], Console_DefaultColorTable, Console_DefaultColorTableSize, item->super.parent->selecteditem == &item->super); + /* Notice: this uses the height of the text to determine the scale (for height and width) + * if this is not right, we need an alternative way to track the scaling factor and size. + */ } + + void Menu_Text_DefaultUse (struct Menu_TextItem *item, void *cookie) { Shell_ExecuteScript("menu text use", cookie); } + Nbool Menu_Text_KeyPress (Menu_TextItem *item, UNUSED NUint mod, NUint sym, UNUSED NUint character, Nbool downevent) { if (sym == SDLK_RETURN || sym == MOUSE1) @@ -267,9 +273,40 @@ return it; } +Menu_TextItem *Menu_BigText_Create(Menu_SubMenu *parent, NSint x, NSint y, char *text, void *cookie, void (*UseItem) (struct Menu_TextItem *item, void *cookie)) +{ + Menu_TextItem *it; + it = Menu_Text_Create(parent, x, y, text, cookie, UseItem); + it->super.size[0] *= 2; + it->super.size[1] *= 2; + /* Todo: Alternate scaling factors? */ + + return it; +} + + +/* + * Menu Padding + */ +void Menu_Pad_Draw(Menu_PadItem *item, Menu_Inheritance *inh) +{ + return; +} + +Menu_PadItem *Menu_Pad_Create(Menu_SubMenu *parent, NSint padx, NSint pady) +{ + Menu_PadItem *it = (Menu_PadItem*)Menu_Generic_Create(parent, MENU_ITEMTYPE_PAD, 0, 0, sizeof(Menu_PadItem)); + + it->super.Draw = (MenuItemDraw_t)Menu_Pad_Draw; + it->super.size[0] = padx; + it->super.size[1] = pady; + return it; +} + + //text-edit fields //fixme: only work with grabs? void Menu_Edit_Draw(Menu_EditItem *item, Menu_Inheritance *inh) @@ -884,6 +921,8 @@ menu->super.Destroy = (MenuItemDestroy_t)Menu_SubMenu_Destroy; menu->allowclose = true; + menu->padding[1] = 2; + /* default spacing of 2 pixels - I think this helps readability significantly -quin */ return menu; } @@ -942,13 +981,13 @@ for (sitem = menu->subitems; sitem; sitem = sitem->next) { sitem->pos[axis] = maxval; - maxval += sitem->size[axis] + pad; + maxval += sitem->size[axis] + pad + menu->padding[axis]; } + val = maxval; - val = maxval; for (sitem = menu->subitems; sitem; sitem = sitem->next) { - val -= sitem->size[axis] + pad; + val -= sitem->size[axis] + pad + menu->padding[axis]; sitem->pos[axis] = val; switch(arrange) @@ -1052,6 +1091,8 @@ Menu_SubMenu *menu = cookie; it->value = menu->subwindow.pos[1]; } + +#if 0 void Menu_Menu_Test(void) { //fixme: we still need to figure out how to do the parent's frames, so the subwindow doesn't appear outside the parent @@ -1090,30 +1131,39 @@ (Shell_Symbol_Callback) Menu_Menu_Test }; +#endif +/* Menu_Text_Create(menu, 0, 16, "Hello World", "echo Hello World\n", NULL); + Menu_Text_Create(menu, 0, 24, "Start up test map", "map test\n", NULL); + Menu_Text_Create(menu, 0, 32, "Go to the west!", "map west\n", NULL);*/ + /* + Menu_Text_Create(menu, 0, 56+16, "test menu", "menu_test\n", NULL); + Menu_Edit_Create(menu, 0, 56, "EditItem"); + Menu_Combo_Create(menu, 0, 56, 21*8, "ComboItem", "Option 1|Option 2|Option 3|Fuzzy Little Bunnies|Big Rocket Launcher|Children|Lightning Gun|Newborn Chicks|Grenade Launcher|Rodents|Nukes"); +*/ +#define IHEIGHT 160 + void Menu_Main(void) { Menu_SubMenu *menu = Menu_SubMenu_Create(&Menu.rootmenu); menu->dragable = true; + - Menu_Text_Create(menu, 0, 0, "Main menu", NULL, NULL); + Menu_BigText_Create(menu, 0, 0, "DarkWar", NULL, NULL); // TODO: replace this with a graphic -quin + Menu_Pad_Create(menu, 0, 8); - Menu_Text_Create(menu, 0, 16, "Hello World", "echo Hello World\n", NULL); - Menu_Text_Create(menu, 0, 24, "Start up test map", "map test\n", NULL); - Menu_Text_Create(menu, 0, 32, "Go to the west!", "map west\n", NULL); - Menu_Text_Create(menu, 0, 40, "quit", "menu_quit\n", NULL); + Menu_Text_Create(menu, 0, 0, "Singleplayer", NULL, NULL); - Menu_Text_Create(menu, 0, 56, "Close menu", "menu_close\n", NULL); + Menu_Text_Create(menu, 0, 0, "Multiplayer", "menu_multiplayer", NULL); - Menu_Text_Create(menu, 0, 56+16, "test menu", "menu_test\n", NULL); - - Menu_Edit_Create(menu, 0, 56, "EditItem"); - Menu_Combo_Create(menu, 0, 56, 21*8, "ComboItem", "Option 1|Option 2|Option 3|Fuzzy Little Bunnies|Big Rocket Launcher|Children|Lightning Gun|Newborn Chicks|Grenade Launcher|Rodents|Nukes"); - + Menu_Text_Create(menu, 0, 0, "Options", NULL, NULL); + + Menu_Text_Create(menu, 0, 0, "Exit DarkWar", "quit", NULL); + Menu_SubMenu_Finish(menu); Menu_SubMenu_Arrange(menu, false, 0, MENU_ARRANGESTYLE_CENTER); Menu_SubMenu_Finish(menu); @@ -1146,41 +1196,12 @@ (Shell_Symbol_Callback) Menu_CloseMenu }; - - -//The simple quit menu -void Menu_Menu_Quit(void) -{ - Menu_SubMenu *menu = Menu_SubMenu_Create(&Menu.rootmenu); - menu->dragable = true; - - Menu_Text_Create(menu, 0, 0, "Really Quit?", NULL, NULL); - - Menu_Text_Create(menu, 0, 16, "Yes, and wipe my harddrive too.", "quit\n", NULL); - Menu_Text_Create(menu, 0, 24, "No. I want to keep playing this awesome game", "menu_close\n", NULL); - - Menu_SubMenu_Finish(menu); - - Menu_Picture_Create(menu, 0, 0, menu->super.size[0], menu->super.size[1], "maps/test/skybox_ny.tga", NULL, NULL); - - Menu_MoveToCenter(menu); -} -static Shell_SymbolDecl Menu_Menu_Quit_Decl = { - "menu_quit", - "asks the user if they want to quit, in a polite way.", - "usage: menu_quit", - "", - (Shell_Symbol_Callback) Menu_Menu_Quit -}; - - void Menu_Init(void) { Menu.menu_zone = Mem_AllocZone ("MenuZone", NULL, 0); Shell_Register(&Menu_Menu_Main_Decl, NULL); - Shell_Register(&Menu_Menu_Test_Decl, NULL); - Shell_Register(&Menu_Menu_Quit_Decl, NULL); + //Shell_Register(&Menu_Menu_Test_Decl, NULL); Shell_Register(&Menu_Menu_Close_Decl, NULL); // init the root menu Modified: trunk/game/m_menucore.h =================================================================== --- trunk/game/m_menucore.h 2006-05-05 21:50:55 UTC (rev 708) +++ trunk/game/m_menucore.h 2006-05-08 03:25:23 UTC (rev 709) @@ -27,6 +27,7 @@ MENU_ITEMTYPE_COMBO, MENU_ITEMTYPE_TEXT, MENU_ITEMTYPE_PICTURE, + MENU_ITEMTYPE_PAD } Menu_ItemType; @@ -68,6 +69,7 @@ struct Menu_Item *selecteditem; struct Menu_Item *subitems; + NSint padding[2]; } Menu_SubMenu; @@ -85,6 +87,13 @@ } Menu_TextItem; + +typedef struct Menu_PadItem +{ + Menu_Item super; +} +Menu_PadItem; + typedef struct Menu_EditItem { Menu_Item super; From painquin at icculus.org Mon May 8 09:32:57 2006 From: painquin at icculus.org (painquin at icculus.org) Date: 8 May 2006 09:32:57 -0400 Subject: r710 - trunk Message-ID: <20060508133257.1630.qmail@icculus.org> Author: painquin Date: 2006-05-08 09:32:57 -0400 (Mon, 08 May 2006) New Revision: 710 Modified: trunk/darkwar-net2003.vcproj Log: Added modelanim.c/h to the vcproj file Modified: trunk/darkwar-net2003.vcproj =================================================================== --- trunk/darkwar-net2003.vcproj 2006-05-08 03:25:23 UTC (rev 709) +++ trunk/darkwar-net2003.vcproj 2006-05-08 13:32:57 UTC (rev 710) @@ -481,6 +481,12 @@ RelativePath=".\model.h"> + + + + Author: painquin Date: 2006-05-08 13:47:12 -0400 (Mon, 08 May 2006) New Revision: 711 Added: trunk/base/menu/ trunk/base/menu/main_logo.tga Log: menu graphics - main logo Added: trunk/base/menu/main_logo.tga =================================================================== (Binary files differ) Property changes on: trunk/base/menu/main_logo.tga ___________________________________________________________________ Name: svn:mime-type + application/octet-stream From painquin at icculus.org Mon May 8 19:19:48 2006 From: painquin at icculus.org (painquin at icculus.org) Date: 8 May 2006 19:19:48 -0400 Subject: r712 - in trunk: . game Message-ID: <20060508231948.29750.qmail@icculus.org> Author: painquin Date: 2006-05-08 19:19:48 -0400 (Mon, 08 May 2006) New Revision: 712 Modified: trunk/darkwar-net2003.vcproj trunk/game/m_menucore.c trunk/game/m_menucore.h Log: more work on the visual aspect of the menus, please give feedback this update includes margins for padding menu size this is useful mostly when creating background images also m_menucore.h was missing from the vcproj Modified: trunk/darkwar-net2003.vcproj =================================================================== --- trunk/darkwar-net2003.vcproj 2006-05-08 17:47:12 UTC (rev 711) +++ trunk/darkwar-net2003.vcproj 2006-05-08 23:19:48 UTC (rev 712) @@ -286,6 +286,9 @@ RelativePath=".\game\m_menucore.c"> + + super.MouseMove = (MenuItemMouseMove_t)Menu_Generic_MouseMoveSelectable; it->super.KeyEvent = (MenuItemKeyEvent_t)Menu_Text_KeyPress; } - it->super.size[0] = 8*strlen(text); - it->super.size[1] = 8; + it->super.size[0] = 16*strlen(text); + it->super.size[1] = 16; it->text = text; it->cookie = cookie; @@ -306,7 +306,14 @@ return it; } +void Menu_CloseOnUse(struct Menu_TextItem *item, void *cookie) +{ + Shell_ExecuteScript("menu text use", cookie); + Menu_Item_RemoveFromParent(&item->super.parent->super); + item->super.parent->super.Destroy(item->super.parent); +} + //text-edit fields //fixme: only work with grabs? void Menu_Edit_Draw(Menu_EditItem *item, Menu_Inheritance *inh) @@ -832,6 +839,8 @@ R_SetScissor(inh->window.pos[0], inh->window.pos[1], inh->window.size[0], inh->window.size[1]); } + + Nbool Menu_SubMenu_KeyEvent (Menu_SubMenu *item, NUint mod, NUint sym, NUint character, Nbool downevent) { Menu_Item *subitem; @@ -923,6 +932,8 @@ menu->allowclose = true; menu->padding[1] = 2; /* default spacing of 2 pixels - I think this helps readability significantly -quin */ + menu->margin[0] = 4; + menu->margin[1] = 4; return menu; } @@ -954,11 +965,11 @@ minpos[1] = subitem->pos[1]; } - menu->super.size[0] = maxpos[0]; - menu->super.size[1] = maxpos[1]; + menu->super.size[0] = maxpos[0] + menu->margin[0]; + menu->super.size[1] = maxpos[1] + menu->margin[1]; - menu->subwindow.size[0] = maxpos[0] - minpos[0]; - menu->subwindow.size[1] = maxpos[1] - minpos[1]; + menu->subwindow.size[0] = maxpos[0] - minpos[0] + menu->margin[0] * 2; + menu->subwindow.size[1] = maxpos[1] - minpos[1] + menu->margin[1] * 2; } void Menu_SubMenu_Arrange(Menu_SubMenu *menu, Nbool horizontal, NSint pad, Menu_ArrangeStyle arrange) @@ -966,18 +977,14 @@ Menu_Item *sitem; NSint axis, otheraxis; NSint val = 0; - NSint maxval = 0; + NSint maxval = menu->margin[horizontal]; //axis is usually the 'vertical' axis, where each field is spaced with padding //otheraxis is the axis on which we align stuff (rather than just space it) - if (horizontal) - axis = 0; - else - axis = 1; + otheraxis = horizontal; + axis = !otheraxis; - otheraxis = !axis; - for (sitem = menu->subitems; sitem; sitem = sitem->next) { sitem->pos[axis] = maxval; @@ -996,15 +1003,16 @@ break; case MENU_ARRANGESTYLE_LEFT: - sitem->pos[otheraxis] = 0; + sitem->pos[otheraxis] = menu->margin[otheraxis]; break; case MENU_ARRANGESTYLE_CENTER: - sitem->pos[otheraxis] = (menu->subwindow.size[otheraxis] - sitem->size[otheraxis])/2; + sitem->pos[otheraxis] = ((menu->subwindow.size[otheraxis] - menu->margin[otheraxis]*2) + - sitem->size[otheraxis])/2 + menu->margin[otheraxis]; break; case MENU_ARRANGESTYLE_RIGHT: - sitem->pos[otheraxis] = (menu->subwindow.size[otheraxis] - sitem->size[otheraxis]); + sitem->pos[otheraxis] = (menu->subwindow.size[otheraxis] - (sitem->size[otheraxis] + menu->margin[otheraxis])); break; case MENU_ARRANGESTYLE_RESIZE: @@ -1055,17 +1063,6 @@ - - - - - - - - - - - Nfloat sliderscale = 8; Nfloat imagesize = 512; Nfloat windowsize = 128; @@ -1145,29 +1142,52 @@ Menu_Edit_Create(menu, 0, 56, "EditItem"); Menu_Combo_Create(menu, 0, 56, 21*8, "ComboItem", "Option 1|Option 2|Option 3|Fuzzy Little Bunnies|Big Rocket Launcher|Children|Lightning Gun|Newborn Chicks|Grenade Launcher|Rodents|Nukes"); */ -#define IHEIGHT 160 +void Menu_Multiplayer(Menu_TextItem *item, void *cookie) +{ + Menu_SubMenu *menu = Menu_SubMenu_Create(&Menu.rootmenu); + Menu_SubMenu_Destroy(item->super.parent); + menu->padding[0] = menu->padding[1] = 4; + menu->margin[0] = menu->margin[1] = 15; + Menu_BigText_Create(menu, 0, 0, "Multiplayer", NULL, NULL); + Menu_Pad_Create(menu, 0, 6); + + Menu_Text_Create(menu, 0, 0, "Join a Game", "map west", Menu_CloseOnUse); //Menu_ServerBrowser); + Menu_Text_Create(menu, 0, 0, "Start a Server", "map test", Menu_CloseOnUse); + Menu_Text_Create(menu, 0, 0, "Multiplayer Settings", NULL, NULL); //Menu_MPSettings); + Menu_Text_Create(menu, 0, 0, "Back", "menu_main", Menu_CloseOnUse); + + Menu_SubMenu_Finish(menu); + Menu_SubMenu_Arrange(menu, false, 0, MENU_ARRANGESTYLE_CENTER); + Menu_SubMenu_Finish(menu); +// Menu_Picture_Create(menu, 0, 0, menu->super.size[0], menu->super.size[1], "maps/test/skybox_ny.tga", NULL, NULL); + + Menu_MoveToCenter(menu); + +} + void Menu_Main(void) { Menu_SubMenu *menu = Menu_SubMenu_Create(&Menu.rootmenu); - menu->dragable = true; - + menu->padding[0] = menu->padding[1] = 4; + menu->margin[0] = menu->margin[1] = 15; - Menu_BigText_Create(menu, 0, 0, "DarkWar", NULL, NULL); // TODO: replace this with a graphic -quin - Menu_Pad_Create(menu, 0, 8); + Menu_Picture_Create(menu, 0, 0, 138, 81, "menu/main_logo.tga", NULL, NULL); + Menu_Pad_Create(menu, 0, 6); Menu_Text_Create(menu, 0, 0, "Singleplayer", NULL, NULL); - Menu_Text_Create(menu, 0, 0, "Multiplayer", "menu_multiplayer", NULL); + Menu_Text_Create(menu, 0, 0, "Multiplayer", "", Menu_Multiplayer); Menu_Text_Create(menu, 0, 0, "Options", NULL, NULL); + Menu_Pad_Create(menu, 0, 8); Menu_Text_Create(menu, 0, 0, "Exit DarkWar", "quit", NULL); Menu_SubMenu_Finish(menu); Menu_SubMenu_Arrange(menu, false, 0, MENU_ARRANGESTYLE_CENTER); Menu_SubMenu_Finish(menu); - Menu_Picture_Create(menu, 0, 0, menu->super.size[0], menu->super.size[1], "maps/test/skybox_ny.tga", NULL, NULL); +// Menu_Picture_Create(menu, 0, 0, menu->super.size[0], menu->super.size[1], "maps/test/skybox_ny.tga", NULL, NULL); Menu_MoveToCenter(menu); } Modified: trunk/game/m_menucore.h =================================================================== --- trunk/game/m_menucore.h 2006-05-08 17:47:12 UTC (rev 711) +++ trunk/game/m_menucore.h 2006-05-08 23:19:48 UTC (rev 712) @@ -70,6 +70,7 @@ struct Menu_Item *selecteditem; struct Menu_Item *subitems; NSint padding[2]; + NSint margin[2]; } Menu_SubMenu; From painquin at icculus.org Tue May 9 16:05:18 2006 From: painquin at icculus.org (painquin at icculus.org) Date: 9 May 2006 16:05:18 -0400 Subject: r713 - in trunk: base/menu game Message-ID: <20060509200518.19524.qmail@icculus.org> Author: painquin Date: 2006-05-09 16:05:18 -0400 (Tue, 09 May 2006) New Revision: 713 Added: trunk/base/menu/ll.tga trunk/base/menu/lr.tga trunk/base/menu/ul.tga trunk/base/menu/ur.tga Modified: trunk/game/m_menucore.c Log: more menu graphics - someone with art skills please replace Added: trunk/base/menu/ll.tga =================================================================== (Binary files differ) Property changes on: trunk/base/menu/ll.tga ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/base/menu/lr.tga =================================================================== (Binary files differ) Property changes on: trunk/base/menu/lr.tga ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/base/menu/ul.tga =================================================================== (Binary files differ) Property changes on: trunk/base/menu/ul.tga ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/base/menu/ur.tga =================================================================== (Binary files differ) Property changes on: trunk/base/menu/ur.tga ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Modified: trunk/game/m_menucore.c =================================================================== --- trunk/game/m_menucore.c 2006-05-08 23:19:48 UTC (rev 712) +++ trunk/game/m_menucore.c 2006-05-09 20:05:18 UTC (rev 713) @@ -1142,6 +1142,10 @@ Menu_Edit_Create(menu, 0, 56, "EditItem"); Menu_Combo_Create(menu, 0, 56, 21*8, "ComboItem", "Option 1|Option 2|Option 3|Fuzzy Little Bunnies|Big Rocket Launcher|Children|Lightning Gun|Newborn Chicks|Grenade Launcher|Rodents|Nukes"); */ + +#define MSIZE 50 + + void Menu_Multiplayer(Menu_TextItem *item, void *cookie) { Menu_SubMenu *menu = Menu_SubMenu_Create(&Menu.rootmenu); @@ -1155,12 +1159,17 @@ Menu_Text_Create(menu, 0, 0, "Join a Game", "map west", Menu_CloseOnUse); //Menu_ServerBrowser); Menu_Text_Create(menu, 0, 0, "Start a Server", "map test", Menu_CloseOnUse); Menu_Text_Create(menu, 0, 0, "Multiplayer Settings", NULL, NULL); //Menu_MPSettings); + Menu_Pad_Create(menu, 0, 6); Menu_Text_Create(menu, 0, 0, "Back", "menu_main", Menu_CloseOnUse); Menu_SubMenu_Finish(menu); Menu_SubMenu_Arrange(menu, false, 0, MENU_ARRANGESTYLE_CENTER); Menu_SubMenu_Finish(menu); // Menu_Picture_Create(menu, 0, 0, menu->super.size[0], menu->super.size[1], "maps/test/skybox_ny.tga", NULL, NULL); + Menu_Picture_Create(menu, 0, 0, MSIZE, MSIZE, "menu/ul.tga", NULL, NULL); + Menu_Picture_Create(menu, menu->super.size[0] - MSIZE, 0, MSIZE, MSIZE, "menu/ur.tga", NULL, NULL); + Menu_Picture_Create(menu, menu->super.size[0] - MSIZE, menu->super.size[1] - MSIZE, MSIZE, MSIZE, "menu/lr.tga", NULL, NULL); + Menu_Picture_Create(menu, 0, menu->super.size[1] - MSIZE, MSIZE, MSIZE, "menu/ll.tga", NULL, NULL); Menu_MoveToCenter(menu); @@ -1170,7 +1179,7 @@ { Menu_SubMenu *menu = Menu_SubMenu_Create(&Menu.rootmenu); menu->padding[0] = menu->padding[1] = 4; - menu->margin[0] = menu->margin[1] = 15; + menu->margin[0] = menu->margin[1] = 25; Menu_Picture_Create(menu, 0, 0, 138, 81, "menu/main_logo.tga", NULL, NULL); Menu_Pad_Create(menu, 0, 6); @@ -1187,6 +1196,12 @@ Menu_SubMenu_Finish(menu); Menu_SubMenu_Arrange(menu, false, 0, MENU_ARRANGESTYLE_CENTER); Menu_SubMenu_Finish(menu); + + Menu_Picture_Create(menu, 0, 0, MSIZE, MSIZE, "menu/ul.tga", NULL, NULL); + Menu_Picture_Create(menu, menu->super.size[0] - MSIZE, 0, MSIZE, MSIZE, "menu/ur.tga", NULL, NULL); + Menu_Picture_Create(menu, menu->super.size[0] - MSIZE, menu->super.size[1] - MSIZE, MSIZE, MSIZE, "menu/lr.tga", NULL, NULL); + Menu_Picture_Create(menu, 0, menu->super.size[1] - MSIZE, MSIZE, MSIZE, "menu/ll.tga", NULL, NULL); + // Menu_Picture_Create(menu, 0, 0, menu->super.size[0], menu->super.size[1], "maps/test/skybox_ny.tga", NULL, NULL); Menu_MoveToCenter(menu); From lordhavoc at icculus.org Fri May 12 04:36:48 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 12 May 2006 04:36:48 -0400 Subject: r714 - in trunk: . base/shaders Message-ID: <20060512083648.5869.qmail@icculus.org> Author: lordhavoc Date: 2006-05-12 04:36:47 -0400 (Fri, 12 May 2006) New Revision: 714 Modified: trunk/base/shaders/light.vert trunk/model.c trunk/model.h trunk/util.c trunk/util.h Log: migrated Util_BuildModel code into Model_Build namespace and it now uses the Model struct Modified: trunk/base/shaders/light.vert =================================================================== --- trunk/base/shaders/light.vert 2006-05-09 20:05:18 UTC (rev 713) +++ trunk/base/shaders/light.vert 2006-05-12 08:36:47 UTC (rev 714) @@ -30,14 +30,14 @@ vec3 lightminusvertex = LightPosition - gl_Vertex.xyz; LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz); LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz); - LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz); + LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz); #if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING) // transform unnormalized eye direction into tangent space vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz; EyeVector.x = dot(eyeminusvertex, gl_MultiTexCoord1.xyz); EyeVector.y = dot(eyeminusvertex, gl_MultiTexCoord2.xyz); - EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz); + EyeVector.z = dot(eyeminusvertex, gl_MultiTexCoord3.xyz); #endif // transform vertex to camera space, using ftransform to match non-VS Modified: trunk/model.c =================================================================== --- trunk/model.c 2006-05-09 20:05:18 UTC (rev 713) +++ trunk/model.c 2006-05-12 08:36:47 UTC (rev 714) @@ -22,21 +22,37 @@ } } -// build vectors (along S, T, and Normal) for a triangle -static void Model_TriangleVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f) +// build smoothed normals for all vertices of a mesh +static void Model_MeshNormals(NUint32 numtriangles, const NUint32 *element3i, NUint32 numvertices, const float *vertex3f, const float *texcoord2f, float *normal3f) { - float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2]; - // 103 add/sub/negate/multiply (1 cycle), 3 divide (20 cycle), 3 sqrt (22 cycle), 4 compare (3 cycle?), total cycles not counting load/store/exchange roughly 241 cycles - // 12 add, 28 subtract, 57 multiply, 3 divide, 3 sqrt, 4 compare, 50% chance of 6 negates + NUint32 i, j; + float normal[3]; + // clear the output array + memset(normal3f, 0, numvertices * sizeof(float[3])); + // iterate the triangles + for (i = 0;i < numtriangles;i++) + { + TriangleNormal(vertex3f + element3i[i*3+0]*3, vertex3f + element3i[i*3+1]*3, vertex3f + element3i[i*3+2]*3, normal); + // accumulate normals + for (j = 0;j < 3;j++) + VectorAdd(normal3f + element3i[i*3+j]*3, normal, normal3f + element3i[i*3+j]*3); + } + // normalize the results + for (i = 0;i < numvertices;i++) + VectorNormalize(normal3f + i * 3); +} +// build tangent vectors (vectors along S, T texcoords) for a triangle +static void Model_TangentVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f) +{ + float tangentcross[3], v10[3], v20[3], tc10[2], tc20[2], normal3f[3]; + // 6 multiply, 9 subtract VectorSubtract(v1, v0, v10); VectorSubtract(v2, v0, v20); normal3f[0] = v20[1] * v10[2] - v10[1] * v20[2]; normal3f[1] = v20[2] * v10[0] - v10[2] * v20[0]; normal3f[2] = v20[0] * v10[1] - v10[0] * v20[1]; - // 1 sqrt, 1 divide, 6 multiply, 2 add, 1 compare - VectorNormalize(normal3f); // 12 multiply, 10 subtract tc10[1] = tc1[1] - tc0[1]; tc20[1] = tc2[1] - tc0[1]; @@ -48,18 +64,6 @@ tvector3f[0] = v20[0] * tc10[0] - v10[0] * tc20[0]; tvector3f[1] = v20[1] * tc10[0] - v10[1] * tc20[0]; tvector3f[2] = v20[2] * tc10[0] - v10[2] * tc20[0]; - // 12 multiply, 4 add, 6 subtract - f = DotProduct(svector3f, normal3f); - svector3f[0] -= f * normal3f[0]; - svector3f[1] -= f * normal3f[1]; - svector3f[2] -= f * normal3f[2]; - f = DotProduct(tvector3f, normal3f); - tvector3f[0] -= f * normal3f[0]; - tvector3f[1] -= f * normal3f[1]; - tvector3f[2] -= f * normal3f[2]; - // 2 sqrt, 2 divide, 12 multiply, 4 add, 2 compare - VectorNormalize(svector3f); - VectorNormalize(tvector3f); // if texture is mapped the wrong way (counterclockwise), the tangents // have to be flipped, this is detected by calculating a normal from the // two tangents, and seeing if it is opposite the surface normal @@ -73,39 +77,48 @@ } // build smoothed vectors (along S, T, and Normal) for all vertices of a mesh -static void Model_MeshVectors(NUint32 numtriangles, const NUint32 *element3i, NUint32 numvertices, const float *vertex3f, const float *texcoord2f, float *svector3f, float *tvector3f, float *normal3f) +static void Model_MeshTangents(NUint32 numtriangles, const NUint32 *element3i, NUint32 numvertices, const float *vertex3f, const float *texcoord2f, float *normal3f, float *svector3f, float *tvector3f) { NUint32 i, j; - float svector[3], tvector[3], normal[3]; // this calculates a set of vectors per triangle and blends them onto the // triangle's vertices, if triangle share vertices (continuous mesh) this // smooths them, if they are not shared then this looks facetted. // - // a possibly more intelligent scheme would be to smooth vectors on all - // vertices at the same position that share similar vectors, but that - // takes longer and may still yield artifacts on texcoord seams + // a possibly more intelligent scheme would be to smooth normals on all + // vertices at the same position that share similar normals, but that + // takes longer and is difficult if they belong to different meshes // clear the output arrays memset(svector3f, 0, numvertices * sizeof(float[3])); memset(tvector3f, 0, numvertices * sizeof(float[3])); - memset(normal3f, 0, numvertices * sizeof(float[3])); // iterate the triangles for (i = 0;i < numtriangles;i++) { - Model_TriangleVectors(vertex3f + element3i[i*3+0] * 3, vertex3f + element3i[i*3+1] * 3, vertex3f + element3i[i*3+2] * 3, texcoord2f + element3i[i*3+0] * 2, texcoord2f + element3i[i*3+1] * 2, texcoord2f + element3i[i*3+2] * 2, svector, tvector, normal); + float svector[3], tvector[3]; + Model_TangentVectors(vertex3f + element3i[i*3+0] * 3, vertex3f + element3i[i*3+1] * 3, vertex3f + element3i[i*3+2] * 3, texcoord2f + element3i[i*3+0] * 2, texcoord2f + element3i[i*3+1] * 2, texcoord2f + element3i[i*3+2] * 2, svector, tvector); // accumulate vectors onto vertices for (j = 0;j < 3;j++) { VectorAdd(svector3f + element3i[i*3+j]*3, svector, svector3f + element3i[i*3+j]*3); VectorAdd(tvector3f + element3i[i*3+j]*3, tvector, tvector3f + element3i[i*3+j]*3); - VectorAdd(normal3f + element3i[i*3+j]*3, normal, normal3f + element3i[i*3+j]*3); } } - // normalize the results - for (i = 0;i < numvertices;i++) + // project tangents onto planes and normalize the results + for (i = 0;i < numvertices;i++, svector3f += 3, tvector3f += 3, normal3f += 3) { - VectorNormalize(svector3f + i * 3); - VectorNormalize(tvector3f + i * 3); - VectorNormalize(normal3f + i * 3); + // project tangents onto plane defined by normal + // (makes sure they are perpendicular to the normal) + float f; + f = DotProduct(svector3f, normal3f); + svector3f[0] -= f * normal3f[0]; + svector3f[1] -= f * normal3f[1]; + svector3f[2] -= f * normal3f[2]; + f = DotProduct(tvector3f, normal3f); + tvector3f[0] -= f * normal3f[0]; + tvector3f[1] -= f * normal3f[1]; + tvector3f[2] -= f * normal3f[2]; + // normalize the tangents + VectorNormalize(svector3f); + VectorNormalize(tvector3f); } } @@ -175,6 +188,563 @@ Mem_Free(&hashtable); } +void Model_Build_Begin(Model *b, Mem_Zone *memzone, Nbool isskeletal) +{ + memset(b, 0, sizeof(*b)); + b->memzone = memzone; + b->isskeletal = isskeletal; +} + +static void Model_Build_GenerateNeighbors(Model_Mesh *mesh) +{ + Model_MeshNeighbors(mesh->num_triangles, mesh->data_element3i, mesh->data_neighbor3i, mesh->num_vertices); +} + +static void Model_Build_GeneratePlanes(Model_Mesh *mesh) +{ + Model_BuildTrianglePlanes(mesh->data_vertex3f, mesh->num_triangles, mesh->data_element3i, mesh->data_plane4f); +} + +static void Model_Build_GenerateNormals(Model_Mesh *mesh) +{ + Model_MeshNormals(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f); +} + +static void Model_Build_GenerateTangents(Model_Mesh *mesh) +{ + Model_MeshTangents(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f, mesh->data_svector3f, mesh->data_tvector3f); +} + +static void Model_Build_GenerateLightmapTexCoords(Model_Mesh *mesh) +{ + // TODO + // this function should build non-overlapping triangle groups in a + // lightmap texture with some kind of assumed resolution based on the + // model bounding box (the resolution only matters when ensuring that + // some texture exists around each group to accomodate linear filtering, + // or perhaps a bit more if we decide to use mipmapped lightmaps) + // + // TODO: how do do this? +} + +void Model_Build_Compile(Model *b, Nbool generateneighbors, Nbool generateplanes, Nbool generatenormals, Nbool generatetangents, Nbool generatelightmaptexcoords, Nbool generatecollisionbrushes) +{ + NUint32 i, j; + const float *v; + Model_Mesh *mesh; + Nbool initbox; + initbox = true; + VectorClear(b->basecullmins); + VectorClear(b->basecullmaxs); + for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++) + { + if (mesh->max_triangles > mesh->num_triangles) + { + mesh->max_triangles = mesh->num_triangles; + if (mesh->data_element3i) Mem_ReAlloc(b->memzone, &mesh->data_element3i, mesh->max_triangles * 3 * sizeof(*mesh->data_element3i)); + if (mesh->data_neighbor3i) Mem_ReAlloc(b->memzone, &mesh->data_neighbor3i, mesh->max_triangles * 3 * sizeof(*mesh->data_neighbor3i)); + if (mesh->data_plane4f) Mem_ReAlloc(b->memzone, &mesh->data_plane4f, mesh->max_triangles * 4 * sizeof(*mesh->data_plane4f)); + } + + if (mesh->max_vertices > mesh->num_vertices) + { + mesh->max_vertices = mesh->num_vertices; + if (mesh->data_vertex3f) Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); + if (mesh->data_svector3f) Mem_ReAlloc(b->memzone, &mesh->data_svector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_svector3f)); + if (mesh->data_tvector3f) Mem_ReAlloc(b->memzone, &mesh->data_tvector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_tvector3f)); + if (mesh->data_normal3f) Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); + if (mesh->data_texcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); + if (mesh->data_lightmaptexcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_lightmaptexcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_lightmaptexcoord2f)); + if (mesh->data_weightindex4b) Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); + if (mesh->data_weightvalue4b) Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); + } + + if (generateneighbors) + { + if (!mesh->data_neighbor3i) Mem_ReAlloc(b->memzone, &mesh->data_neighbor3i, mesh->max_triangles * 3 * sizeof(*mesh->data_neighbor3i)); + Model_Build_GenerateNeighbors(mesh); + } + + if (generateplanes) + { + if (!mesh->data_plane4f) Mem_ReAlloc(b->memzone, &mesh->data_plane4f, mesh->max_triangles * 4 * sizeof(*mesh->data_plane4f)); + Model_Build_GeneratePlanes(mesh); + } + + if (generatenormals) + { + if (!mesh->data_normal3f) Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); + Model_Build_GenerateNormals(mesh); + } + + if (generatetangents) + { + if (!mesh->data_svector3f) Mem_ReAlloc(b->memzone, &mesh->data_svector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_svector3f)); + if (!mesh->data_tvector3f) Mem_ReAlloc(b->memzone, &mesh->data_tvector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_tvector3f)); + Model_Build_GenerateTangents(mesh); + } + + if (generatelightmaptexcoords) + { + if (!mesh->data_lightmaptexcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_lightmaptexcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_lightmaptexcoord2f)); + Model_Build_GenerateLightmapTexCoords(mesh); + } + + if (mesh->data_collisionbrushes) + { + Collision_Brush_FreeBrushesForTriangleMesh(mesh->data_collisionbrushes, mesh->max_collisionbrushes); + mesh->num_collisionbrushes = 0; + mesh->max_collisionbrushes = 0; + mesh->data_collisionbrushes = NULL; + } + if (generatecollisionbrushes) + { + mesh->num_collisionbrushes = mesh->num_triangles; + mesh->max_collisionbrushes = mesh->num_collisionbrushes; + mesh->data_collisionbrushes = Collision_Brush_AllocBrushesForTriangleMesh(b->memzone, mesh->max_collisionbrushes); + Collision_Brush_UpdateTriangleMeshBrushes(mesh->data_collisionbrushes, mesh->max_collisionbrushes, mesh->data_element3i, mesh->data_vertex3f); + } + + for (j = 0, v = mesh->data_vertex3f;j < mesh->num_vertices;j++, v += 3) + { + if (initbox) + { + initbox = false; + VectorCopy(v, b->basecullmins); + VectorCopy(v, b->basecullmaxs); + } + else + { + b->basecullmins[0] = Min(b->basecullmins[0], v[0]); + b->basecullmins[1] = Min(b->basecullmins[1], v[1]); + b->basecullmins[2] = Min(b->basecullmins[2], v[2]); + b->basecullmaxs[0] = Max(b->basecullmaxs[0], v[0]); + b->basecullmaxs[1] = Max(b->basecullmaxs[1], v[1]); + b->basecullmaxs[2] = Max(b->basecullmaxs[2], v[2]); + } + } + } +} + +void Model_Build_Free(Model *b) +{ + NUint32 i; + Model_Mesh *mesh; + for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++) + { + if (mesh->materialname) String_Free(&mesh->materialname); + if (mesh->data_element3i) Mem_Free(&mesh->data_element3i); + if (mesh->data_neighbor3i) Mem_Free(&mesh->data_neighbor3i); + if (mesh->data_plane4f) Mem_Free(&mesh->data_plane4f); + if (mesh->data_vertex3f) Mem_Free(&mesh->data_vertex3f); + if (mesh->data_svector3f) Mem_Free(&mesh->data_svector3f); + if (mesh->data_tvector3f) Mem_Free(&mesh->data_tvector3f); + if (mesh->data_normal3f) Mem_Free(&mesh->data_normal3f); + if (mesh->data_texcoord2f) Mem_Free(&mesh->data_texcoord2f); + if (mesh->data_lightmaptexcoord2f) Mem_Free(&mesh->data_lightmaptexcoord2f); + if (mesh->data_weightindex4b) Mem_Free(&mesh->data_weightindex4b); + if (mesh->data_weightvalue4b) Mem_Free(&mesh->data_weightvalue4b); + if (mesh->data_collisionbrushes) Collision_Brush_FreeBrushesForTriangleMesh(mesh->data_collisionbrushes, mesh->max_collisionbrushes); + } + if (b->data_meshes) + Mem_Free(&b->data_meshes); + memset(b, 0, sizeof(*b)); +} + +NUint32 Model_Build_AddSurface(Model *b, Mem_Zone *zone, const char *materialname, NUint32 initialtriangles, NUint32 initialvertices) +{ + Model_Mesh *mesh; + if (b->num_meshes >= b->max_meshes) + { + b->max_meshes = Max(b->max_meshes * 2, 16); + Mem_ReAlloc(Global_Zone, &b->data_meshes, b->max_meshes * sizeof(*b->data_meshes)); + } + mesh = b->data_meshes + b->num_meshes; + String_Set(&mesh->materialname, zone, materialname); + mesh->max_triangles = initialtriangles; + mesh->max_vertices = initialvertices; + b->num_meshes++; + return b->num_meshes - 1; +} + +NUint32 Model_Build_AddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t) +{ + float *v; + Model_Mesh *mesh = b->data_meshes + meshindex; + if (mesh->num_vertices >= mesh->max_vertices) + { + mesh->max_vertices = Max(mesh->max_vertices * 2, 1024); + Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); + Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); + Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); + if (b->isskeletal) + { + Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); + Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); + } + } + v = mesh->data_vertex3f + mesh->num_vertices * 3; + v[0] = x; + v[1] = y; + v[2] = z; + v = mesh->data_normal3f + mesh->num_vertices * 3; + v[0] = nx; + v[1] = ny; + v[2] = nz; + v = mesh->data_texcoord2f + mesh->num_vertices * 2; + v[0] = s; + v[1] = t; + if (b->isskeletal) + { + NUint8 *wi = mesh->data_weightindex4b + mesh->num_vertices * 4; + NUint8 *wf = mesh->data_weightvalue4b + mesh->num_vertices * 4; + wi[0] = 0; + wi[1] = 0; + wi[2] = 0; + wi[3] = 0; + wf[0] = 255; + wf[1] = 0; + wf[2] = 0; + wf[3] = 0; + } + mesh->num_vertices++; + return mesh->num_vertices - 1; +} + +NUint32 Model_Build_AddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb) +{ + float *v; + Model_Mesh *mesh = b->data_meshes + meshindex; + if (mesh->num_vertices >= mesh->max_vertices) + { + mesh->max_vertices = Max(mesh->max_vertices * 2, 1024); + Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); + Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); + Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); + if (b->isskeletal) + { + Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); + Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); + } + } + v = mesh->data_vertex3f + mesh->num_vertices * 3; + v[0] = x; + v[1] = y; + v[2] = z; + v = mesh->data_normal3f + mesh->num_vertices * 3; + v[0] = nx; + v[1] = ny; + v[2] = nz; + v = mesh->data_texcoord2f + mesh->num_vertices * 2; + v[0] = s; + v[1] = t; + if (b->isskeletal) + { + NUint8 *wi = mesh->data_weightindex4b + mesh->num_vertices * 4; + NUint8 *wf = mesh->data_weightvalue4b + mesh->num_vertices * 4; + Vector4Copy(wib, wi); + Vector4Copy(wfb, wf); + } + mesh->num_vertices++; + return mesh->num_vertices - 1; +} + +NUint32 Model_Build_FindOrAddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t) +{ + NUint32 i; + float *v, *n, *tc; + NUint8 *wi, *wf; + Model_Mesh *mesh = b->data_meshes + meshindex; + for (i = 0, v = mesh->data_vertex3f, n = mesh->data_normal3f, tc = mesh->data_texcoord2f, wi = mesh->data_weightindex4b, wf = mesh->data_weightvalue4b;i < mesh->num_vertices;i++, v += 3, n += 3, tc += 2, wi += 4, wf += 4) + if (fabs(v[0] - x) < 0.0001 && fabs(v[1] - y) < 0.0001 && fabs(v[2] - z) < 0.0001 + && fabs(n[0] - nx) < 0.0001 && fabs(n[1] - ny) < 0.0001 && fabs(n[2] - nz) < 0.0001 + && fabs(tc[0] - s) < 0.0001 && fabs(tc[1] - t) < 0.0001) + return i; + return Model_Build_AddVertex(b, meshindex, x, y, z, nx, ny, nz, s, t); +} + +NUint32 Model_Build_FindOrAddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb) +{ + NUint32 i; + float *v, *n, *tc; + NUint8 *wi, *wf; + Model_Mesh *mesh = b->data_meshes + meshindex; + for (i = 0, v = mesh->data_vertex3f, n = mesh->data_normal3f, tc = mesh->data_texcoord2f, wi = mesh->data_weightindex4b, wf = mesh->data_weightvalue4b;i < mesh->num_vertices;i++, v += 3, n += 3, tc += 2, wi += 4, wf += 4) + if (fabs(v[0] - x) < 0.0001 && fabs(v[1] - y) < 0.0001 && fabs(v[2] - z) < 0.0001 + && fabs(n[0] - nx) < 0.0001 && fabs(n[1] - ny) < 0.0001 && fabs(n[2] - nz) < 0.0001 + && fabs(tc[0] - s) < 0.0001 && fabs(tc[1] - t) < 0.0001 + && wi[0] == wib[0] && wi[1] == wib[1] && wi[2] == wib[2] && wi[3] == wib[3] + && wf[0] == wfb[0] && wf[1] == wfb[1] && wf[2] == wfb[2] && wf[3] == wfb[3]) + return i; + return Model_Build_AddVertexSkeletal(b, meshindex, x, y, z, nx, ny, nz, s, t, wib, wfb); +} + +NUint32 Model_Build_AddTriangle(Model *b, NUint32 meshindex, int e0, int e1, int e2) +{ + Model_Mesh *mesh = b->data_meshes + meshindex; + NUint32 *e; + if (mesh->num_triangles >= mesh->max_triangles) + { + mesh->max_triangles = Max(mesh->max_triangles * 2, 1024); + Mem_ReAlloc(b->memzone, &mesh->data_element3i, mesh->max_triangles * 3 * sizeof(*mesh->data_element3i)); + } + e = mesh->data_element3i + mesh->num_triangles * 3; + e[0] = e0; + e[1] = e1; + e[2] = e2; + mesh->num_triangles++; + return mesh->num_triangles - 1; +} + +void Model_Build_Write(Model *b, const char *filename) +{ + // FIXME: this is very unlikely to overflow but it should be made buffer size safe at some point + NUint32 i, num; + Nsize textsize, textmaxsize; + char *text; + Model_Mesh *mesh; + textmaxsize = 0x100000; + for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++) + textmaxsize += mesh->num_vertices * 60 + mesh->num_triangles * 40; + textsize = 0; + text = Mem_Alloc(Global_Zone, textmaxsize); + textsize += snprintf(text + textsize, textmaxsize - textsize, "MD5Version 10\ncommandline \"\"\n\nnumJoints 1\nnumMeshes %u\n\njoints {\n\t\"ROOT\"\t-1 ( 0.000000 0.000000 0.000000 ) ( 0.000000 0.000000 0.000000 ) // \n}\n", b->num_meshes); + for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++) + { + if (textmaxsize < textsize + mesh->num_vertices * 100 + mesh->num_triangles * 100 + mesh->num_vertices * 100 + 1000) + { + textmaxsize = textsize + mesh->num_vertices * 200 + mesh->num_triangles * 200 + mesh->num_vertices * 200 + 2000; + Mem_ReAlloc(Global_Zone, &text, textmaxsize); + } + textsize += snprintf(text + textsize, textmaxsize - textsize, "\nmesh {\n\tshader \"%s\"\n\n\tnumverts %u\n", mesh->materialname, mesh->num_vertices); + for (num = 0;num < mesh->num_vertices;num++) + textsize += snprintf(text + textsize, textmaxsize - textsize, "\tvert %u ( %.6f %.6f ) %u 1\n", num, mesh->data_texcoord2f[num*2+0], mesh->data_texcoord2f[num*2+1], num); + textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumtris %u\n", mesh->num_triangles); + for (num = 0;num < mesh->num_triangles;num++) + textsize += snprintf(text + textsize, textmaxsize - textsize, "\ttri %u %u %u %u\n", num, mesh->data_element3i[num*3+0], mesh->data_element3i[num*3+1], mesh->data_element3i[num*3+2]); + textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumweights %u\n", mesh->num_vertices); + for (num = 0;num < mesh->num_vertices;num++) + textsize += snprintf(text + textsize, textmaxsize - textsize, "\tweight %u 0 1.000000 ( %.6f %.6f %.6f )\n", num, mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1], mesh->data_vertex3f[num*3+2]); + textsize += snprintf(text + textsize, textmaxsize - textsize, "}\n"); + } + File_WriteFile(filename, text, textsize); + Mem_Free(&text); +} + +void Model_Build_ImportOBJ(Model *b, const char *inputname, const char *text, const char *textend) +{ + NUint32 linenumber = 0; + NSint32 meshindex = -1; + NUint32 num_vertices = 0, max_vertices = 0; + NUint32 num_normals = 0, max_normals = 0; + NUint32 num_texcoords = 0, max_texcoords = 0; + float *data_vertex3f = NULL; + float *data_normal3f = NULL; + float *data_texcoord2f = NULL; + while (text < textend) + { + Nbool comment = false; + NUint32 argc = 0; + char argv[64][256]; + // parse the line + linenumber++; + while (text < textend && *text != '\r' && *text != '\n') + { + if (comment || *text <= ' ') + text++; + else if (*text == '#') + comment = true; + else + { + NUint32 charnum; + for (charnum = 0;text < textend && *text > ' ';text++) + if (charnum < sizeof(argv[0]) - 1) + argv[argc][charnum++] = *text; + argv[argc++][charnum] = 0; + } + } + if (*text == '\r' && text[1] == '\n') + text++; + if (*text == '\n') + text++; + // now we have a command + if (argc < 1) + continue; + if (!String_Compare(argv[0], "v")) + { + // v -4.99960e-2 0.250000 -1.00000 + if (argc == 4) + { + if (num_vertices >= max_vertices) + { + max_vertices = Max(max_vertices * 2, 1024); + Mem_ReAlloc(Global_Zone, &data_vertex3f, max_vertices * sizeof(float[3])); + } + data_vertex3f[num_vertices*3+0] = atof(argv[1]); + data_vertex3f[num_vertices*3+2] = atof(argv[2]); + data_vertex3f[num_vertices*3+1] = atof(argv[3]); + num_vertices++; + } + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3); + } + else if (!String_Compare(argv[0], "vn")) + { + // vn 1.99019e-6 2.65359e-5 -1.000000 + if (argc == 4) + { + if (num_normals >= max_normals) + { + max_normals = Max(max_normals * 2, 1024); + Mem_ReAlloc(Global_Zone, &data_normal3f, max_normals * sizeof(float[3])); + } + data_normal3f[num_normals*3+0] = atof(argv[1]); + data_normal3f[num_normals*3+2] = atof(argv[2]); + data_normal3f[num_normals*3+1] = atof(argv[3]); + num_normals++; + } + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3); + } + else if (!String_Compare(argv[0], "vt")) + { + // vt 0.00000e+0 1.99019e-6 + if (argc == 3) + { + if (num_texcoords >= max_texcoords) + { + max_texcoords = Max(max_texcoords * 2, 1024); + Mem_ReAlloc(Global_Zone, &data_texcoord2f, max_texcoords * sizeof(float[2])); + } + data_texcoord2f[num_texcoords*2+0] = atof(argv[1]); + data_texcoord2f[num_texcoords*2+1] = -atof(argv[2]); + num_texcoords++; + } + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 2); + } + else if (!String_Compare(argv[0], "usemtl")) + { + // usemtl mtrl/chrome + if (argc == 2) + meshindex = Model_Build_AddSurface(b, Global_Zone, argv[1], 0, 0); + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); + } + else if (!String_Compare(argv[0], "f")) + { + // f 1/11/5 18/56/71 17/58/67 + NUint32 i; + NUint32 indices[64]; + if (argc >= 4) + { + if (meshindex == -1) + meshindex = Model_Build_AddSurface(b, Global_Zone, "default", 0, 0); + for (i = 0;i < argc - 1;i++) + { + NUint32 j; + const char *s = argv[i+1]; + float v[3]; + float vn[3]; + float tc[2]; + // if there are 3 indices, they are vertex, texcoord, normal + // if there are 2 indices, they are vertex, texcoord + // if there is only one index, it is vertex + // so we just initialize the values to defaults, + // and update them as indices are read + VectorClear(v); + VectorClear(vn); + Vector2Clear(tc); + for (j = 0;j < 3;j++) + { + if (*s) + { + NSint32 k = atoi(s); + switch (j) + { + case 0: + if (k < 0) + k += num_vertices; + else + k--; + if (k >= 0 && k < num_vertices) + VectorCopy(data_vertex3f + k * 3, v); + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face vertex index (parameter #%i)\n", inputname, linenumber, i + 1); + break; + case 1: + if (k < 0) + k += num_texcoords; + else + k--; + if (k >= 0 && k < num_texcoords) + Vector2Copy(data_texcoord2f + k * 2, tc); + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face texcoord index (parameter #%i)\n", inputname, linenumber, i + 1); + break; + case 2: + if (k < 0) + k += num_normals; + else + k--; + if (k >= 0 && k < num_normals) + VectorCopy(data_normal3f + k * 3, vn); + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face vertexnormal index (parameter #%i)\n", inputname, linenumber, i + 1); + break; + } + } + // this weird code construct exits at NUL, or if the + // character is /, and then leaves s at the character + // after the NUL or / + while (*s) + { + if (*s == '/') + { + s++; + break; + } + s++; + } + } + indices[i] = Model_Build_FindOrAddVertex(b, meshindex, v[0], v[1], v[2], vn[0], vn[1], vn[2], tc[0], tc[1]); + // make a triangle fan if we have enough vertices + if (i >= 2) + Model_Build_AddTriangle(b, meshindex, indices[0], indices[i-1], indices[i]); + } + } + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i or more parameters\n", inputname, linenumber, argv[0], 3); + } + else if (!String_Compare(argv[0], "o")) + { + // o cylinder1 + if (argc != 2) + Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); + } + else if (!String_Compare(argv[0], "mtllib")) + { + // mtllib zrail2.mtl + if (argc != 2) + Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); + } + else if (!String_Compare(argv[0], "g")) + { + // g cylinder1_mtrl/invisible + if (argc != 2) + Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); + } + else + Console_Printf("Model_Build_ImportOBJ: %s:%i: unknown obj command %s\n", inputname, linenumber, argv[0]); + } + if (data_vertex3f) + Mem_Free(&data_vertex3f); + if (data_normal3f) + Mem_Free(&data_normal3f); + if (data_texcoord2f) + Mem_Free(&data_texcoord2f); +} + /* example clips of an MD5 model MD5Version 10 commandline "" @@ -578,7 +1148,8 @@ VectorCopy(md5weights[md5weightrange[i*2+0]].vertex, mesh->data_vertex3f + i*3); } // compile the base frame of the mesh for static uses - Model_MeshVectors(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_svector3f, mesh->data_tvector3f, mesh->data_normal3f); + Model_MeshNormals(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f); + Model_MeshTangents(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f, mesh->data_svector3f, mesh->data_tvector3f); Model_MeshNeighbors(mesh->num_triangles, mesh->data_element3i, mesh->data_neighbor3i, mesh->num_vertices); Model_BuildTrianglePlanes(mesh->data_vertex3f, mesh->num_triangles, mesh->data_element3i, mesh->data_plane4f); // collision brushes are for the static frame Modified: trunk/model.h =================================================================== --- trunk/model.h 2006-05-09 20:05:18 UTC (rev 713) +++ trunk/model.h 2006-05-12 08:36:47 UTC (rev 714) @@ -80,6 +80,11 @@ typedef struct Model { + // set at the creation of the Model + Mem_Zone *memzone; + + Nbool isskeletal; + NUint32 num_meshes; NUint32 max_meshes; Model_Mesh *data_meshes; @@ -97,6 +102,18 @@ void Model_Load(ResourceEntry *r); void Model_Unload(ResourceEntry *r); +void Model_Build_Begin(Model *b, Mem_Zone *memzone, Nbool isskeletal); +void Model_Build_Compile(Model *b, Nbool generateneighbors, Nbool generateplanes, Nbool generatenormals, Nbool generatetangents, Nbool generatelightmaptexcoords, Nbool generatecollisionbrushes); +void Model_Build_Free(Model *b); +NUint32 Model_Build_AddSurface(Model *b, Mem_Zone *zone, const char *materialname, NUint32 initialtriangles, NUint32 initialvertices); +NUint32 Model_Build_AddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t); +NUint32 Model_Build_AddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb); +NUint32 Model_Build_FindOrAddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t); +NUint32 Model_Build_FindOrAddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb); +NUint32 Model_Build_AddTriangle(Model *b, NUint32 meshindex, int e0, int e1, int e2); +void Model_Build_Write(Model *b, const char *filename); +void Model_Build_ImportOBJ(Model *b, const char *inputname, const char *text, const char *textend); + // this function decodes skeletal vertex information to your supplied arrays // NOTE: outplane4f requires outvertex3f void Model_GetVertices(NUint32 resourceindex, NUint32 meshindex, const matrix4x4_t *transforms, float *outvertex3f, float *outsvector3f, float *outtvector3f, float *outnormal3f, float *outplane4f); Modified: trunk/util.c =================================================================== --- trunk/util.c 2006-05-09 20:05:18 UTC (rev 713) +++ trunk/util.c 2006-05-12 08:36:47 UTC (rev 714) @@ -2,6 +2,7 @@ #include "ncommon.h" #include "util.h" #include "texture.h" +#include "model.h" static Shell_SymbolDecl Util_Shell_MakeSkyBox_Decl; static Shell_SymbolDecl Util_Shell_MakeTerrain_Decl; @@ -240,337 +241,6 @@ #undef ReadNext } -void Util_BuildModel_Begin(Util_BuildModel *b) -{ - memset(b, 0, sizeof(*b)); -} - -void Util_BuildModel_End(Util_BuildModel *b) -{ - NUint32 i; - Util_BuildModel_Surface *surface; - for (i = 0, surface = b->data_surfaces;i < b->num_surfaces;i++, surface++) - { - Mem_Free(&surface->data_element3i); - Mem_Free(&surface->data_vertex8f); - } - Mem_Free(&b->data_surfaces); - memset(b, 0, sizeof(*b)); -} - -NUint32 Util_BuildModel_AddSurface(Util_BuildModel *b, const char *materialname) -{ - Util_BuildModel_Surface *surface; - if (b->num_surfaces >= b->max_surfaces) - { - b->max_surfaces = Max(b->max_surfaces * 2, 16); - Mem_ReAlloc(Global_Zone, &b->data_surfaces, b->max_surfaces * sizeof(Util_BuildModel_Surface)); - } - surface = b->data_surfaces + b->num_surfaces; - strncpy(surface->materialname, materialname, sizeof(surface->materialname) - 1); - b->num_surfaces++; - return b->num_surfaces - 1; -} - -NUint32 Util_BuildModel_AddVertex(Util_BuildModel *b, NUint32 surfaceindex, float x, float y, float z, float nx, float ny, float nz, float s, float t) -{ - float *v; - Util_BuildModel_Surface *surface = b->data_surfaces + surfaceindex; - if (surface->num_vertices >= surface->max_vertices) - { - surface->max_vertices = Max(surface->max_vertices * 2, 1024); - Mem_ReAlloc(Global_Zone, &surface->data_vertex8f, surface->max_vertices * sizeof(float[8])); - } - v = surface->data_vertex8f + surface->num_vertices * 8; - v[0] = x; - v[1] = y; - v[2] = z; - v[3] = nx; - v[4] = ny; - v[5] = nz; - v[6] = s; - v[7] = t; - surface->num_vertices++; - return surface->num_vertices - 1; -} - -NUint32 Util_BuildModel_FindOrAddVertex(Util_BuildModel *b, NUint32 surfaceindex, float x, float y, float z, float nx, float ny, float nz, float s, float t) -{ - NUint32 i; - float *v; - Util_BuildModel_Surface *surface = b->data_surfaces + surfaceindex; - for (i = 0, v = surface->data_vertex8f;i < surface->num_vertices;i++, v += 8) - if (fabs(v[0] - x) < 0.0001 && fabs(v[1] - y) < 0.0001 && fabs(v[2] - z) < 0.0001 && fabs(v[3] - nx) < 0.0001 && fabs(v[4] - ny) < 0.0001 && fabs(v[5] - nz) < 0.0001 && fabs(v[6] - s) < 0.0001 && fabs(v[7] - t) < 0.0001) - return i; - return Util_BuildModel_AddVertex(b, surfaceindex, x, y, z, nx, ny, nz, s, t); -} - -NUint32 Util_BuildModel_AddTriangle(Util_BuildModel *b, NUint32 surfaceindex, int e0, int e1, int e2) -{ - Util_BuildModel_Surface *surface = b->data_surfaces + surfaceindex; - NUint32 *e; - if (surface->num_triangles >= surface->max_triangles) - { - surface->max_triangles = Max(surface->max_triangles * 2, 1024); - Mem_ReAlloc(Global_Zone, &surface->data_element3i, surface->max_triangles * sizeof(NUint32[3])); - } - e = surface->data_element3i + surface->num_triangles * 3; - e[0] = e0; - e[1] = e1; - e[2] = e2; - surface->num_triangles++; - return surface->num_triangles - 1; -} - -void Util_BuildModel_Write(Util_BuildModel *b, const char *filename) -{ - // FIXME: this is very unlikely to overflow but it should be made buffer size safe at some point - NUint32 i, num; - Nsize textsize, textmaxsize; - char *text; - Util_BuildModel_Surface *surface; - textmaxsize = 0x100000; - for (i = 0, surface = b->data_surfaces;i < b->num_surfaces;i++, surface++) - textmaxsize += surface->num_vertices * 60 + surface->num_triangles * 40; - textsize = 0; - text = Mem_Alloc(Global_Zone, textmaxsize); - textsize += snprintf(text + textsize, textmaxsize - textsize, "MD5Version 10\ncommandline \"\"\n\nnumJoints 1\nnumMeshes %u\n\njoints {\n\t\"ROOT\"\t-1 ( 0.000000 0.000000 0.000000 ) ( 0.000000 0.000000 0.000000 ) // \n}\n", b->num_surfaces); - for (i = 0, surface = b->data_surfaces;i < b->num_surfaces;i++, surface++) - { - if (textmaxsize < textsize + surface->num_vertices * 100 + surface->num_triangles * 100 + surface->num_vertices * 100 + 1000) - { - textmaxsize = textsize + surface->num_vertices * 200 + surface->num_triangles * 200 + surface->num_vertices * 200 + 2000; - Mem_ReAlloc(Global_Zone, &text, textmaxsize); - } - textsize += snprintf(text + textsize, textmaxsize - textsize, "\nmesh {\n\tshader \"%s\"\n\n\tnumverts %u\n", surface->materialname, surface->num_vertices); - for (num = 0;num < surface->num_vertices;num++) - textsize += snprintf(text + textsize, textmaxsize - textsize, "\tvert %u ( %.6f %.6f ) %u 1\n", num, surface->data_vertex8f[num*8+6], surface->data_vertex8f[num*8+7], num); - textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumtris %u\n", surface->num_triangles); - for (num = 0;num < surface->num_triangles;num++) - textsize += snprintf(text + textsize, textmaxsize - textsize, "\ttri %u %u %u %u\n", num, surface->data_element3i[num*3+0], surface->data_element3i[num*3+1], surface->data_element3i[num*3+2]); - textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumweights %u\n", surface->num_vertices); - for (num = 0;num < surface->num_vertices;num++) - textsize += snprintf(text + textsize, textmaxsize - textsize, "\tweight %u 0 1.000000 ( %.6f %.6f %.6f )\n", num, surface->data_vertex8f[num*8+0], surface->data_vertex8f[num*8+1], surface->data_vertex8f[num*8+2]); - textsize += snprintf(text + textsize, textmaxsize - textsize, "}\n"); - } - File_WriteFile(filename, text, textsize); - Mem_Free(&text); -} - -void Util_BuildModel_ImportOBJ(Util_BuildModel *b, const char *inputname, const char *text, const char *textend) -{ - NUint32 linenumber = 0; - NSint32 surfaceindex = -1; - NUint32 num_vertices = 0, max_vertices = 0; - NUint32 num_normals = 0, max_normals = 0; - NUint32 num_texcoords = 0, max_texcoords = 0; - float *data_vertex3f = NULL; - float *data_normal3f = NULL; - float *data_texcoord2f = NULL; - while (text < textend) - { - Nbool comment = false; - NUint32 argc = 0; - char argv[64][256]; - // parse the line - linenumber++; - while (text < textend && *text != '\r' && *text != '\n') - { - if (comment || *text <= ' ') - text++; - else if (*text == '#') - comment = true; - else - { - NUint32 charnum; - for (charnum = 0;text < textend && *text > ' ';text++) - if (charnum < sizeof(argv[0]) - 1) - argv[argc][charnum++] = *text; - argv[argc++][charnum] = 0; - } - } - if (*text == '\r' && text[1] == '\n') - text++; - if (*text == '\n') - text++; - // now we have a command - if (argc < 1) - continue; - if (!String_Compare(argv[0], "v")) - { - // v -4.99960e-2 0.250000 -1.00000 - if (argc == 4) - { - if (num_vertices >= max_vertices) - { - max_vertices = Max(max_vertices * 2, 1024); - Mem_ReAlloc(Global_Zone, &data_vertex3f, max_vertices * sizeof(float[3])); - } - data_vertex3f[num_vertices*3+0] = atof(argv[1]); - data_vertex3f[num_vertices*3+2] = atof(argv[2]); - data_vertex3f[num_vertices*3+1] = atof(argv[3]); - num_vertices++; - } - else - Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3); - } - else if (!String_Compare(argv[0], "vn")) - { - // vn 1.99019e-6 2.65359e-5 -1.000000 - if (argc == 4) - { - if (num_normals >= max_normals) - { - max_normals = Max(max_normals * 2, 1024); - Mem_ReAlloc(Global_Zone, &data_normal3f, max_normals * sizeof(float[3])); - } - data_normal3f[num_normals*3+0] = atof(argv[1]); - data_normal3f[num_normals*3+2] = atof(argv[2]); - data_normal3f[num_normals*3+1] = atof(argv[3]); - num_normals++; - } - else - Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3); - } - else if (!String_Compare(argv[0], "vt")) - { - // vt 0.00000e+0 1.99019e-6 - if (argc == 3) - { - if (num_texcoords >= max_texcoords) - { - max_texcoords = Max(max_texcoords * 2, 1024); - Mem_ReAlloc(Global_Zone, &data_texcoord2f, max_texcoords * sizeof(float[2])); - } - data_texcoord2f[num_texcoords*2+0] = atof(argv[1]); - data_texcoord2f[num_texcoords*2+1] = -atof(argv[2]); - num_texcoords++; - } - else - Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 2); - } - else if (!String_Compare(argv[0], "usemtl")) - { - // usemtl mtrl/chrome - if (argc == 2) - surfaceindex = Util_BuildModel_AddSurface(b, argv[1]); - else - Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); - } - else if (!String_Compare(argv[0], "f")) - { - // f 1/11/5 18/56/71 17/58/67 - NUint32 i; - NUint32 indices[64]; - if (argc >= 4) - { - if (surfaceindex == -1) - surfaceindex = Util_BuildModel_AddSurface(b, "default"); - for (i = 0;i < argc - 1;i++) - { - NUint32 j; - const char *s = argv[i+1]; - float v[3]; - float vn[3]; - float tc[2]; - // if there are 3 indices, they are vertex, texcoord, normal - // if there are 2 indices, they are vertex, texcoord - // if there is only one index, it is vertex - // so we just initialize the values to defaults, - // and update them as indices are read - VectorClear(v); - VectorClear(vn); - Vector2Clear(tc); - for (j = 0;j < 3;j++) - { - if (*s) - { - NSint32 k = atoi(s); - switch (j) - { - case 0: - if (k < 0) - k += num_vertices; - else - k--; - if (k >= 0 && k < num_vertices) - VectorCopy(data_vertex3f + k * 3, v); - else - Console_Printf("util_convertobj: %s:%i: invalid face vertex index (parameter #%i)\n", inputname, linenumber, i + 1); - break; - case 1: - if (k < 0) - k += num_texcoords; - else - k--; - if (k >= 0 && k < num_texcoords) - Vector2Copy(data_texcoord2f + k * 2, tc); - else - Console_Printf("util_convertobj: %s:%i: invalid face texcoord index (parameter #%i)\n", inputname, linenumber, i + 1); - break; - case 2: - if (k < 0) - k += num_normals; - else - k--; - if (k >= 0 && k < num_normals) - VectorCopy(data_normal3f + k * 3, vn); - else - Console_Printf("util_convertobj: %s:%i: invalid face vertexnormal index (parameter #%i)\n", inputname, linenumber, i + 1); - break; - } - } - // this weird code construct exits at NUL, or if the - // character is /, and then leaves s at the character - // after the NUL or / - while (*s) - { - if (*s == '/') - { - s++; - break; - } - s++; - } - } - indices[i] = Util_BuildModel_FindOrAddVertex(b, surfaceindex, v[0], v[1], v[2], vn[0], vn[1], vn[2], tc[0], tc[1]); - // make a triangle fan if we have enough vertices - if (i >= 2) - Util_BuildModel_AddTriangle(b, surfaceindex, indices[0], indices[i-1], indices[i]); - } - } - else - Console_Printf("util_convertobj: %s:%i: command %s takes %i or more parameters\n", inputname, linenumber, argv[0], 3); - } - else if (!String_Compare(argv[0], "o")) - { - // o cylinder1 - if (argc != 2) - Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); - } - else if (!String_Compare(argv[0], "mtllib")) - { - // mtllib zrail2.mtl - if (argc != 2) - Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); - } - else if (!String_Compare(argv[0], "g")) - { - // g cylinder1_mtrl/invisible - if (argc != 2) - Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); - } - else - Console_Printf("util_convertobj: %s:%i: unknown obj command %s\n", inputname, linenumber, argv[0]); - } - if (data_vertex3f) - Mem_Free(&data_vertex3f); - if (data_normal3f) - Mem_Free(&data_normal3f); - if (data_texcoord2f) - Mem_Free(&data_texcoord2f); -} - static void Util_Shell_MakeTerrain(void) { NUint32 tilesize, width, height, bx, by, tx, ty, tilewidth, tileheight, num, tileswidth, tilesheight; @@ -578,7 +248,7 @@ const char *basename, *imagename, *materialname; char *tilename; Nvec terrainsize[3], texturesize[2], terrainscale[3], terrainorigin[3], texturescale[2]; - Util_BuildModel b; + Model b; basename = Shell_Callback_GetArg(1); imagename = Shell_Callback_GetArg(2); tilesize = (int) Shell_Callback_GetArgValue(3); @@ -610,12 +280,12 @@ terrainorigin[2] = terrainsize[2] * -0.5; tileswidth = width / tilesize; tilesheight = height / tilesize; - Util_BuildModel_Begin(&b); + Model_Build_Begin(&b, Global_Zone, false); for (by = 0;by < height;by += tilesize) { for (bx = 0;bx < width;bx += tilesize) { - NUint32 surfaceindex = Util_BuildModel_AddSurface(&b, materialname); + NUint32 meshindex = Model_Build_AddSurface(&b, Global_Zone, materialname, 0, 0); tilewidth = Bound(0, width - bx, tilesize+2); tileheight = Bound(0, height - by, tilesize+2); for (ty = 0, num = 0;ty < tileheight;ty++) @@ -634,8 +304,8 @@ pyf = py - pyi; p = pixels + (pyi * width + pxi) * 4; pz = ((p[0]+p[1]+p[2])*(1.0-pxf)+(p[4]+p[5]+p[6])*(pxf))*(1.0-pyf)+((p[w+0]+p[w+1]+p[w+2])*(1.0-pxf)+(p[w+4]+p[w+5]+p[w+6])*(pxf))*(pyf); - // FIXME: this SHOULD calculate a valid surface normal!! - Util_BuildModel_AddVertex(&b, surfaceindex, px * terrainscale[0] + terrainorigin[0], py * terrainscale[1] + terrainorigin[1], pz * terrainscale[2] + terrainorigin[2], 0, 0, 1, (px * terrainscale[0] + terrainorigin[0]) * texturescale[0], (py * terrainscale[1] + terrainorigin[1]) * texturescale[1]); + // FIXME: this SHOULD calculate a valid mesh normal!! + Model_Build_AddVertex(&b, meshindex, px * terrainscale[0] + terrainorigin[0], py * terrainscale[1] + terrainorigin[1], pz * terrainscale[2] + terrainorigin[2], 0, 0, 1, (px * terrainscale[0] + terrainorigin[0]) * texturescale[0], (py * terrainscale[1] + terrainorigin[1]) * texturescale[1]); } } for (ty = 0, num = 0;ty < tileheight-1;ty++) @@ -643,17 +313,17 @@ for (tx = 0;tx < tilewidth-1;tx++, num += 6) { NUint32 i = ty*tilewidth+tx; - Util_BuildModel_AddTriangle(&b, surfaceindex, i, i+1, i+1+tilewidth); - Util_BuildModel_AddTriangle(&b, surfaceindex, i, i+1+tilewidth, i+tilewidth); + Model_Build_AddTriangle(&b, meshindex, i, i+1, i+1+tilewidth); + Model_Build_AddTriangle(&b, meshindex, i, i+1+tilewidth, i+tilewidth); } } } } Mem_Free(&pixels); tilename = String_APrintf(Global_Zone, "%s.md5mesh", basename); - Util_BuildModel_Write(&b, tilename); + Model_Build_Write(&b, tilename); String_Free(&tilename); - Util_BuildModel_End(&b); + Model_Build_Free(&b); } static Shell_SymbolDecl Util_Shell_MakeTerrain_Decl = { @@ -669,7 +339,7 @@ static void Util_Shell_ConvertOBJ(void) { Nsize objtextsize; - Util_BuildModel b; + Model b; const char *inputname = Shell_Callback_GetArg(1); const char *outputname = Shell_Callback_GetArg(2); char *objtext = File_LoadFile(inputname, &objtextsize); @@ -679,10 +349,10 @@ // SHELLTODO return; } - Util_BuildModel_Begin(&b); - Util_BuildModel_ImportOBJ(&b, inputname, objtext, objtext + objtextsize); - Util_BuildModel_Write(&b, outputname); - Util_BuildModel_End(&b); + Model_Build_Begin(&b, Global_Zone, false); + Model_Build_ImportOBJ(&b, inputname, objtext, objtext + objtextsize); + Model_Build_Write(&b, outputname); + Model_Build_Free(&b); Mem_Free(&objtext); } @@ -702,7 +372,7 @@ #define UTIL_SHELL_CONVERTLWO_FACE_MAXVERTS 4 typedef struct Util_Shell_ConvertLWO_Face { - NUint32 surfaceindex; + NUint32 meshindex; NUint32 numpoints; float point[UTIL_SHELL_CONVERTLWO_FACE_MAXVERTS][3]; } @@ -823,7 +493,7 @@ // polygon attributes if (!memcmp(chunk, "SURF", 4)) { - // list of polygons and their corresponding surfaces + // list of polygons and their corresponding meshes chunk_ptag_surf = chunk; } continue; @@ -846,7 +516,7 @@ if (!memcmp(chunk, "SURF", 4)) { materialindex++; - // surface name, often Default + // mesh name, often Default while (*content) content++; // skip to 4 byte boundary in file @@ -965,27 +635,27 @@ double boxsize; const char *basefilename, *baseimagename; char *filename; - Util_BuildModel b; + Model b; basefilename = Shell_Callback_GetArg(1); baseimagename = Shell_Callback_GetArg(2); boxsize = atof(Shell_Callback_GetArg(3)); - Util_BuildModel_Begin(&b); + Model_Build_Begin(&b, 0, 0); for (i = 0;i < 6;i++) { NUint32 j; NUint32 indices[4]; char *materialname = String_APrintf(Global_Zone, "%s_%s", baseimagename, skyboxsuffix[i]); - NUint32 surfaceindex = Util_BuildModel_AddSurface(&b, materialname); + NUint32 meshindex = Model_Build_AddSurface(&b, Global_Zone, materialname, 2, 4); String_Free(&materialname); for (j = 0;j < 4;j++) - indices[j] = Util_BuildModel_FindOrAddVertex(&b, surfaceindex, skyboxvertex[i][j][0], skyboxvertex[i][j][1], skyboxvertex[i][j][2], skyboxvertex[i][j][3], skyboxvertex[i][j][4], skyboxvertex[i][j][5], skyboxvertex[i][j][6], skyboxvertex[i][j][7]); - Util_BuildModel_AddTriangle(&b, surfaceindex, indices[0], indices[2], indices[1]); - Util_BuildModel_AddTriangle(&b, surfaceindex, indices[0], indices[3], indices[2]); + indices[j] = Model_Build_FindOrAddVertex(&b, meshindex, skyboxvertex[i][j][0], skyboxvertex[i][j][1], skyboxvertex[i][j][2], skyboxvertex[i][j][3], skyboxvertex[i][j][4], skyboxvertex[i][j][5], skyboxvertex[i][j][6], skyboxvertex[i][j][7]); + Model_Build_AddTriangle(&b, meshindex, indices[0], indices[2], indices[1]); + Model_Build_AddTriangle(&b, meshindex, indices[0], indices[3], indices[2]); } filename = String_APrintf(Global_Zone, "%s.md5mesh", basefilename); - Util_BuildModel_Write(&b, filename); + Model_Build_Write(&b, filename); String_Free(&filename); - Util_BuildModel_End(&b); + Model_Build_Free(&b); } static Shell_SymbolDecl Util_Shell_MakeSkyBox_Decl = { Modified: trunk/util.h =================================================================== --- trunk/util.h 2006-05-09 20:05:18 UTC (rev 713) +++ trunk/util.h 2006-05-12 08:36:47 UTC (rev 714) @@ -40,35 +40,6 @@ // lex the next token void Util_ParseC_Lex(Util_ParseC_Thread *thread); -typedef struct Util_BuildModel_Surface -{ - // no support for skeletal weighting since this is only used by utilities building simple models - char materialname[64]; - NUint32 num_triangles, max_triangles; - NUint32 *data_element3i; - NUint32 num_vertices, max_vertices; - float *data_vertex8f; -} -Util_BuildModel_Surface; - -typedef struct Util_BuildModel -{ - NUint32 num_surfaces, max_surfaces; - Util_BuildModel_Surface *data_surfaces; - // no support for skeleton since this is only used by utilities building simple models -} -Util_BuildModel; - -// a small system for easily building md5mesh files -void Util_BuildModel_Begin(Util_BuildModel *b); -void Util_BuildModel_End(Util_BuildModel *b); -NUint32 Util_BuildModel_AddSurface(Util_BuildModel *b, const char *materialname); -NUint32 Util_BuildModel_AddVertex(Util_BuildModel *b, NUint32 surfaceindex, float x, float y, float z, float nx, float ny, float nz, float s, float t); -NUint32 Util_BuildModel_FindOrAddVertex(Util_BuildModel *b, NUint32 surfaceindex, float x, float y, float z, float nx, float ny, float nz, float s, float t); -NUint32 Util_BuildModel_AddTriangle(Util_BuildModel *b, NUint32 surfaceindex, int e0, int e1, int e2); -void Util_BuildModel_Write(Util_BuildModel *b, const char *filename); -void Util_BuildModel_ImportOBJ(Util_BuildModel *b, const char *inputname, const char *text, const char *textend); - void Util_Init(void); void Util_Quit(void); From lordhavoc at icculus.org Fri May 12 07:03:18 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 12 May 2006 07:03:18 -0400 Subject: r715 - trunk Message-ID: <20060512110318.31208.qmail@icculus.org> Author: lordhavoc Date: 2006-05-12 07:03:18 -0400 (Fri, 12 May 2006) New Revision: 715 Modified: trunk/console.c Log: avoid an assertion failure when cursoring up/down if command history is empty Modified: trunk/console.c =================================================================== --- trunk/console.c 2006-05-12 08:36:47 UTC (rev 714) +++ trunk/console.c 2006-05-12 11:03:18 UTC (rev 715) @@ -156,7 +156,7 @@ (Shell_Symbol_Callback) Console_Toggle }; -static void Console_Shell_Echo(void) +static void Console_Shell_Echo(void) { NUint i; Console_Printf( "%s", Shell_Callback_GetArg( 1 ) ); @@ -174,7 +174,7 @@ (Shell_Symbol_Callback) Console_Shell_Echo }; -static void Console_Shell_Print(void) +static void Console_Shell_Print(void) { NUint i; Console_Printf( "%s", Shell_Callback_GetArg( 1 ) ); @@ -493,6 +493,8 @@ void Console_Cursor_Up(void) { + if (!Console.numcommandhistorymessages) + return; if (Console.commandindex == 0) return; Console.commandindex--; @@ -502,6 +504,8 @@ void Console_Cursor_Down(void) { + if (!Console.numcommandhistorymessages) + return; if (Console.commandindex < Console.numcommandhistorymessages - 1) { Console.commandindex++; String_Set(&Console.command, Console.zone, Console_GetCommandHistoryLine(Console.commandindex)); From lordhavoc at icculus.org Fri May 12 07:04:49 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 12 May 2006 07:04:49 -0400 Subject: r716 - in trunk: . base/maps Message-ID: <20060512110449.31288.qmail@icculus.org> Author: lordhavoc Date: 2006-05-12 07:04:48 -0400 (Fri, 12 May 2006) New Revision: 716 Modified: trunk/base/maps/test.ent trunk/model.c trunk/model.h trunk/nstring.c trunk/nstring.h trunk/util.c Log: reworked model system to use Import functions for loading each model format and also Write now identifies file extension, this means that util_convertobj has become util_convertmodel (able to convert any supported format to any other supported format), and obj models now work in the game without conversion. Modified: trunk/base/maps/test.ent =================================================================== --- trunk/base/maps/test.ent 2006-05-12 11:03:18 UTC (rev 715) +++ trunk/base/maps/test.ent 2006-05-12 11:04:48 UTC (rev 716) @@ -19,7 +19,7 @@ "classname" "vehicle_tank" } { - "origin" "0 -23 8" + "origin" "0 -35 6" "classname" "model" "model" "models/players/generic/player_generic.md5mesh" } Modified: trunk/model.c =================================================================== --- trunk/model.c 2006-05-12 11:03:18 UTC (rev 715) +++ trunk/model.c 2006-05-12 11:04:48 UTC (rev 716) @@ -188,11 +188,12 @@ Mem_Free(&hashtable); } -void Model_Build_Begin(Model *b, Mem_Zone *memzone, Nbool isskeletal) +void Model_Build_Begin(Model *model, const char *filename, Mem_Zone *memzone, Nbool isskeletal) { - memset(b, 0, sizeof(*b)); - b->memzone = memzone; - b->isskeletal = isskeletal; + memset(model, 0, sizeof(*model)); + strncpy(model->filename, filename, sizeof(model->filename) - 1); + model->memzone = memzone; + model->isskeletal = isskeletal; } static void Model_Build_GenerateNeighbors(Model_Mesh *mesh) @@ -227,69 +228,85 @@ // TODO: how do do this? } -void Model_Build_Compile(Model *b, Nbool generateneighbors, Nbool generateplanes, Nbool generatenormals, Nbool generatetangents, Nbool generatelightmaptexcoords, Nbool generatecollisionbrushes) +void Model_Build_Compile(Model *model, Nbool generateneighbors, Nbool generateplanes, Nbool generatenormals, Nbool generatetangents, Nbool generatelightmaptexcoords, Nbool generatecollisionbrushes) { - NUint32 i, j; + NUint32 meshindex, vertexindex, weightindex, transformindex; const float *v; Model_Mesh *mesh; Nbool initbox; initbox = true; - VectorClear(b->basecullmins); - VectorClear(b->basecullmaxs); - for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++) + VectorClear(model->basecullmins); + VectorClear(model->basecullmaxs); + // clear the culling radius value in each transform as it will be regenerated + if (model->num_transforms) + for (transformindex = 0;transformindex < model->num_transforms;transformindex++) + model->data_transforminfo[transformindex].radius = 0; + // process each mesh + for (meshindex = 0, mesh = model->data_meshes;meshindex < model->num_meshes;meshindex++, mesh++) { + // load the material + mesh->resource_material = Resource_IndexForName(mesh->materialname, RESOURCETYPE_MATERIAL, 0, 0); + + // resize triangle arrays if there is some wasted space if (mesh->max_triangles > mesh->num_triangles) { mesh->max_triangles = mesh->num_triangles; - if (mesh->data_element3i) Mem_ReAlloc(b->memzone, &mesh->data_element3i, mesh->max_triangles * 3 * sizeof(*mesh->data_element3i)); - if (mesh->data_neighbor3i) Mem_ReAlloc(b->memzone, &mesh->data_neighbor3i, mesh->max_triangles * 3 * sizeof(*mesh->data_neighbor3i)); - if (mesh->data_plane4f) Mem_ReAlloc(b->memzone, &mesh->data_plane4f, mesh->max_triangles * 4 * sizeof(*mesh->data_plane4f)); + if (mesh->data_element3i) Mem_ReAlloc(model->memzone, &mesh->data_element3i, mesh->max_triangles * 3 * sizeof(*mesh->data_element3i)); + if (mesh->data_neighbor3i) Mem_ReAlloc(model->memzone, &mesh->data_neighbor3i, mesh->max_triangles * 3 * sizeof(*mesh->data_neighbor3i)); + if (mesh->data_plane4f) Mem_ReAlloc(model->memzone, &mesh->data_plane4f, mesh->max_triangles * 4 * sizeof(*mesh->data_plane4f)); } + // resize vertex arrays if there is some wasted space if (mesh->max_vertices > mesh->num_vertices) { mesh->max_vertices = mesh->num_vertices; - if (mesh->data_vertex3f) Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); - if (mesh->data_svector3f) Mem_ReAlloc(b->memzone, &mesh->data_svector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_svector3f)); - if (mesh->data_tvector3f) Mem_ReAlloc(b->memzone, &mesh->data_tvector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_tvector3f)); - if (mesh->data_normal3f) Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); - if (mesh->data_texcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); - if (mesh->data_lightmaptexcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_lightmaptexcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_lightmaptexcoord2f)); - if (mesh->data_weightindex4b) Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); - if (mesh->data_weightvalue4b) Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); + if (mesh->data_vertex3f) Mem_ReAlloc(model->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); + if (mesh->data_svector3f) Mem_ReAlloc(model->memzone, &mesh->data_svector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_svector3f)); + if (mesh->data_tvector3f) Mem_ReAlloc(model->memzone, &mesh->data_tvector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_tvector3f)); + if (mesh->data_normal3f) Mem_ReAlloc(model->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); + if (mesh->data_texcoord2f) Mem_ReAlloc(model->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); + if (mesh->data_lightmaptexcoord2f) Mem_ReAlloc(model->memzone, &mesh->data_lightmaptexcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_lightmaptexcoord2f)); + if (mesh->data_weightindex4b) Mem_ReAlloc(model->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); + if (mesh->data_weightvalue4b) Mem_ReAlloc(model->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); } + // generate triangle neighbors if requested if (generateneighbors) { - if (!mesh->data_neighbor3i) Mem_ReAlloc(b->memzone, &mesh->data_neighbor3i, mesh->max_triangles * 3 * sizeof(*mesh->data_neighbor3i)); + if (!mesh->data_neighbor3i) Mem_ReAlloc(model->memzone, &mesh->data_neighbor3i, mesh->max_triangles * 3 * sizeof(*mesh->data_neighbor3i)); Model_Build_GenerateNeighbors(mesh); } + // generate triangle planes if requested if (generateplanes) { - if (!mesh->data_plane4f) Mem_ReAlloc(b->memzone, &mesh->data_plane4f, mesh->max_triangles * 4 * sizeof(*mesh->data_plane4f)); + if (!mesh->data_plane4f) Mem_ReAlloc(model->memzone, &mesh->data_plane4f, mesh->max_triangles * 4 * sizeof(*mesh->data_plane4f)); Model_Build_GeneratePlanes(mesh); } + // generate vertex normals if requested if (generatenormals) { - if (!mesh->data_normal3f) Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); + if (!mesh->data_normal3f) Mem_ReAlloc(model->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); Model_Build_GenerateNormals(mesh); } + // generate vertex tangent vectors if requested if (generatetangents) { - if (!mesh->data_svector3f) Mem_ReAlloc(b->memzone, &mesh->data_svector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_svector3f)); - if (!mesh->data_tvector3f) Mem_ReAlloc(b->memzone, &mesh->data_tvector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_tvector3f)); + if (!mesh->data_svector3f) Mem_ReAlloc(model->memzone, &mesh->data_svector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_svector3f)); + if (!mesh->data_tvector3f) Mem_ReAlloc(model->memzone, &mesh->data_tvector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_tvector3f)); Model_Build_GenerateTangents(mesh); } + // generate lightmap texcoords if requested if (generatelightmaptexcoords) { - if (!mesh->data_lightmaptexcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_lightmaptexcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_lightmaptexcoord2f)); + if (!mesh->data_lightmaptexcoord2f) Mem_ReAlloc(model->memzone, &mesh->data_lightmaptexcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_lightmaptexcoord2f)); Model_Build_GenerateLightmapTexCoords(mesh); } + // free old triangle collision brushes if (mesh->data_collisionbrushes) { Collision_Brush_FreeBrushesForTriangleMesh(mesh->data_collisionbrushes, mesh->max_collisionbrushes); @@ -297,40 +314,63 @@ mesh->max_collisionbrushes = 0; mesh->data_collisionbrushes = NULL; } + // generate triangle collision brushes if requested if (generatecollisionbrushes) { mesh->num_collisionbrushes = mesh->num_triangles; mesh->max_collisionbrushes = mesh->num_collisionbrushes; - mesh->data_collisionbrushes = Collision_Brush_AllocBrushesForTriangleMesh(b->memzone, mesh->max_collisionbrushes); + mesh->data_collisionbrushes = Collision_Brush_AllocBrushesForTriangleMesh(model->memzone, mesh->max_collisionbrushes); Collision_Brush_UpdateTriangleMeshBrushes(mesh->data_collisionbrushes, mesh->max_collisionbrushes, mesh->data_element3i, mesh->data_vertex3f); } - for (j = 0, v = mesh->data_vertex3f;j < mesh->num_vertices;j++, v += 3) + // compute culling box for this mesh and update model box + // also compute culling spheres for transforms + VectorCopy(mesh->data_vertex3f, mesh->basecullmins); + VectorCopy(mesh->data_vertex3f, mesh->basecullmaxs); + for (vertexindex = 0, v = mesh->data_vertex3f;vertexindex < mesh->num_vertices;vertexindex++, v += 3) { - if (initbox) + mesh->basecullmins[0] = Min(mesh->basecullmins[0], v[0]); + mesh->basecullmins[1] = Min(mesh->basecullmins[1], v[1]); + mesh->basecullmins[2] = Min(mesh->basecullmins[2], v[2]); + mesh->basecullmaxs[0] = Max(mesh->basecullmaxs[0], v[0]); + mesh->basecullmaxs[1] = Max(mesh->basecullmaxs[1], v[1]); + mesh->basecullmaxs[2] = Max(mesh->basecullmaxs[2], v[2]); + if (mesh->data_weightindex4b) { - initbox = false; - VectorCopy(v, b->basecullmins); - VectorCopy(v, b->basecullmaxs); + for (weightindex = 0;weightindex < 4 && mesh->data_weightvalue4b[vertexindex*4+weightindex] > 0;weightindex++) + { + NUint32 index = mesh->data_weightindex4b[vertexindex*4+weightindex]; + Nvec3 v1, v; + Nvec r; + VectorCopy(mesh->data_vertex3f + vertexindex * 3, v1); + Matrix4x4_Transform(&model->data_transforminfo[index].baseinversematrix, v1, v); + r = VectorLength(v); + model->data_transforminfo[index].radius = Max(model->data_transforminfo[index].radius, r); + } } - else - { - b->basecullmins[0] = Min(b->basecullmins[0], v[0]); - b->basecullmins[1] = Min(b->basecullmins[1], v[1]); - b->basecullmins[2] = Min(b->basecullmins[2], v[2]); - b->basecullmaxs[0] = Max(b->basecullmaxs[0], v[0]); - b->basecullmaxs[1] = Max(b->basecullmaxs[1], v[1]); - b->basecullmaxs[2] = Max(b->basecullmaxs[2], v[2]); - } } + if (!meshindex) + { + VectorCopy(mesh->basecullmins, model->basecullmins); + VectorCopy(mesh->basecullmaxs, model->basecullmaxs); + } + else + { + model->basecullmins[0] = Min(model->basecullmins[0], mesh->basecullmins[0]); + model->basecullmins[1] = Min(model->basecullmins[1], mesh->basecullmins[1]); + model->basecullmins[2] = Min(model->basecullmins[2], mesh->basecullmins[2]); + model->basecullmaxs[0] = Max(model->basecullmaxs[0], mesh->basecullmaxs[0]); + model->basecullmaxs[1] = Max(model->basecullmaxs[1], mesh->basecullmaxs[1]); + model->basecullmaxs[2] = Max(model->basecullmaxs[2], mesh->basecullmaxs[2]); + } } } -void Model_Build_Free(Model *b) +void Model_Build_Free(Model *model) { NUint32 i; Model_Mesh *mesh; - for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++) + for (i = 0, mesh = model->data_meshes;i < model->num_meshes;i++, mesh++) { if (mesh->materialname) String_Free(&mesh->materialname); if (mesh->data_element3i) Mem_Free(&mesh->data_element3i); @@ -346,41 +386,41 @@ if (mesh->data_weightvalue4b) Mem_Free(&mesh->data_weightvalue4b); if (mesh->data_collisionbrushes) Collision_Brush_FreeBrushesForTriangleMesh(mesh->data_collisionbrushes, mesh->max_collisionbrushes); } - if (b->data_meshes) - Mem_Free(&b->data_meshes); - memset(b, 0, sizeof(*b)); + if (model->data_meshes) + Mem_Free(&model->data_meshes); + memset(model, 0, sizeof(*model)); } -NUint32 Model_Build_AddSurface(Model *b, Mem_Zone *zone, const char *materialname, NUint32 initialtriangles, NUint32 initialvertices) +NUint32 Model_Build_AddSurface(Model *model, const char *materialname, NUint32 initialtriangles, NUint32 initialvertices) { Model_Mesh *mesh; - if (b->num_meshes >= b->max_meshes) + if (model->num_meshes >= model->max_meshes) { - b->max_meshes = Max(b->max_meshes * 2, 16); - Mem_ReAlloc(Global_Zone, &b->data_meshes, b->max_meshes * sizeof(*b->data_meshes)); + model->max_meshes = Max(model->max_meshes * 2, 16); + Mem_ReAlloc(model->memzone, &model->data_meshes, model->max_meshes * sizeof(*model->data_meshes)); } - mesh = b->data_meshes + b->num_meshes; - String_Set(&mesh->materialname, zone, materialname); + mesh = model->data_meshes + model->num_meshes; + String_Set(&mesh->materialname, model->memzone, materialname); mesh->max_triangles = initialtriangles; mesh->max_vertices = initialvertices; - b->num_meshes++; - return b->num_meshes - 1; + model->num_meshes++; + return model->num_meshes - 1; } -NUint32 Model_Build_AddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t) +NUint32 Model_Build_AddVertex(Model *model, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t) { float *v; - Model_Mesh *mesh = b->data_meshes + meshindex; + Model_Mesh *mesh = model->data_meshes + meshindex; if (mesh->num_vertices >= mesh->max_vertices) { mesh->max_vertices = Max(mesh->max_vertices * 2, 1024); - Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); - Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); - Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); - if (b->isskeletal) + Mem_ReAlloc(model->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); + Mem_ReAlloc(model->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); + Mem_ReAlloc(model->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); + if (model->isskeletal) { - Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); - Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); + Mem_ReAlloc(model->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); + Mem_ReAlloc(model->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); } } v = mesh->data_vertex3f + mesh->num_vertices * 3; @@ -394,7 +434,7 @@ v = mesh->data_texcoord2f + mesh->num_vertices * 2; v[0] = s; v[1] = t; - if (b->isskeletal) + if (model->isskeletal) { NUint8 *wi = mesh->data_weightindex4b + mesh->num_vertices * 4; NUint8 *wf = mesh->data_weightvalue4b + mesh->num_vertices * 4; @@ -411,20 +451,20 @@ return mesh->num_vertices - 1; } -NUint32 Model_Build_AddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb) +NUint32 Model_Build_AddVertexSkeletal(Model *model, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb) { float *v; - Model_Mesh *mesh = b->data_meshes + meshindex; + Model_Mesh *mesh = model->data_meshes + meshindex; if (mesh->num_vertices >= mesh->max_vertices) { mesh->max_vertices = Max(mesh->max_vertices * 2, 1024); - Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); - Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); - Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); - if (b->isskeletal) + Mem_ReAlloc(model->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f)); + Mem_ReAlloc(model->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f)); + Mem_ReAlloc(model->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f)); + if (model->isskeletal) { - Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); - Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); + Mem_ReAlloc(model->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b)); + Mem_ReAlloc(model->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b)); } } v = mesh->data_vertex3f + mesh->num_vertices * 3; @@ -438,7 +478,7 @@ v = mesh->data_texcoord2f + mesh->num_vertices * 2; v[0] = s; v[1] = t; - if (b->isskeletal) + if (model->isskeletal) { NUint8 *wi = mesh->data_weightindex4b + mesh->num_vertices * 4; NUint8 *wf = mesh->data_weightvalue4b + mesh->num_vertices * 4; @@ -449,26 +489,26 @@ return mesh->num_vertices - 1; } -NUint32 Model_Build_FindOrAddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t) +NUint32 Model_Build_FindOrAddVertex(Model *model, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t) { NUint32 i; float *v, *n, *tc; NUint8 *wi, *wf; - Model_Mesh *mesh = b->data_meshes + meshindex; + Model_Mesh *mesh = model->data_meshes + meshindex; for (i = 0, v = mesh->data_vertex3f, n = mesh->data_normal3f, tc = mesh->data_texcoord2f, wi = mesh->data_weightindex4b, wf = mesh->data_weightvalue4b;i < mesh->num_vertices;i++, v += 3, n += 3, tc += 2, wi += 4, wf += 4) if (fabs(v[0] - x) < 0.0001 && fabs(v[1] - y) < 0.0001 && fabs(v[2] - z) < 0.0001 && fabs(n[0] - nx) < 0.0001 && fabs(n[1] - ny) < 0.0001 && fabs(n[2] - nz) < 0.0001 && fabs(tc[0] - s) < 0.0001 && fabs(tc[1] - t) < 0.0001) return i; - return Model_Build_AddVertex(b, meshindex, x, y, z, nx, ny, nz, s, t); + return Model_Build_AddVertex(model, meshindex, x, y, z, nx, ny, nz, s, t); } -NUint32 Model_Build_FindOrAddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb) +NUint32 Model_Build_FindOrAddVertexSkeletal(Model *model, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb) { NUint32 i; float *v, *n, *tc; NUint8 *wi, *wf; - Model_Mesh *mesh = b->data_meshes + meshindex; + Model_Mesh *mesh = model->data_meshes + meshindex; for (i = 0, v = mesh->data_vertex3f, n = mesh->data_normal3f, tc = mesh->data_texcoord2f, wi = mesh->data_weightindex4b, wf = mesh->data_weightvalue4b;i < mesh->num_vertices;i++, v += 3, n += 3, tc += 2, wi += 4, wf += 4) if (fabs(v[0] - x) < 0.0001 && fabs(v[1] - y) < 0.0001 && fabs(v[2] - z) < 0.0001 && fabs(n[0] - nx) < 0.0001 && fabs(n[1] - ny) < 0.0001 && fabs(n[2] - nz) < 0.0001 @@ -476,17 +516,17 @@ && wi[0] == wib[0] && wi[1] == wib[1] && wi[2] == wib[2] && wi[3] == wib[3] && wf[0] == wfb[0] && wf[1] == wfb[1] && wf[2] == wfb[2] && wf[3] == wfb[3]) return i; - return Model_Build_AddVertexSkeletal(b, meshindex, x, y, z, nx, ny, nz, s, t, wib, wfb); + return Model_Build_AddVertexSkeletal(model, meshindex, x, y, z, nx, ny, nz, s, t, wib, wfb); } -NUint32 Model_Build_AddTriangle(Model *b, NUint32 meshindex, int e0, int e1, int e2) +NUint32 Model_Build_AddTriangle(Model *model, NUint32 meshindex, int e0, int e1, int e2) { - Model_Mesh *mesh = b->data_meshes + meshindex; + Model_Mesh *mesh = model->data_meshes + meshindex; NUint32 *e; if (mesh->num_triangles >= mesh->max_triangles) { mesh->max_triangles = Max(mesh->max_triangles * 2, 1024); - Mem_ReAlloc(b->memzone, &mesh->data_element3i, mesh->max_triangles * 3 * sizeof(*mesh->data_element3i)); + Mem_ReAlloc(model->memzone, &mesh->data_element3i, mesh->max_triangles * 3 * sizeof(*mesh->data_element3i)); } e = mesh->data_element3i + mesh->num_triangles * 3; e[0] = e0; @@ -496,7 +536,7 @@ return mesh->num_triangles - 1; } -void Model_Build_Write(Model *b, const char *filename) +static void Model_Build_WriteMD5(Model *model, const char *filename) { // FIXME: this is very unlikely to overflow but it should be made buffer size safe at some point NUint32 i, num; @@ -504,12 +544,12 @@ char *text; Model_Mesh *mesh; textmaxsize = 0x100000; - for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++) + for (i = 0, mesh = model->data_meshes;i < model->num_meshes;i++, mesh++) textmaxsize += mesh->num_vertices * 60 + mesh->num_triangles * 40; textsize = 0; text = Mem_Alloc(Global_Zone, textmaxsize); - textsize += snprintf(text + textsize, textmaxsize - textsize, "MD5Version 10\ncommandline \"\"\n\nnumJoints 1\nnumMeshes %u\n\njoints {\n\t\"ROOT\"\t-1 ( 0.000000 0.000000 0.000000 ) ( 0.000000 0.000000 0.000000 ) // \n}\n", b->num_meshes); - for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++) + textsize += snprintf(text + textsize, textmaxsize - textsize, "MD5Version 10\ncommandline \"\"\n\nnumJoints 1\nnumMeshes %u\n\njoints {\n\t\"ROOT\"\t-1 ( 0.000000 0.000000 0.000000 ) ( 0.000000 0.000000 0.000000 ) // \n}\n", model->num_meshes); + for (i = 0, mesh = model->data_meshes;i < model->num_meshes;i++, mesh++) { if (textmaxsize < textsize + mesh->num_vertices * 100 + mesh->num_triangles * 100 + mesh->num_vertices * 100 + 1000) { @@ -531,8 +571,16 @@ Mem_Free(&text); } -void Model_Build_ImportOBJ(Model *b, const char *inputname, const char *text, const char *textend) +void Model_Build_Write(Model *model, const char *filename) { + if (String_EndsWith(filename, ".md5mesh")) + Model_Build_WriteMD5(model, filename); + else + Console_Printf("Model_Build_Write: %s extension not recognized\n", filename); +} + +static Nbool Model_Build_Import_OBJ(Model *model, Nsize filesize, const char *filedata) +{ NUint32 linenumber = 0; NSint32 meshindex = -1; NUint32 num_vertices = 0, max_vertices = 0; @@ -541,6 +589,8 @@ float *data_vertex3f = NULL; float *data_normal3f = NULL; float *data_texcoord2f = NULL; + const char *text = filedata; + const char *textend = filedata + filesize; while (text < textend) { Nbool comment = false; @@ -586,7 +636,7 @@ num_vertices++; } else - Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3); + Console_Printf("Model_Build_Import_OBJ: %s:%i: command %s takes %i parameters\n", model->filename, linenumber, argv[0], 3); } else if (!String_Compare(argv[0], "vn")) { @@ -604,7 +654,7 @@ num_normals++; } else - Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3); + Console_Printf("Model_Build_Import_OBJ: %s:%i: command %s takes %i parameters\n", model->filename, linenumber, argv[0], 3); } else if (!String_Compare(argv[0], "vt")) { @@ -621,15 +671,15 @@ num_texcoords++; } else - Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 2); + Console_Printf("Model_Build_Import_OBJ: %s:%i: command %s takes %i parameters\n", model->filename, linenumber, argv[0], 2); } else if (!String_Compare(argv[0], "usemtl")) { // usemtl mtrl/chrome if (argc == 2) - meshindex = Model_Build_AddSurface(b, Global_Zone, argv[1], 0, 0); + meshindex = Model_Build_AddSurface(model, argv[1], 0, 0); else - Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); + Console_Printf("Model_Build_Import_OBJ: %s:%i: command %s takes %i parameters\n", model->filename, linenumber, argv[0], 1); } else if (!String_Compare(argv[0], "f")) { @@ -639,7 +689,7 @@ if (argc >= 4) { if (meshindex == -1) - meshindex = Model_Build_AddSurface(b, Global_Zone, "default", 0, 0); + meshindex = Model_Build_AddSurface(model, "default", 0, 0); for (i = 0;i < argc - 1;i++) { NUint32 j; @@ -670,7 +720,7 @@ if (k >= 0 && k < num_vertices) VectorCopy(data_vertex3f + k * 3, v); else - Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face vertex index (parameter #%i)\n", inputname, linenumber, i + 1); + Console_Printf("Model_Build_Import_OBJ: %s:%i: invalid face vertex index (parameter #%i)\n", model->filename, linenumber, i + 1); break; case 1: if (k < 0) @@ -680,7 +730,7 @@ if (k >= 0 && k < num_texcoords) Vector2Copy(data_texcoord2f + k * 2, tc); else - Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face texcoord index (parameter #%i)\n", inputname, linenumber, i + 1); + Console_Printf("Model_Build_Import_OBJ: %s:%i: invalid face texcoord index (parameter #%i)\n", model->filename, linenumber, i + 1); break; case 2: if (k < 0) @@ -690,7 +740,7 @@ if (k >= 0 && k < num_normals) VectorCopy(data_normal3f + k * 3, vn); else - Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face vertexnormal index (parameter #%i)\n", inputname, linenumber, i + 1); + Console_Printf("Model_Build_Import_OBJ: %s:%i: invalid face vertexnormal index (parameter #%i)\n", model->filename, linenumber, i + 1); break; } } @@ -707,35 +757,35 @@ s++; } } - indices[i] = Model_Build_FindOrAddVertex(b, meshindex, v[0], v[1], v[2], vn[0], vn[1], vn[2], tc[0], tc[1]); + indices[i] = Model_Build_FindOrAddVertex(model, meshindex, v[0], v[1], v[2], vn[0], vn[1], vn[2], tc[0], tc[1]); // make a triangle fan if we have enough vertices if (i >= 2) - Model_Build_AddTriangle(b, meshindex, indices[0], indices[i-1], indices[i]); + Model_Build_AddTriangle(model, meshindex, indices[0], indices[i], indices[i-1]); } } else - Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i or more parameters\n", inputname, linenumber, argv[0], 3); + Console_Printf("Model_Build_Import_OBJ: %s:%i: command %s takes %i or more parameters\n", model->filename, linenumber, argv[0], 3); } else if (!String_Compare(argv[0], "o")) { // o cylinder1 if (argc != 2) - Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); + Console_Printf("Model_Build_Import_OBJ: %s:%i: command %s takes %i parameters\n", model->filename, linenumber, argv[0], 1); } else if (!String_Compare(argv[0], "mtllib")) { // mtllib zrail2.mtl if (argc != 2) - Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); + Console_Printf("Model_Build_Import_OBJ: %s:%i: command %s takes %i parameters\n", model->filename, linenumber, argv[0], 1); } else if (!String_Compare(argv[0], "g")) { // g cylinder1_mtrl/invisible if (argc != 2) - Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1); + Console_Printf("Model_Build_Import_OBJ: %s:%i: command %s takes %i parameters\n", model->filename, linenumber, argv[0], 1); } else - Console_Printf("Model_Build_ImportOBJ: %s:%i: unknown obj command %s\n", inputname, linenumber, argv[0]); + Console_Printf("Model_Build_Import_OBJ: %s:%i: unknown obj command %s\n", model->filename, linenumber, argv[0]); } if (data_vertex3f) Mem_Free(&data_vertex3f); @@ -743,6 +793,7 @@ Mem_Free(&data_normal3f); if (data_texcoord2f) Mem_Free(&data_texcoord2f); + return false; } /* example clips of an MD5 model @@ -782,50 +833,41 @@ } Model_MD5_Weight; -void Model_Load(ResourceEntry *r) +static Nbool Model_Build_Import_MD5(Model *model, Nsize filesize, const char *filedata) { Util_ParseC_Thread thread; NUint32 meshnum, version, numjoints = 0; Nbool error; - Nsize filesize; - Model *model; - char *filedata; Nbool isskeletal = false; - model = Mem_Alloc(r->memzone, sizeof(Model)); - - filedata = File_LoadFile(r->name, &filesize); - if (!filedata) - return; - Util_ParseC_SetUpThread(&thread, filedata, filesize); #define Abort() { error = true; break; } #define LoadValue(var, errstr) if (thread.type != UTIL_PARSEC_TOKENTYPE_VALUE) { \ - Console_Printf("Model_Load: Expected value " errstr "\n"); Abort(); \ + Console_Printf("Model_Build_Import_MD5: Expected value " errstr "\n"); Abort(); \ } else \ (var) = thread.value, Util_ParseC_Lex(&thread) #define LoadInt(var, errstr) if (thread.type != UTIL_PARSEC_TOKENTYPE_VALUE) { \ - Console_Printf("Model_Load: Expected integer " errstr "\n"); Abort(); \ + Console_Printf("Model_Build_Import_MD5: Expected integer " errstr "\n"); Abort(); \ } else \ (var) = thread.value, Util_ParseC_Lex(&thread) #define LoadString(var, errstr) if (thread.type != UTIL_PARSEC_TOKENTYPE_STRING) { \ - Console_Printf("Model_Load: Expected string " errstr "\n"); Abort(); \ + Console_Printf("Model_Build_Import_MD5: Expected string " errstr "\n"); Abort(); \ } else \ - String_Set( &(var), r->memzone, thread.token), Util_ParseC_Lex(&thread) + String_Set( &(var), model->memzone, thread.token), Util_ParseC_Lex(&thread) #define ExpectKeyword(str, errstr) if (!Util_ParseC_MatchName(&thread, (str))) { \ - Console_Printf("Model_Load: Expected '" str "' " errstr "\n"); Abort(); } + Console_Printf("Model_Build_Import_MD5: Expected '" str "' " errstr "\n"); Abort(); } version = 0; meshnum = 0; error = false; - VectorClear(model->basecullmins); - VectorClear(model->basecullmaxs); - + // FIXME: this code should probably use more of the Model_Build_ functions + // where possible, to allow importing additional geometry into an existing + // model structure while (!error && thread.type != UTIL_PARSEC_TOKENTYPE_EOF) { //MD5Version 10 @@ -834,7 +876,7 @@ LoadInt(version, "after 'MD5Version'"); if (version != 10) { - Console_Printf("Model_Load: MD5Version %i not supported\n", version); + Console_Printf("Model_Build_Import_MD5: MD5Version %i not supported\n", version); Abort(); } } @@ -849,7 +891,7 @@ LoadInt(numjoints, "after 'numJoints'"); if (numjoints < 1) { - Console_Printf("Model_Load: numJoints %i < 1\n", numjoints); + Console_Printf("Model_Build_Import_MD5: numJoints %i < 1\n", numjoints); Abort(); } if (numjoints > 1) @@ -857,7 +899,7 @@ isskeletal = true; model->num_transforms = numjoints; model->max_transforms = model->num_transforms; - model->data_transforminfo = Mem_Alloc(r->memzone, model->max_transforms * sizeof(*model->data_transforminfo)); + model->data_transforminfo = Mem_Alloc(model->memzone, model->max_transforms * sizeof(*model->data_transforminfo)); } } //numMeshes 1 @@ -866,11 +908,11 @@ LoadInt(model->num_meshes, "after 'numMeshes'"); if (model->num_meshes < 1) { - Console_Printf("Model_Load: numMeshes %i < 1\n", model->num_meshes); + Console_Printf("Model_Build_Import_MD5: numMeshes %i < 1\n", model->num_meshes); Abort(); } model->max_meshes = model->num_meshes; - model->data_meshes = Mem_Alloc(r->memzone, model->max_meshes * sizeof(Model_Mesh)); + model->data_meshes = Mem_Alloc(model->memzone, model->max_meshes * sizeof(Model_Mesh)); } //joints { // "root" -1 ( 0.000000 0.000000 0.000000 ) ( -0.707107 -0.000000 -0.000000 ) // @@ -902,7 +944,7 @@ if (parent >= (NSint32)jointnum) { String_Free(&name); - Console_Printf("Model_Load: joint.parent (%i) >= joint (%i)\n", parent, jointnum); + Console_Printf("Model_Build_Import_MD5: joint.parent (%i) >= joint (%i)\n", parent, jointnum); Abort(); } if (isskeletal) @@ -916,7 +958,7 @@ String_Free(&name); if (jointnum != numjoints) { - Console_Printf("Model_Load: final jointnum (%i) != numJoints (%i)\n", jointnum, numjoints); + Console_Printf("Model_Build_Import_MD5: final jointnum (%i) != numJoints (%i)\n", jointnum, numjoints); Abort(); } } @@ -933,7 +975,7 @@ ExpectKeyword("{", "after 'mesh'"); if (meshnum >= model->num_meshes) { - Console_Printf("Model_Load: meshnum (%i) >= nummeshes (%i)\n", meshnum, model->num_meshes); + Console_Printf("Model_Build_Import_MD5: meshnum (%i) >= nummeshes (%i)\n", meshnum, model->num_meshes); Abort(); } mesh = model->data_meshes + meshnum; @@ -952,22 +994,22 @@ LoadInt(mesh->num_vertices, "after 'numverts'"); if (mesh->num_vertices < 3) { - Console_Printf("Model_Load: numverts (%i) < 3\n", mesh->num_vertices); + Console_Printf("Model_Build_Import_MD5: numverts (%i) < 3\n", mesh->num_vertices); Abort(); } mesh->max_vertices = mesh->num_vertices; - mesh->data_vertex3f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[3])); - mesh->data_svector3f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[3])); - mesh->data_tvector3f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[3])); - mesh->data_normal3f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[3])); - mesh->data_texcoord2f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[2])); - mesh->data_lightmaptexcoord2f = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(float[2])); + mesh->data_vertex3f = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(float[3])); + mesh->data_svector3f = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(float[3])); + mesh->data_tvector3f = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(float[3])); + mesh->data_normal3f = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(float[3])); + mesh->data_texcoord2f = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(float[2])); + mesh->data_lightmaptexcoord2f = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(float[2])); if (isskeletal) { - mesh->data_weightindex4b = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(NUint8[4])); - mesh->data_weightvalue4b = Mem_Alloc(r->memzone, mesh->max_vertices * sizeof(NUint8[4])); + mesh->data_weightindex4b = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(NUint8[4])); + mesh->data_weightvalue4b = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(NUint8[4])); } - md5weightrange = Mem_Alloc(Global_Zone, mesh->max_vertices * sizeof(NUint32[2])); + md5weightrange = Mem_Alloc(model->memzone, mesh->max_vertices * sizeof(NUint32[2])); } // vert 0 ( 0.142532 0.983877 ) 0 1 // vert 1 ( 0.155314 0.987100 ) 1 1 @@ -979,7 +1021,7 @@ LoadInt(vertexnum, "after 'vert'"); if (vertexnum >= mesh->num_vertices) { - Console_Printf("Model_Load: vert (%i) >= numverts (%i)\n", vertexnum, mesh->num_vertices); + Console_Printf("Model_Build_Import_MD5: vert (%i) >= numverts (%i)\n", vertexnum, mesh->num_vertices); Abort(); } // ( @@ -1002,13 +1044,13 @@ LoadInt(mesh->num_triangles, "after 'numtris'"); if (mesh->num_triangles < 1) { - Console_Printf("Model_Load: numtris (%i) < 1\n", mesh->num_triangles); + Console_Printf("Model_Build_Import_MD5: numtris (%i) < 1\n", mesh->num_triangles); Abort(); } mesh->max_triangles = mesh->num_triangles; - mesh->data_element3i = Mem_Alloc(r->memzone, mesh->max_triangles * sizeof(NUint32[3])); - mesh->data_neighbor3i = Mem_Alloc(r->memzone, mesh->max_triangles * sizeof(NSint32[3])); - mesh->data_plane4f = Mem_Alloc(r->memzone, mesh->max_triangles * sizeof(float[4])); + mesh->data_element3i = Mem_Alloc(model->memzone, mesh->max_triangles * sizeof(NUint32[3])); + mesh->data_neighbor3i = Mem_Alloc(model->memzone, mesh->max_triangles * sizeof(NSint32[3])); + mesh->data_plane4f = Mem_Alloc(model->memzone, mesh->max_triangles * sizeof(float[4])); } // tri 0 29 30 31 // tri 1 32 29 76 @@ -1019,7 +1061,7 @@ LoadInt(trianglenum, "after 'tri'"); if (trianglenum >= mesh->num_triangles) { - Console_Printf("Model_Load: tri (%i) >= numtris (%i)\n", trianglenum, mesh->num_triangles); + Console_Printf("Model_Build_Import_MD5: tri (%i) >= numtris (%i)\n", trianglenum, mesh->num_triangles); Abort(); } // TODO: boundscheck elements @@ -1035,7 +1077,7 @@ LoadInt(md5numweights, "after 'numweights'"); if (md5numweights < 1) { - Console_Printf("Model_Load: numweights (%i) < 1\n", md5numweights); + Console_Printf("Model_Build_Import_MD5: numweights (%i) < 1\n", md5numweights); Abort(); } md5weights = Mem_Alloc(Global_Zone, md5numweights * sizeof(Model_MD5_Weight)); @@ -1051,7 +1093,7 @@ LoadInt(weightnum, "after 'weight'"); if (weightnum >= md5numweights) { - Console_Printf("Model_Load: weight (%i) >= numweights (%i)\n", weightnum, md5numweights); + Console_Printf("Model_Build_Import_MD5: weight (%i) >= numweights (%i)\n", weightnum, md5numweights); Abort(); } md5weight = md5weights + weightnum; @@ -1059,7 +1101,7 @@ LoadInt(md5weight->jointnum, "(weight jointnum)"); if (md5weight->jointnum >= numjoints) { - Console_Printf("Model_Load: joint (%i) >= numjoints (%i)\n", md5weight->jointnum, numjoints); + Console_Printf("Model_Build_Import_MD5: joint (%i) >= numjoints (%i)\n", md5weight->jointnum, numjoints); Abort(); } // 1.000000 @@ -1147,63 +1189,6 @@ for (i = 0;i < mesh->num_vertices;i++) VectorCopy(md5weights[md5weightrange[i*2+0]].vertex, mesh->data_vertex3f + i*3); } - // compile the base frame of the mesh for static uses - Model_MeshNormals(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f); - Model_MeshTangents(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f, mesh->data_svector3f, mesh->data_tvector3f); - Model_MeshNeighbors(mesh->num_triangles, mesh->data_element3i, mesh->data_neighbor3i, mesh->num_vertices); - Model_BuildTrianglePlanes(mesh->data_vertex3f, mesh->num_triangles, mesh->data_element3i, mesh->data_plane4f); - // collision brushes are for the static frame - // TODO: load separate collision brush file for faster collisions? - mesh->num_collisionbrushes = mesh->num_triangles; - mesh->max_collisionbrushes = mesh->num_collisionbrushes; - mesh->data_collisionbrushes = Collision_Brush_AllocBrushesForTriangleMesh(r->memzone, mesh->max_triangles); - Collision_Brush_UpdateTriangleMeshBrushes(mesh->data_collisionbrushes, mesh->num_triangles, mesh->data_element3i, mesh->data_vertex3f); - // calculate culling shapes - for (i = 0;i < mesh->num_vertices;i++) - { - NUint32 k; - if (!i && !meshnum) - { - VectorCopy(mesh->data_vertex3f, model->basecullmins); - VectorCopy(mesh->data_vertex3f, model->basecullmaxs); - } - else - { - model->basecullmins[0] = Min(model->basecullmins[0], mesh->data_vertex3f[i * 3 + 0]); - model->basecullmins[1] = Min(model->basecullmins[1], mesh->data_vertex3f[i * 3 + 1]); - model->basecullmins[2] = Min(model->basecullmins[2], mesh->data_vertex3f[i * 3 + 2]); - model->basecullmaxs[0] = Max(model->basecullmaxs[0], mesh->data_vertex3f[i * 3 + 0]); - model->basecullmaxs[1] = Max(model->basecullmaxs[1], mesh->data_vertex3f[i * 3 + 1]); - model->basecullmaxs[2] = Max(model->basecullmaxs[2], mesh->data_vertex3f[i * 3 + 2]); - } - if (!i) - { - VectorCopy(mesh->data_vertex3f, mesh->basecullmins); - VectorCopy(mesh->data_vertex3f, mesh->basecullmaxs); - } - else - { - mesh->basecullmins[0] = Min(mesh->basecullmins[0], mesh->data_vertex3f[i * 3 + 0]); - mesh->basecullmins[1] = Min(mesh->basecullmins[1], mesh->data_vertex3f[i * 3 + 1]); - mesh->basecullmins[2] = Min(mesh->basecullmins[2], mesh->data_vertex3f[i * 3 + 2]); - mesh->basecullmaxs[0] = Max(mesh->basecullmaxs[0], mesh->data_vertex3f[i * 3 + 0]); - mesh->basecullmaxs[1] = Max(mesh->basecullmaxs[1], mesh->data_vertex3f[i * 3 + 1]); - mesh->basecullmaxs[2] = Max(mesh->basecullmaxs[2], mesh->data_vertex3f[i * 3 + 2]); - } - if (isskeletal) - { - for (k = 0;k < 4 && mesh->data_weightvalue4b[i*4+k] > 0;k++) - { - NUint32 index = mesh->data_weightindex4b[i*4+k]; - Nvec3 v1, v; - Nvec r; - VectorCopy(mesh->data_vertex3f + i * 3, v1); - Matrix4x4_Transform(&model->data_transforminfo[index].baseinversematrix, v1, v); - r = VectorLength(v); - model->data_transforminfo[index].radius = Max(model->data_transforminfo[index].radius, r); - } - } - } Mem_Free(&md5weights); Mem_Free(&md5weightrange); meshnum++; @@ -1212,17 +1197,55 @@ } Util_ParseC_CleanUpThread(&thread); Mem_Free(&filedata); - // if there was a load error, don't point to the Model so nothing will try - // to use the incomplete data - if (!error) - r->data = model; #undef Abort #undef LoadInt #undef LoadValue #undef LoadString #undef ExpectKeyword + return error; } +Nbool Model_Build_Import(Model *model, Nsize filesize, const char *filedata) +{ + Nbool error = false; + if (String_EndsWith(model->filename, ".obj")) + error = Model_Build_Import_OBJ(model, filesize, filedata); + else if (String_EndsWith(model->filename, ".md5mesh")) + error = Model_Build_Import_MD5(model, filesize, filedata); + else + { + Console_Printf("Model_Build_Import_MD5: %s extension not recognized\n", model->filename); + error = true; + } + return error; +} + +void Model_Load(ResourceEntry *r) +{ + Nsize filesize; + Model *model; + Nbool error; + char *filedata; + + filedata = File_LoadFile(r->name, &filesize); + if (!filedata) + return; + + model = Mem_Alloc(r->memzone, sizeof(Model)); + Model_Build_Begin(model, r->name, r->memzone, false); + + error = Model_Build_Import(model, filesize, filedata); + + // if there was a load error, don't point to the Model so nothing will try + // to use the incomplete data + if (!error) + { + Model_Build_Compile(model, true, true, true, true, true, true); + r->data = model; + } +} + + void Model_Unload(UNUSED ResourceEntry *r) { // freeing of the memzone will get rid of the model Modified: trunk/model.h =================================================================== --- trunk/model.h 2006-05-12 11:03:18 UTC (rev 715) +++ trunk/model.h 2006-05-12 11:04:48 UTC (rev 716) @@ -81,6 +81,7 @@ typedef struct Model { // set at the creation of the Model + char filename[64]; Mem_Zone *memzone; Nbool isskeletal; @@ -99,20 +100,20 @@ } Model; +Nbool Model_Build_Import(Model *model, Nsize filesize, const char *filedata); void Model_Load(ResourceEntry *r); void Model_Unload(ResourceEntry *r); -void Model_Build_Begin(Model *b, Mem_Zone *memzone, Nbool isskeletal); -void Model_Build_Compile(Model *b, Nbool generateneighbors, Nbool generateplanes, Nbool generatenormals, Nbool generatetangents, Nbool generatelightmaptexcoords, Nbool generatecollisionbrushes); -void Model_Build_Free(Model *b); -NUint32 Model_Build_AddSurface(Model *b, Mem_Zone *zone, const char *materialname, NUint32 initialtriangles, NUint32 initialvertices); -NUint32 Model_Build_AddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t); -NUint32 Model_Build_AddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb); -NUint32 Model_Build_FindOrAddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t); -NUint32 Model_Build_FindOrAddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb); -NUint32 Model_Build_AddTriangle(Model *b, NUint32 meshindex, int e0, int e1, int e2); -void Model_Build_Write(Model *b, const char *filename); -void Model_Build_ImportOBJ(Model *b, const char *inputname, const char *text, const char *textend); +void Model_Build_Begin(Model *model, const char *filename, Mem_Zone *memzone, Nbool isskeletal); +void Model_Build_Compile(Model *model, Nbool generateneighbors, Nbool generateplanes, Nbool generatenormals, Nbool generatetangents, Nbool generatelightmaptexcoords, Nbool generatecollisionbrushes); +void Model_Build_Free(Model *model); +NUint32 Model_Build_AddSurface(Model *model, const char *materialname, NUint32 initialtriangles, NUint32 initialvertices); +NUint32 Model_Build_AddVertex(Model *model, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t); +NUint32 Model_Build_AddVertexSkeletal(Model *model, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb); +NUint32 Model_Build_FindOrAddVertex(Model *model, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t); +NUint32 Model_Build_FindOrAddVertexSkeletal(Model *model, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb); +NUint32 Model_Build_AddTriangle(Model *model, NUint32 meshindex, int e0, int e1, int e2); +void Model_Build_Write(Model *model, const char *filename); // this function decodes skeletal vertex information to your supplied arrays // NOTE: outplane4f requires outvertex3f Modified: trunk/nstring.c =================================================================== --- trunk/nstring.c 2006-05-12 11:03:18 UTC (rev 715) +++ trunk/nstring.c 2006-05-12 11:04:48 UTC (rev 716) @@ -269,6 +269,18 @@ return strncasecmp(s ? s : "", t ? t : "", n); } +Nbool String_EndsWith(const char *s, const char *t) +{ + Nsize i; + Nsize slen = String_Length(s); + Nsize tlen = String_Length(t); + if (tlen && slen >= tlen) + for (i = 0;i <= slen - tlen;i++) + if (!String_Compare(s + i, t)) + return true; + return false; +} + void String_ToLower(char *s) { if( !s ) Modified: trunk/nstring.h =================================================================== --- trunk/nstring.h 2006-05-12 11:03:18 UTC (rev 715) +++ trunk/nstring.h 2006-05-12 11:04:48 UTC (rev 716) @@ -29,6 +29,7 @@ NSint String_ICompare(const char *s, const char *t); NSint String_NCompare(const char *s, const char *t, Nsize n); NSint String_NICompare(const char *s, const char *t, Nsize n); +Nbool String_EndsWith(const char *s, const char *t); Nsize String_Length(const char *s); Modified: trunk/util.c =================================================================== --- trunk/util.c 2006-05-12 11:03:18 UTC (rev 715) +++ trunk/util.c 2006-05-12 11:04:48 UTC (rev 716) @@ -248,7 +248,7 @@ const char *basename, *imagename, *materialname; char *tilename; Nvec terrainsize[3], texturesize[2], terrainscale[3], terrainorigin[3], texturescale[2]; - Model b; + Model model; basename = Shell_Callback_GetArg(1); imagename = Shell_Callback_GetArg(2); tilesize = (int) Shell_Callback_GetArgValue(3); @@ -280,12 +280,14 @@ terrainorigin[2] = terrainsize[2] * -0.5; tileswidth = width / tilesize; tilesheight = height / tilesize; - Model_Build_Begin(&b, Global_Zone, false); + tilename = String_APrintf(Global_Zone, "%s.md5mesh", basename); + Model_Build_Begin(&model, tilename, Global_Zone, false); + String_Free(&tilename); for (by = 0;by < height;by += tilesize) { for (bx = 0;bx < width;bx += tilesize) { - NUint32 meshindex = Model_Build_AddSurface(&b, Global_Zone, materialname, 0, 0); + NUint32 meshindex = Model_Build_AddSurface(&model, materialname, 0, 0); tilewidth = Bound(0, width - bx, tilesize+2); tileheight = Bound(0, height - by, tilesize+2); for (ty = 0, num = 0;ty < tileheight;ty++) @@ -305,7 +307,7 @@ p = pixels + (pyi * width + pxi) * 4; pz = ((p[0]+p[1]+p[2])*(1.0-pxf)+(p[4]+p[5]+p[6])*(pxf))*(1.0-pyf)+((p[w+0]+p[w+1]+p[w+2])*(1.0-pxf)+(p[w+4]+p[w+5]+p[w+6])*(pxf))*(pyf); // FIXME: this SHOULD calculate a valid mesh normal!! - Model_Build_AddVertex(&b, meshindex, px * terrainscale[0] + terrainorigin[0], py * terrainscale[1] + terrainorigin[1], pz * terrainscale[2] + terrainorigin[2], 0, 0, 1, (px * terrainscale[0] + terrainorigin[0]) * texturescale[0], (py * terrainscale[1] + terrainorigin[1]) * texturescale[1]); + Model_Build_AddVertex(&model, meshindex, px * terrainscale[0] + terrainorigin[0], py * terrainscale[1] + terrainorigin[1], pz * terrainscale[2] + terrainorigin[2], 0, 0, 1, (px * terrainscale[0] + terrainorigin[0]) * texturescale[0], (py * terrainscale[1] + terrainorigin[1]) * texturescale[1]); } } for (ty = 0, num = 0;ty < tileheight-1;ty++) @@ -313,17 +315,15 @@ for (tx = 0;tx < tilewidth-1;tx++, num += 6) { NUint32 i = ty*tilewidth+tx; - Model_Build_AddTriangle(&b, meshindex, i, i+1, i+1+tilewidth); - Model_Build_AddTriangle(&b, meshindex, i, i+1+tilewidth, i+tilewidth); + Model_Build_AddTriangle(&model, meshindex, i, i+1, i+1+tilewidth); + Model_Build_AddTriangle(&model, meshindex, i, i+1+tilewidth, i+tilewidth); } } } } Mem_Free(&pixels); - tilename = String_APrintf(Global_Zone, "%s.md5mesh", basename); - Model_Build_Write(&b, tilename); - String_Free(&tilename); - Model_Build_Free(&b); + Model_Build_Write(&model, model.filename); + Model_Build_Free(&model); } static Shell_SymbolDecl Util_Shell_MakeTerrain_Decl = { @@ -336,33 +336,33 @@ (Shell_Symbol_Callback) Util_Shell_MakeTerrain }; -static void Util_Shell_ConvertOBJ(void) +static void Util_Shell_ConvertModel(void) { - Nsize objtextsize; - Model b; + Nsize filesize; + Model model; const char *inputname = Shell_Callback_GetArg(1); const char *outputname = Shell_Callback_GetArg(2); - char *objtext = File_LoadFile(inputname, &objtextsize); - if (!objtext) + char *filedata = File_LoadFile(inputname, &filesize); + if (!filedata) { - Shell_Callback_ThrowError("Could not open OBJ file\n"); + Shell_Callback_ThrowError("Could not open model file\n"); // SHELLTODO return; } - Model_Build_Begin(&b, Global_Zone, false); - Model_Build_ImportOBJ(&b, inputname, objtext, objtext + objtextsize); - Model_Build_Write(&b, outputname); - Model_Build_Free(&b); - Mem_Free(&objtext); + Model_Build_Begin(&model, inputname, Global_Zone, false); + if (!Model_Build_Import(&model, filesize, filedata)) + Model_Build_Write(&model, outputname); + Model_Build_Free(&model); + Mem_Free(&filedata); } -static Shell_SymbolDecl Util_Shell_ConvertOBJ_Decl = { - "util_convertobj", - "Turn a .obj model into a .md5mesh model file.", - "Usage: util_convertobj \n" - "Example: util_convertobj maps/mymap/mymodel.obj maps/mymap/mymodel.md5mesh", +static Shell_SymbolDecl Util_Shell_ConvertModel_Decl = { + "util_convertmodel", + "Convert a model from any supported format to any other.", + "Usage: util_convertmodel \n" + "Example: util_convertmodel maps/mymap/mymodel.obj maps/mymap/mymodel.md5mesh", "ss", - (Shell_Symbol_Callback) Util_Shell_ConvertOBJ + (Shell_Symbol_Callback) Util_Shell_ConvertModel }; @@ -635,32 +635,32 @@ double boxsize; const char *basefilename, *baseimagename; char *filename; - Model b; + Model model; basefilename = Shell_Callback_GetArg(1); baseimagename = Shell_Callback_GetArg(2); boxsize = atof(Shell_Callback_GetArg(3)); - Model_Build_Begin(&b, 0, 0); + filename = String_APrintf(Global_Zone, "%s.md5mesh", basefilename); + Model_Build_Begin(&model, filename, Global_Zone, false); + String_Free(&filename); for (i = 0;i < 6;i++) { NUint32 j; NUint32 indices[4]; char *materialname = String_APrintf(Global_Zone, "%s_%s", baseimagename, skyboxsuffix[i]); - NUint32 meshindex = Model_Build_AddSurface(&b, Global_Zone, materialname, 2, 4); + NUint32 meshindex = Model_Build_AddSurface(&model, materialname, 2, 4); String_Free(&materialname); for (j = 0;j < 4;j++) - indices[j] = Model_Build_FindOrAddVertex(&b, meshindex, skyboxvertex[i][j][0], skyboxvertex[i][j][1], skyboxvertex[i][j][2], skyboxvertex[i][j][3], skyboxvertex[i][j][4], skyboxvertex[i][j][5], skyboxvertex[i][j][6], skyboxvertex[i][j][7]); - Model_Build_AddTriangle(&b, meshindex, indices[0], indices[2], indices[1]); - Model_Build_AddTriangle(&b, meshindex, indices[0], indices[3], indices[2]); + indices[j] = Model_Build_FindOrAddVertex(&model, meshindex, skyboxvertex[i][j][0], skyboxvertex[i][j][1], skyboxvertex[i][j][2], skyboxvertex[i][j][3], skyboxvertex[i][j][4], skyboxvertex[i][j][5], skyboxvertex[i][j][6], skyboxvertex[i][j][7]); + Model_Build_AddTriangle(&model, meshindex, indices[0], indices[2], indices[1]); + Model_Build_AddTriangle(&model, meshindex, indices[0], indices[3], indices[2]); } - filename = String_APrintf(Global_Zone, "%s.md5mesh", basefilename); - Model_Build_Write(&b, filename); - String_Free(&filename); - Model_Build_Free(&b); + Model_Build_Write(&model, model.filename); + Model_Build_Free(&model); } static Shell_SymbolDecl Util_Shell_MakeSkyBox_Decl = { "util_makeskybox", - "Make an skybox md5mesh file.", + "Make a skybox md5mesh file.", "Usage: util_makeskybox \n" "Example: util_makeskybox maps/mymap/sunnyday maps/mymap/sunnyday 30000\n" "would produce a file named maps/mymap/sunnyday.md5mesh containing 6 meshes for maps/mymap/sunnyday_px.tga and _nx, _py, _ny, _pz, _nz, forming a box +-100000m in each direction", @@ -672,7 +672,7 @@ { Shell_RegisterFunction(&Util_Shell_MakeTerrain_Decl); Shell_RegisterFunction(&Util_Shell_MakeSkyBox_Decl); - Shell_RegisterFunction(&Util_Shell_ConvertOBJ_Decl); + Shell_RegisterFunction(&Util_Shell_ConvertModel_Decl); } void Util_Quit(void) From lordhavoc at icculus.org Fri May 12 07:19:17 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 12 May 2006 07:19:17 -0400 Subject: r717 - trunk Message-ID: <20060512111917.962.qmail@icculus.org> Author: lordhavoc Date: 2006-05-12 07:19:17 -0400 (Fri, 12 May 2006) New Revision: 717 Modified: trunk/model.c Log: now preserves smooth shading across texture seams in obj models that contain vertex normals Modified: trunk/model.c =================================================================== --- trunk/model.c 2006-05-12 11:04:48 UTC (rev 716) +++ trunk/model.c 2006-05-12 11:19:17 UTC (rev 717) @@ -1240,7 +1240,12 @@ // to use the incomplete data if (!error) { - Model_Build_Compile(model, true, true, true, true, true, true); + // generate new vertex normals if the loaded model does not have any + // (we detect this by checking if the first vertex's normal is + // zero-length or if the array is missing entirely) + Nbool generatenormals = !model->data_meshes || !model->data_meshes[0].data_normal3f || !VectorLength2(model->data_meshes[0].data_normal3f); + Nbool generatetangents = !model->data_meshes || !model->data_meshes[0].data_svector3f || !VectorLength2(model->data_meshes[0].data_svector3f); + Model_Build_Compile(model, true, true, generatenormals, generatetangents, true, true); r->data = model; } } From lordhavoc at icculus.org Fri May 12 08:34:10 2006 From: lordhavoc at icculus.org (lordhavoc at icculus.org) Date: 12 May 2006 08:34:10 -0400 Subject: r718 - in trunk: . game Message-ID: <20060512123410.11844.qmail@icculus.org> Author: lordhavoc Date: 2006-05-12 08:34:09 -0400 (Fri, 12 May 2006) New Revision: 718 Modified: trunk/game/g_entity.c trunk/game/g_entityclass.c trunk/mathlib.h Log: turned IsNAN into a macro in mathlib.h and moved the NAN velocity checks to G_Entity_PlayerPhysics Modified: trunk/game/g_entity.c =================================================================== --- trunk/game/g_entity.c 2006-05-12 11:19:17 UTC (rev 717) +++ trunk/game/g_entity.c 2006-05-12 12:34:09 UTC (rev 718) @@ -506,8 +506,12 @@ void G_Entity_PlayerPhysics(G_Entity *self, Nvec3 wishvel, Nvec groundfriction, Nvec groundaccel, Nvec groundstopspeed, Nvec airfriction, Nvec airaccel, Nvec airstopspeed, Nvec jumpspeed, Nvec gravityscale, Nvec3 thrustvel) { + NUint32 j; Nvec f; Nvec3 gravityimpulse, countergravityimpulse; + for (j = 0; j < 3; j++) + if (IS_NAN(self->position.velocity[j])) + self->position.velocity[j] = 0; VectorScale(G.globalgravity, G.frametime * gravityscale, gravityimpulse); if (self->groundentity) { @@ -575,6 +579,9 @@ } if (thrustvel) VectorMA(self->position.velocity, G.frametime, thrustvel, self->position.velocity); + for (j = 0; j < 3; j++) + if (IS_NAN(self->position.velocity[j])) + self->position.velocity[j] = 0; } static Collision_Brush boxbrush; Modified: trunk/game/g_entityclass.c =================================================================== --- trunk/game/g_entityclass.c 2006-05-12 11:19:17 UTC (rev 717) +++ trunk/game/g_entityclass.c 2006-05-12 12:34:09 UTC (rev 718) @@ -100,15 +100,6 @@ { } -Nbool IsNAN(float f) -{ - return (*((int*)&f)&0x7fc00000) == 0x7fc00000; -} -//Nbool IsNAN(double f) -//{ -// return (*((int*)&f)&0x7fe00000) == 0x7fe00000; -//} - static void G_Object_Infantry_Frame(G_Entity *self) { NUint32 buttonbits; @@ -163,15 +154,6 @@ else G_Entity_PlayerPhysics(self, rotatedmovement, self->eclass->friction, self->eclass->acceleration, self->eclass->stopspeed, self->eclass->airfriction, self->eclass->airacceleration, self->eclass->airstopspeed, (buttonbits & G_BUTTON_MOVEUP) ? self->eclass->jumpvelocity : 0, 1, NULL); - { - int j; - for (j = 0; j < 3; j++) - { - if (IsNAN(self->position.velocity[j])) - self->position.velocity[j] = 0; - } - } - G_Entity_Move(self, user->noclipmode ? 0 : G_SCOPE_BLOCK_PLAYER, self->eclass->stepheight, 0); //Matrix4x4_ConcatQuakeEntity(&self->position.m, movement[0], movement[1], movement[2], turn[0], turn[1], turn[2], 1); Modified: trunk/mathlib.h =================================================================== --- trunk/mathlib.h 2006-05-12 11:19:17 UTC (rev 717) +++ trunk/mathlib.h 2006-05-12 12:34:09 UTC (rev 718) @@ -2,6 +2,7 @@ #ifndef MATHLIB_H #define MATHLIB_H +#define IS_NAN(x) (((*(int *)&x)&0x7fc00000) == 0x7fc00000) #define Min( a, b ) ( ((a) < (b)) ? (a) : (b) ) #define Max( a, b ) ( ((a) > (b)) ? (a) : (b) ) From sajt at icculus.org Sun May 14 22:07:33 2006 From: sajt at icculus.org (sajt at icculus.org) Date: 14 May 2006 22:07:33 -0400 Subject: r719 - trunk Message-ID: <20060515020733.21786.qmail@icculus.org> Author: sajt Date: 2006-05-14 22:07:33 -0400 (Sun, 14 May 2006) New Revision: 719 Modified: trunk/darkwar.dsp Log: Added modelanim.[ch] to VC6 project file Modified: trunk/darkwar.dsp =================================================================== (Binary files differ) From kazashi at icculus.org Sun May 14 22:14:50 2006 From: kazashi at icculus.org (kazashi at icculus.org) Date: 14 May 2006 22:14:50 -0400 Subject: r720 - trunk Message-ID: <20060515021450.22899.qmail@icculus.org> Author: kazashi Date: 2006-05-14 22:14:50 -0400 (Sun, 14 May 2006) New Revision: 720 Modified: trunk/darkwar.dev Log: Added modelanim.[ch], m_menucore.h to Dev-C++ project file Modified: trunk/darkwar.dev =================================================================== --- trunk/darkwar.dev 2006-05-15 02:07:33 UTC (rev 719) +++ trunk/darkwar.dev 2006-05-15 02:14:50 UTC (rev 720) @@ -1,7 +1,7 @@ [Project] FileName=darkwar.dev Name=DarkWar -UnitCount=99 +UnitCount=102 Type=0 Ver=1 ObjFiles= @@ -1020,7 +1020,7 @@ [Unit98] FileName=systemfallbacks.c CompileCpp=0 -Folder=DarkWar +Folder= Compile=1 Link=1 Priority=1000 @@ -1037,3 +1037,33 @@ OverrideBuildCmd=0 BuildCmd= +[Unit100] +FileName=..\darkwar\game\m_menucore.h +CompileCpp=0 +Folder=Headers +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit101] +FileName=..\darkwar\modelanim.c +CompileCpp=0 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit102] +FileName=..\darkwar\modelanim.h +CompileCpp=0 +Folder=Headers +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + From black at icculus.org Tue May 23 15:42:08 2006 From: black at icculus.org (black at icculus.org) Date: 23 May 2006 15:42:08 -0400 Subject: r721 - trunk Message-ID: <20060523194208.1397.qmail@icculus.org> Author: black Date: 2006-05-23 15:42:08 -0400 (Tue, 23 May 2006) New Revision: 721 Modified: trunk/shell.c Log: Change the shell parser to not split up tokens into one value and one string token but treat it as one token (as it should) - this is necessary for IP addresses to work correctly. Modified: trunk/shell.c =================================================================== --- trunk/shell.c 2006-05-15 02:14:50 UTC (rev 720) +++ trunk/shell.c 2006-05-23 19:42:08 UTC (rev 721) @@ -374,7 +374,11 @@ if( Shell_Parser_MatchChar( parser, '.' ) ) { while( Shell_Parser_MatchDigit( parser ) ); } - return true; + // do not match e.g. 192.168.0.1 as 192.168|.0.1 but as one string + // TODO: maybe add an IP/DNS type to the console? This needs to be discussed. + if( IsWhitespace( *parser->currentChar ) ) { + return true; + } } return false; } From kazashi at icculus.org Wed May 31 23:57:24 2006 From: kazashi at icculus.org (kazashi at icculus.org) Date: 31 May 2006 23:57:24 -0400 Subject: r722 - in trunk/base/maps: . west Message-ID: <20060601035724.16651.qmail@icculus.org> Author: kazashi Date: 2006-05-31 23:51:15 -0400 (Wed, 31 May 2006) New Revision: 722 Added: trunk/base/maps/west/ trunk/base/maps/west/roofing_01.tga trunk/base/maps/west/roofing_01_gloss.tga trunk/base/maps/west/roofing_01_norm.tga Log: Added: trunk/base/maps/west/roofing_01.tga =================================================================== (Binary files differ) Property changes on: trunk/base/maps/west/roofing_01.tga ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/base/maps/west/roofing_01_gloss.tga =================================================================== (Binary files differ) Property changes on: trunk/base/maps/west/roofing_01_gloss.tga ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/base/maps/west/roofing_01_norm.tga =================================================================== (Binary files differ) Property changes on: trunk/base/maps/west/roofing_01_norm.tga ___________________________________________________________________ Name: svn:mime-type + application/octet-stream