/* ================= R_AliasSetupFrames ================= */ static void R_AliasSetupFrames(const entity_t *currententity, const model_t *currentmodel, dmdl_t *pmdl) { int thisframe = currententity->frame; int lastframe = currententity->oldframe; if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) ) { R_Printf(PRINT_ALL, "%s %s: no such thisframe %d\n", __func__, currentmodel->name, thisframe); thisframe = 0; } if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) ) { R_Printf(PRINT_ALL, "%s %s: no such lastframe %d\n", __func__, currentmodel->name, lastframe); lastframe = 0; } r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames + thisframe * pmdl->framesize); r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames + lastframe * pmdl->framesize); }
void GL3_ImageList_f(void) { int i, texels=0; gl3image_t *image; const char *formatstrings[2] = { "RGB ", "RGBA" }; const char* potstrings[2] = { " POT", "NPOT" }; R_Printf(PRINT_ALL, "------------------\n"); for (i = 0, image = gl3textures; i < numgl3textures; i++, image++) { int w, h; qboolean isNPOT = false; if (image->texnum == 0) { continue; } w = image->width; h = image->height; isNPOT = IsNPOT(w) || IsNPOT(h); texels += w*h; switch (image->type) { case it_skin: R_Printf(PRINT_ALL, "M"); break; case it_sprite: R_Printf(PRINT_ALL, "S"); break; case it_wall: R_Printf(PRINT_ALL, "W"); break; case it_pic: R_Printf(PRINT_ALL, "P"); break; case it_sky: R_Printf(PRINT_ALL, "Y"); break; default: R_Printf(PRINT_ALL, "?"); break; } R_Printf(PRINT_ALL, " %3i %3i %s %s: %s\n", w, h, formatstrings[image->has_alpha], potstrings[isNPOT], image->name); } R_Printf(PRINT_ALL, "Total texel count (not counting mipmaps): %i\n", texels); }
/* =============== R_ImageList_f =============== */ void R_ImageList_f(void) { int i; image_t *image; int texels; R_Printf(PRINT_ALL, "------------------\n"); texels = 0; for (i = 0, image = r_images; i < numr_images; i++, image++) { if (image->registration_sequence <= 0) continue; texels += image->width * image->height; switch (image->type) { case it_skin: R_Printf(PRINT_ALL, "M"); break; case it_sprite: R_Printf(PRINT_ALL, "S"); break; case it_wall: R_Printf(PRINT_ALL, "W"); break; case it_pic: R_Printf(PRINT_ALL, "P"); break; default: R_Printf(PRINT_ALL, " "); break; } R_Printf(PRINT_ALL, " %3i %3i : %s\n", image->width, image->height, image->name); } R_Printf(PRINT_ALL, "Total texel count: %i\n", texels); }
static gl3image_t * LoadWal(char *origname) { miptex_t *mt; int width, height, ofs; gl3image_t *image; char name[256]; Q_strlcpy(name, origname, sizeof(name)); /* Add the extension */ if (strcmp(COM_FileExtension(name), "wal")) { Q_strlcat(name, ".wal", sizeof(name)); } ri.FS_LoadFile(name, (void **)&mt); if (!mt) { R_Printf(PRINT_ALL, "LoadWal: can't load %s\n", name); return gl3_notexture; } width = LittleLong(mt->width); height = LittleLong(mt->height); ofs = LittleLong(mt->offsets[0]); image = GL3_LoadPic(name, (byte *)mt + ofs, width, 0, height, 0, it_wall, 8); ri.FS_FreeFile((void *)mt); return image; }
/* =============== R_AliasSetupSkin =============== */ static qboolean R_AliasSetupSkin(const entity_t *currententity, const model_t *currentmodel) { image_t *pskindesc; if (currententity->skin) pskindesc = currententity->skin; else { int skinnum; skinnum = currententity->skinnum; if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0)) { R_Printf(PRINT_ALL, "%s %s: no such skin # %d\n", __func__, currentmodel->name, skinnum); skinnum = 0; } pskindesc = currentmodel->skins[skinnum]; } if ( !pskindesc ) return false; r_affinetridesc.pskin = pskindesc->pixels[0]; r_affinetridesc.skinwidth = pskindesc->width; r_affinetridesc.skinheight = pskindesc->height; R_PolysetUpdateTables (); // FIXME: precalc edge lookups return true; }
/* ================ Mod_Modellist_f ================ */ void Mod_Modellist_f(void) { int i; model_t *mod; int total; total = 0; R_Printf(PRINT_ALL, "Loaded models:\n"); for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { if (!mod->name[0]) continue; R_Printf(PRINT_ALL, "%8i : %s\n", mod->extradatasize, mod->name); total += mod->extradatasize; } R_Printf(PRINT_ALL, "Total resident: %i\n", total); }
void GL3_TextureMode(char *string) { const int num_modes = sizeof(modes)/sizeof(modes[0]); int i; for (i = 0; i < num_modes; i++) { if (!Q_stricmp(modes[i].name, string)) { break; } } if (i == num_modes) { R_Printf(PRINT_ALL, "bad filter name\n"); return; } gl_filter_min = modes[i].minimize; gl_filter_max = modes[i].maximize; /* clamp selected anisotropy */ if (gl3config.anisotropic) { if (gl_anisotropic->value > gl3config.max_anisotropy) { ri.Cvar_SetValue("gl_anisotropic", gl3config.max_anisotropy); } else if (gl_anisotropic->value < 1.0) { ri.Cvar_SetValue("gl_anisotropic", 1.0); } } else { ri.Cvar_SetValue("gl_anisotropic", 0.0); } gl3image_t *glt; /* change all the existing mipmap texture objects */ for (i = 0, glt = gl3textures; i < numgl3textures; i++, glt++) { if ((glt->type != it_pic) && (glt->type != it_sky)) { GL3_SelectTMU(GL_TEXTURE0); GL3_Bind(glt->texnum); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); /* Set anisotropic filter if supported and enabled */ if (gl3config.anisotropic && gl_anisotropic->value) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_anisotropic->value); } } } }
/* ================ R_LoadWal ================ */ image_t *R_LoadWal(char *name) { miptex_t *mt; int ofs; image_t *image; int size; FS_LoadFile(name, (void **) &mt); if (!mt) { R_Printf(PRINT_ALL, "R_LoadWal: can't load %s\n", name); return r_notexture_mip; } image = R_FindFreeImage(); strcpy(image->name, name); image->width = LittleLong(mt->width); image->height = LittleLong(mt->height); image->type = it_wall; image->registration_sequence = registration_sequence; size = image->width * image->height * (256 + 64 + 16 + 4) / 256; image->pixels[0] = malloc(size); image->pixels[1] = image->pixels[0] + image->width * image->height; image->pixels[2] = image->pixels[1] + image->width * image->height / 4; image->pixels[3] = image->pixels[2] + image->width * image->height / 16; ofs = LittleLong(mt->offsets[0]); memcpy(image->pixels[0], (byte *) mt + ofs, size); FS_FreeFile((void *) mt); return image; }
/* * Callback function for debug output. */ static void APIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) { const char* sourceStr = "Source: Unknown"; const char* typeStr = "Type: Unknown"; const char* severityStr = "Severity: Unknown"; switch (severity) { case QGL_DEBUG_SEVERITY_NOTIFICATION: return; case GL_DEBUG_SEVERITY_HIGH_ARB: severityStr = "Severity: High"; break; case GL_DEBUG_SEVERITY_MEDIUM_ARB: severityStr = "Severity: Medium"; break; case GL_DEBUG_SEVERITY_LOW_ARB: severityStr = "Severity: Low"; break; } switch (source) { #define SRCCASE(X) case GL_DEBUG_SOURCE_ ## X ## _ARB: sourceStr = "Source: " #X; break; SRCCASE(API); SRCCASE(WINDOW_SYSTEM); SRCCASE(SHADER_COMPILER); SRCCASE(THIRD_PARTY); SRCCASE(APPLICATION); SRCCASE(OTHER); #undef SRCCASE } switch(type) { #define TYPECASE(X) case GL_DEBUG_TYPE_ ## X ## _ARB: typeStr = "Type: " #X; break; TYPECASE(ERROR); TYPECASE(DEPRECATED_BEHAVIOR); TYPECASE(UNDEFINED_BEHAVIOR); TYPECASE(PORTABILITY); TYPECASE(PERFORMANCE); TYPECASE(OTHER); #undef TYPECASE } // use PRINT_ALL - this is only called with gl3_debugcontext != 0 anyway. R_Printf(PRINT_ALL, "GLDBG %s %s %s: %s\n", sourceStr, typeStr, severityStr, message); }
void GL3_ScreenShot(void) { int w=vid.width, h=vid.height; byte *buffer = malloc(w*h*3); if (!buffer) { R_Printf(PRINT_ALL, "GL3_ScreenShot: Couldn't malloc %d bytes\n", w*h*3); return; } glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, buffer); // the pixels are now row-wise left to right, bottom to top, // but we need them row-wise left to right, top to bottom. // so swap bottom rows with top rows { size_t bytesPerRow = 3*w; byte rowBuffer[bytesPerRow]; byte *curRowL = buffer; // first byte of first row byte *curRowH = buffer + bytesPerRow*(h-1); // first byte of last row while(curRowL < curRowH) { memcpy(rowBuffer, curRowL, bytesPerRow); memcpy(curRowL, curRowH, bytesPerRow); memcpy(curRowH, rowBuffer, bytesPerRow); curRowL += bytesPerRow; curRowH -= bytesPerRow; } } ri.Vid_WriteScreenshot(w, h, 3, buffer); free(buffer); }
void GL3_BindLightmap(int lightmapnum) { int i=0; if(lightmapnum < 0 || lightmapnum >= MAX_LIGHTMAPS) { R_Printf(PRINT_ALL, "WARNING: Invalid lightmapnum %i used!\n", lightmapnum); return; } if (gl3state.currentlightmap == lightmapnum) { return; } gl3state.currentlightmap = lightmapnum; for(i=0; i<MAX_LIGHTMAPS_PER_SURFACE; ++i) { // this assumes that GL_TEXTURE<i+1> = GL_TEXTURE<i> + 1 // at least for GL_TEXTURE0 .. GL_TEXTURE31 that's true GL3_SelectTMU(GL_TEXTURE1+i); glBindTexture(GL_TEXTURE_2D, gl3state.lightmap_textureIDs[lightmapnum][i]); } }
/* ================ R_AliasDrawModel ================ */ void R_AliasDrawModel(entity_t *currententity, const model_t *currentmodel) { s_pmdl = (dmdl_t *)currentmodel->extradata; if ( r_lerpmodels->value == 0 ) currententity->backlerp = 0; float oldAliasxscale = aliasxscale; float oldAliasyscale = aliasyscale; if ( currententity->flags & RF_WEAPONMODEL ) { if ( r_lefthand->value == 2.0F ) { return; } float gunfov = 2 * tan((float)r_gunfov->value / 360 * M_PI); aliasxscale = ((float)r_refdef.vrect.width / gunfov) * r_aliasuvscale; aliasyscale = aliasxscale; if ( r_lefthand->value == 1.0F ) aliasxscale = -aliasxscale; } /* ** we have to set our frame pointers and transformations before ** doing any real work */ R_AliasSetupFrames(currententity, currentmodel, s_pmdl); R_AliasSetUpTransform(currententity); // see if the bounding box lets us trivially reject, also sets // trivial accept status if ( R_AliasCheckBBox(currententity) == BBOX_TRIVIAL_REJECT ) { if ( currententity->flags & RF_WEAPONMODEL ) { aliasxscale = oldAliasxscale; aliasyscale = oldAliasyscale; } return; } // set up the skin and verify it exists if ( !R_AliasSetupSkin(currententity, currentmodel) ) { R_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n", currentmodel->name); aliasxscale = oldAliasxscale; aliasyscale = oldAliasyscale; return; } r_amodels_drawn++; R_AliasSetupLighting(currententity); /* ** select the proper span routine based on translucency */ // added double damage shell // reordered to handle blending if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { int color; // added double color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM); // reordered, new shells after old shells (so they get overriden) if ( color == RF_SHELL_RED ) r_aliasblendcolor = SHELL_RED_COLOR; else if ( color == RF_SHELL_GREEN ) r_aliasblendcolor = SHELL_GREEN_COLOR; else if ( color == RF_SHELL_BLUE ) r_aliasblendcolor = SHELL_BLUE_COLOR; else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) ) r_aliasblendcolor = SHELL_RG_COLOR; else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) ) r_aliasblendcolor = SHELL_RB_COLOR; else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) ) r_aliasblendcolor = SHELL_BG_COLOR; // added this .. it's yellowish else if ( color == (RF_SHELL_DOUBLE) ) r_aliasblendcolor = SHELL_DOUBLE_COLOR; else if ( color == (RF_SHELL_HALF_DAM) ) r_aliasblendcolor = SHELL_HALF_DAM_COLOR; else r_aliasblendcolor = SHELL_WHITE_COLOR; if ( currententity->alpha > 0.33 ) d_pdrawspans = R_PolysetDrawSpansConstant8_66; else d_pdrawspans = R_PolysetDrawSpansConstant8_33; } else if ( currententity->flags & RF_TRANSLUCENT ) { if ( currententity->alpha > 0.66 ) d_pdrawspans = R_PolysetDrawSpans8_Opaque; else if ( currententity->alpha > 0.33 ) d_pdrawspans = R_PolysetDrawSpans8_66; else d_pdrawspans = R_PolysetDrawSpans8_33; } else { d_pdrawspans = R_PolysetDrawSpans8_Opaque; } /* ** compute this_frame and old_frame addresses */ R_AliasSetUpLerpData(currententity, s_pmdl, currententity->backlerp); if (currententity->flags & RF_DEPTHHACK) s_ziscale = (float)0x8000 * (float)SHIFT16XYZ_MULT * 3.0; else s_ziscale = (float)0x8000 * (float)SHIFT16XYZ_MULT; R_AliasPreparePoints(currententity, finalverts, finalverts_max); if ( currententity->flags & RF_WEAPONMODEL ) { aliasxscale = oldAliasxscale; aliasyscale = oldAliasyscale; } }
/* * This function returns the flags used at the SDL window * creation by GLimp_InitGraphics(). In case of error -1 * is returned. */ int GL3_PrepareForWindow(void) { // Mkay, let's try to load the libGL, const char *libgl; cvar_t *gl3_libgl = ri.Cvar_Get("gl3_libgl", "", CVAR_ARCHIVE); if (strlen(gl3_libgl->string) == 0) { libgl = NULL; } else { libgl = gl3_libgl->string; } while (1) { if (SDL_GL_LoadLibrary(libgl) < 0) { if (libgl == NULL) { ri.Sys_Error(ERR_FATAL, "Couldn't load libGL: %s!", SDL_GetError()); return -1; } else { R_Printf(PRINT_ALL, "Couldn't load libGL: %s!\n", SDL_GetError()); R_Printf(PRINT_ALL, "Retrying with default...\n"); ri.Cvar_Set("gl3_libgl", ""); libgl = NULL; } } else { break; } } // Set GL context attributs bound to the window. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8) == 0) { gl3config.stencil = true; } else { gl3config.stencil = false; } SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); // Set GL context flags. int contextFlags = SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG; if (gl3_debugcontext && gl3_debugcontext->value) { contextFlags |= SDL_GL_CONTEXT_DEBUG_FLAG; } if (contextFlags != 0) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, contextFlags); } // Let's see if the driver supports MSAA. int msaa_samples = 0; if (gl_msaa_samples->value) { msaa_samples = gl_msaa_samples->value; if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) < 0) { R_Printf(PRINT_ALL, "MSAA is unsupported: %s\n", SDL_GetError()); ri.Cvar_SetValue ("gl_msaa_samples", 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); } else if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaa_samples) < 0) { R_Printf(PRINT_ALL, "MSAA %ix is unsupported: %s\n", msaa_samples, SDL_GetError()); ri.Cvar_SetValue("gl_msaa_samples", 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); } } else { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); } return SDL_WINDOW_OPENGL; }
/* * Initializes the OpenGL context. Returns true at * success and false at failure. */ int GL3_InitContext(void* win) { // Coders are stupid. if (win == NULL) { ri.Sys_Error(ERR_FATAL, "R_InitContext() must not be called with NULL argument!"); return false; } window = (SDL_Window *)win; // Initialize GL context. context = SDL_GL_CreateContext(window); if(context == NULL) { R_Printf(PRINT_ALL, "GL3_InitContext(): Creating OpenGL Context failed: %s\n", SDL_GetError()); window = NULL; return false; } // Check if we've got the requested MSAA. int msaa_samples = 0; if (gl_msaa_samples->value) { if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &msaa_samples) == 0) { ri.Cvar_SetValue("gl_msaa_samples", msaa_samples); } } // Check if we've got at least 8 stencil bits int stencil_bits = 0; if (gl3config.stencil) { if (SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits) < 0 || stencil_bits < 8) { gl3config.stencil = false; } } // Enable vsync if requested. GL3_SetVsync(); // Load GL pointrs through GLAD and check context. if( !gladLoadGLLoader(SDL_GL_GetProcAddress)) { R_Printf(PRINT_ALL, "GL3_InitContext(): ERROR: loading OpenGL function pointers failed!\n"); return false; } else if (GLVersion.major < 3 || (GLVersion.major == 3 && GLVersion.minor < 2)) { R_Printf(PRINT_ALL, "GL3_InitContext(): ERROR: glad only got GL version %d.%d!\n", GLVersion.major, GLVersion.minor); return false; } else { R_Printf(PRINT_ALL, "Successfully loaded OpenGL function pointers using glad, got version %d.%d!\n", GLVersion.major, GLVersion.minor); } gl3config.debug_output = GLAD_GL_ARB_debug_output != 0; gl3config.anisotropic = GLAD_GL_EXT_texture_filter_anisotropic != 0; gl3config.major_version = GLVersion.major; gl3config.minor_version = GLVersion.minor; // Debug context setup. if (gl3_debugcontext && gl3_debugcontext->value && gl3config.debug_output) { glDebugMessageCallbackARB(DebugCallback, NULL); // Call GL3_DebugCallback() synchronously, i.e. directly when and // where the error happens (so we can get the cause in a backtrace) glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); } // Window title - set here so we can display renderer name in it. char title[40] = {0}; snprintf(title, sizeof(title), "Yamagi Quake II %s - OpenGL 3.2", YQ2VERSION); SDL_SetWindowTitle(window, title); return true; }
void Mod_LoadTexinfo(lump_t *l) { texinfo_t *in; mtexinfo_t *out, *step; int i, j, count; char name[MAX_QPATH]; int next; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) { ri.Sys_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s", loadmodel->name); } count = l->filelen / sizeof(*in); out = Hunk_Alloc(count * sizeof(*out)); loadmodel->texinfo = out; loadmodel->numtexinfo = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 4; j++) { out->vecs[0][j] = LittleFloat(in->vecs[0][j]); out->vecs[1][j] = LittleFloat(in->vecs[1][j]); } out->flags = LittleLong(in->flags); next = LittleLong(in->nexttexinfo); if (next > 0) { out->next = loadmodel->texinfo + next; } else { out->next = NULL; } Com_sprintf(name, sizeof(name), "textures/%s.wal", in->texture); out->image = R_FindImage(name, it_wall); if (!out->image) { R_Printf(PRINT_ALL, "Couldn't load %s\n", name); out->image = r_notexture; } } /* count animation frames */ for (i = 0; i < count; i++) { out = &loadmodel->texinfo[i]; out->numframes = 1; for (step = out->next; step && step != out; step = step->next) { out->numframes++; } } }
void LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) { byte *raw; pcx_t *pcx; int x, y; int len, full_size; int pcx_width, pcx_height; qboolean image_issues = false; int dataByte, runLength; byte *out, *pix; char filename[256]; Q_strlcpy(filename, origname, sizeof(filename)); /* Add the extension */ if (strcmp(COM_FileExtension(filename), "pcx")) { Q_strlcat(filename, ".pcx", sizeof(filename)); } *pic = NULL; if (palette) { *palette = NULL; } /* load the file */ len = FS_LoadFile(filename, (void **) &raw); if (!raw || len < sizeof(pcx_t)) { R_Printf(PRINT_DEVELOPER, "Bad pcx file %s\n", filename); return; } /* parse the PCX file */ pcx = (pcx_t *) raw; pcx->xmin = LittleShort(pcx->xmin); pcx->ymin = LittleShort(pcx->ymin); pcx->xmax = LittleShort(pcx->xmax); pcx->ymax = LittleShort(pcx->ymax); pcx->hres = LittleShort(pcx->hres); pcx->vres = LittleShort(pcx->vres); pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); pcx->palette_type = LittleShort(pcx->palette_type); raw = &pcx->data; pcx_width = pcx->xmax - pcx->xmin; pcx_height = pcx->ymax - pcx->ymin; if ((pcx->manufacturer != 0x0a) || (pcx->version != 5) || (pcx->encoding != 1) || (pcx->bits_per_pixel != 8) || (pcx_width >= 4096) || (pcx_height >= 4096)) { R_Printf(PRINT_ALL, "Bad pcx file %s\n", filename); FS_FreeFile(pcx); return; } full_size = (pcx_height + 1) * (pcx_width + 1); out = malloc(full_size); if (!out) { R_Printf(PRINT_ALL, "Can't allocate\n"); FS_FreeFile(pcx); return; } *pic = out; pix = out; if (palette) { *palette = malloc(768); if (!(*palette)) { R_Printf(PRINT_ALL, "Can't allocate\n"); free(out); FS_FreeFile(pcx); return; } if (len > 768) { memcpy(*palette, (byte *) pcx + len - 768, 768); } else { image_issues = true; } } if (width) { *width = pcx_width + 1; } if (height) { *height = pcx_height + 1; } for (y = 0; y <= pcx_height; y++, pix += pcx_width + 1) { for (x = 0; x <= pcx_width;) { if (raw - (byte *) pcx > len) { // no place for read image_issues = true; x = pcx_width; break; } dataByte = *raw++; if ((dataByte & 0xC0) == 0xC0) { runLength = dataByte & 0x3F; if (raw - (byte *) pcx > len) { // no place for read image_issues = true; x = pcx_width; break; } dataByte = *raw++; } else { runLength = 1; } while (runLength-- > 0) { if ((*pic + full_size) <= (pix + x)) { // no place for write image_issues = true; x += runLength; runLength = 0; } else { pix[x++] = dataByte; } } } } if (raw - (byte *) pcx > len) { R_Printf(PRINT_DEVELOPER, "PCX file %s was malformed", filename); free(*pic); *pic = NULL; } if (image_issues) { R_Printf(PRINT_ALL, "PCX file %s has possible size issues.\n", filename); } FS_FreeFile(pcx); }
/* * This is also used as an entry point for the generated r_notexture */ gl3image_t * GL3_LoadPic(char *name, byte *pic, int width, int realwidth, int height, int realheight, imagetype_t type, int bits) { gl3image_t *image = NULL; GLuint texNum=0; int i; qboolean nolerp = false; if (gl_nolerp_list != NULL && gl_nolerp_list->string != NULL) { nolerp = strstr(gl_nolerp_list->string, name) != NULL; } /* find a free gl3image_t */ for (i = 0, image = gl3textures; i < numgl3textures; i++, image++) { if (image->texnum == 0) { break; } } if (i == numgl3textures) { if (numgl3textures == MAX_GL3TEXTURES) { ri.Sys_Error(ERR_DROP, "MAX_GLTEXTURES"); } numgl3textures++; } image = &gl3textures[i]; if (strlen(name) >= sizeof(image->name)) { ri.Sys_Error(ERR_DROP, "GL3_LoadPic: \"%s\" is too long", name); } strcpy(image->name, name); image->registration_sequence = registration_sequence; image->width = width; image->height = height; image->type = type; if ((type == it_skin) && (bits == 8)) { FloodFillSkin(pic, width, height); } // image->scrap = false; // TODO: reintroduce scrap? would allow optimizations in 2D rendering.. glGenTextures(1, &texNum); image->texnum = texNum; GL3_SelectTMU(GL_TEXTURE0); GL3_Bind(texNum); if (bits == 8) { image->has_alpha = GL3_Upload8(pic, width, height, (image->type != it_pic && image->type != it_sky), image->type == it_sky); } else { image->has_alpha = GL3_Upload32((unsigned *)pic, width, height, (image->type != it_pic && image->type != it_sky)); } if (realwidth && realheight) { if ((realwidth <= image->width) && (realheight <= image->height)) { image->width = realwidth; image->height = realheight; } else { R_Printf(PRINT_DEVELOPER, "Warning, image '%s' has hi-res replacement smaller than the original! (%d x %d) < (%d x %d)\n", name, image->width, image->height, realwidth, realheight); } } image->sl = 0; image->sh = 1; image->tl = 0; image->th = 1; if (nolerp) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } #if 0 // TODO: the scrap could allow batch rendering 2D stuff? not sure it's worth the hassle.. /* load little pics into the scrap */ if (!nolerp && (image->type == it_pic) && (bits == 8) && (image->width < 64) && (image->height < 64)) { int x, y; int i, j, k; int texnum; texnum = Scrap_AllocBlock(image->width, image->height, &x, &y); if (texnum == -1) { goto nonscrap; } scrap_dirty = true; /* copy the texels into the scrap block */ k = 0; for (i = 0; i < image->height; i++) { for (j = 0; j < image->width; j++, k++) { scrap_texels[texnum][(y + i) * BLOCK_WIDTH + x + j] = pic[k]; } } image->texnum = TEXNUM_SCRAPS + texnum; image->scrap = true; image->has_alpha = true; image->sl = (x + 0.01) / (float)BLOCK_WIDTH; image->sh = (x + image->width - 0.01) / (float)BLOCK_WIDTH; image->tl = (y + 0.01) / (float)BLOCK_WIDTH; image->th = (y + image->height - 0.01) / (float)BLOCK_WIDTH; } else { nonscrap: image->scrap = false; image->texnum = TEXNUM_IMAGES + (image - gltextures); R_Bind(image->texnum); if (bits == 8) { image->has_alpha = R_Upload8(pic, width, height, (image->type != it_pic && image->type != it_sky), image->type == it_sky); } else { image->has_alpha = R_Upload32((unsigned *)pic, width, height, (image->type != it_pic && image->type != it_sky)); } image->upload_width = upload_width; /* after power of 2 and scales */ image->upload_height = upload_height; image->paletted = uploaded_paletted; if (realwidth && realheight) { if ((realwidth <= image->width) && (realheight <= image->height)) { image->width = realwidth; image->height = realheight; } else { R_Printf(PRINT_DEVELOPER, "Warning, image '%s' has hi-res replacement smaller than the original! (%d x %d) < (%d x %d)\n", name, image->width, image->height, realwidth, realheight); } } image->sl = 0; image->sh = 1; image->tl = 0; image->th = 1; if (nolerp) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } } #endif // 0 return image; }