If you're wondering what the .m32 texture format is, its basically the .wal format upgraded to 32bit with a few extras. Before we start, this does not add FULL .m32 support. It only adds support to the OpenGL renderer, qbsp3, and qrad3. The engine itself will still try to download the .wal for a texture even if the GL renderer already loaded a .m32 for it, so the allow_download cvar should be set to "0" unless you want to see a bunch of texture download failures. Don't bother looking for detail or damage textures, because this tutorial doesn't go into that. Also, the qrad tool Raven uses must have been compiled with different light falloff values because the sample map from their SDK (the first level of SOF) was WAY too bright when lit with Quake2's qrad3. If you can't find the Quake2 tools source, its at "ftp://ftp.idsoftware.com/idstuff/quake2/source/old/q2source_12_11.zip". This code works with the 3.19 and 3.21 source. Quake2:Open the Quake2 source and set ref_gl as the active project. Open the "Header Files" folder in the File View and open qfiles.h qfiles.h:After: } miptex_t; Add: // |nc - .M32 Support Begin: /* ============================================================================== .M32 texture file format ============================================================================== */ typedef struct miptex32_s { int version; char name[128]; char altname[128]; // texture substitution char animname[128]; // next frame in animation chain char damagename[128]; // image that should be shown when damaged unsigned width[16], height[16]; unsigned offsets[16]; int flags; int contents; int value; float scale_x, scale_y; int mip_scale; // detail texturing info char dt_name[128]; // detailed texture name float dt_scale_x, dt_scale_y; float dt_u, dt_v; float dt_alpha; int dt_src_blend_mode, dt_dst_blend_mode; int flags2; float damage_health; int unused[18]; // future expansion to maintain compatibility with h2 } miptex32_t; // |nc - .M32 Support End gl_model.c: In function Mod_LoadTexinfo(): Replace: if (!out->image) { ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name); out->image = r_notexture; } With: // |nc - .M32 Support Begin: // if (!out->image) // { // ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name); // out->image = r_notexture; // } if (!out->image || out->image == r_notexture) { Com_sprintf (name, sizeof(name), "textures/%s.m32", in->texture); out->image = GL_FindImage (name, it_wall); if (!out->image) { ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name); out->image = r_notexture; } } // |nc - .M32 Support End gl_image.c: After function GL_LoadWal(): Add: // |nc - .M32 Support Begin: /* ================ GL_LoadWal32 ================ */ image_t *GL_LoadWal32 (char *name) { miptex32_t *mt; int width, height, ofs; image_t *image; ri.FS_LoadFile (name, (void **)&mt); if (!mt) { ri.Con_Printf (PRINT_ALL, "GL_FindImage: can't load %s\n", name); return r_notexture; } width = LittleLong (mt->width[0]); height = LittleLong (mt->height[0]); ofs = LittleLong (mt->offsets[0]); image = GL_LoadPic (name, (byte *)mt + ofs, width, height, it_wall, 32); ri.FS_FreeFile ((void *)mt); return image; } // |nc - .M32 Support End In Function GL_FindImage(): After: else if (!strcmp(name+len-4, ".tga")) { LoadTGA (name, &pic, &width, &height); if (!pic) return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); image = GL_LoadPic (name, pic, width, height, type, 32); } Add: // |nc - .M32 Support Begin: else if (!strcmp(name+len-4, ".m32")) { image = GL_LoadWal32 (name); } // |nc - .M32 Support End QBSP3:qfiles.h (in the "External Dependencies" folder): After: } miptex_t; Add: /* ============================================================================== .M32 texture file format ============================================================================== */ typedef struct miptex32_s { int version; char name[128]; char altname[128]; // texture substitution char animname[128]; // next frame in animation chain char damagename[128]; // image that should be shown when damaged unsigned width[16], height[16]; unsigned offsets[16]; int flags; int contents; int value; float scale_x, scale_y; int mip_scale; // detail texturing info char dt_name[128]; // detailed texture name float dt_scale_x, dt_scale_y; float dt_u, dt_v; float dt_alpha; int dt_src_blend_mode, dt_dst_blend_mode; int flags2; float damage_health; int unused[18]; // future expansion to maintain compatibility with h2 } miptex32_t; textures.c: In function FindMiptex(): After: miptex_t *mt; Add: // |nc - .M32 Support Begin: miptex32_t *mt32; // |nc - .M32 Support End After: if (TryLoadFile (path, (void **)&mt) != -1) { textureref[i].value = LittleLong (mt->value); textureref[i].flags = LittleLong (mt->flags); textureref[i].contents = LittleLong (mt->contents); strcpy (textureref[i].animname, mt->animname); free (mt); } Add: // |nc - .M32 Support Begin: else { sprintf (path, "%stextures/%s.m32", gamedir, name); if (TryLoadFile (path, (void **)&mt32) != -1) { textureref[i].value = LittleLong (mt32->value); textureref[i].flags = LittleLong (mt32->flags); textureref[i].contents = LittleLong (mt32->contents); strcpy (textureref[i].animname, mt32->animname); free (mt32); } } // |nc - .M32 Support End QRAD3:patches.c: Replace the entire CalcTextureReflectivity() funcion with: // |nc - .M32 Support Begin void CalcTextureReflectivity (void) { int i; int j, k, texels; int color[3]; int texel; byte *palette; char path[1024]; float r, scale; miptex_t *mt; miptex32_t *mt32; int offset; byte *temp; sprintf (path, "%spics/colormap.pcx", gamedir); // get the game palette Load256Image (path, NULL, &palette, NULL, NULL); // allways set index 0 even if no textures texture_reflectivity[0][0] = 0.5; texture_reflectivity[0][1] = 0.5; texture_reflectivity[0][2] = 0.5; for (i=0 ; i < numtexinfo ; i++) { // see if an earlier texinfo allready got the value for (j=0 ; j < i ; j++) { if (!strcmp (texinfo[i].texture, texinfo[j].texture)) { VectorCopy (texture_reflectivity[j], texture_reflectivity[i]); break; } } if (j != i) continue; // load the wal file sprintf (path, "%stextures/%s.wal", gamedir, texinfo[i].texture); if (TryLoadFile (path, (void **)&mt) != -1) { texels = LittleLong(mt->width)*LittleLong(mt->height); offset = LittleLong(mt->offsets[0]); temp = (byte *)mt; color[0] = color[1] = color[2] = 0; for (j=0 ; j<texels ; j++) { texel = temp[offset + j]; for (k=0 ; k < 3 ; k++) color[k] += palette[texel*3+k]; } } else { sprintf (path, "%stextures/%s.m32", gamedir, texinfo[i].texture); if (TryLoadFile (path, (void **)&mt32) != -1) { texels = LittleLong(mt32->width[0])*LittleLong(mt32->height[0]); offset = LittleLong(mt32->offsets[0]); temp = (byte *)mt32; color[0] = color[1] = color[2] = 0; for (j=0 ; j < texels ; j++) { texel = temp[offset + j]; for (k=0 ; k<3 ; k++) color[k] += texel*4+k; } } else { printf ("Couldn't load %s\n", path); texture_reflectivity[i][0] = 0.5; texture_reflectivity[i][1] = 0.5; texture_reflectivity[i][2] = 0.5; continue; } } for (j=0 ; j<3 ; j++) { r = color[j]/texels/255.0; texture_reflectivity[i][j] = r; } // scale the reflectivity up, because the textures are // so dim scale = ColorNormalize (texture_reflectivity[i], texture_reflectivity[i]); if (scale < 0.5) { scale *= 2; VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]); } #if 0 texture_reflectivity[i][0] = 0.5; texture_reflectivity[i][1] = 0.5; texture_reflectivity[i][2] = 0.5; #endif } } // |nc - .M32 Support End Now you can compile maps with .m32 textures and Quake2 will load them if theres no .wals with the same name. |