int R_FindCustomTranslation(FName name) { switch (name) { case NAME_Ice: // Ice is a special case which will remain in its original slot. return TRANSLATION(TRANSLATION_Standard, 7); case NAME_None: return 0; case NAME_RainPillar1: case NAME_RainPillar2: case NAME_RainPillar3: case NAME_RainPillar4: case NAME_RainPillar5: case NAME_RainPillar6: case NAME_RainPillar7: case NAME_RainPillar8: return TRANSLATION(TRANSLATION_RainPillar, name.GetIndex() - NAME_RainPillar1); case NAME_Player1: case NAME_Player2: case NAME_Player3: case NAME_Player4: case NAME_Player5: case NAME_Player6: case NAME_Player7: case NAME_Player8: return TRANSLATION(TRANSLATION_Players, name.GetIndex() - NAME_Player1); } int *t = customTranslationMap.CheckKey(FName(name, true)); return (t != nullptr)? *t : -1; }
BYTE * GetBlendMap(PalEntry blend, BYTE *blendwork) { switch (blend.a==0 ? blend.r : -1) { case BLEND_INVERSEMAP: return InverseColormap; case BLEND_GOLDMAP: return GoldColormap; case BLEND_REDMAP: return RedColormap; case BLEND_GREENMAP: return GreenColormap; case BLEND_ICEMAP: return TranslationToTable(TRANSLATION(TRANSLATION_Standard, 7))->Remap; default: if (blend.r >= BLEND_DESATURATE1 && blend.r <= BLEND_DESATURATE31) { return DesaturateColormap[blend.r - BLEND_DESATURATE1]; } else { blendwork[0]=0; if (blend.a == 255) { for(int i=1;i<256;i++) { int rr = (blend.r * GPalette.BaseColors[i].r) / 255; int gg = (blend.g * GPalette.BaseColors[i].g) / 255; int bb = (blend.b * GPalette.BaseColors[i].b) / 255; blendwork[i] = ColorMatcher.Pick(rr, gg, bb); } return blendwork; } else if (blend.a != 0) { for(int i=1;i<256;i++) { int rr = (blend.r * blend.a + GPalette.BaseColors[i].r * (255-blend.a)) / 255; int gg = (blend.g * blend.a + GPalette.BaseColors[i].g * (255-blend.a)) / 255; int bb = (blend.b * blend.a + GPalette.BaseColors[i].b * (255-blend.a)) / 255; blendwork[i] = ColorMatcher.Pick(rr, gg, bb); } return blendwork; } } } return NULL; }
int FRemapTable::StoreTranslation() { unsigned int i; for (i = 0; i < translationtables[TRANSLATION_Decorate].Size(); i++) { if (*this == *translationtables[TRANSLATION_Decorate][i]) { // A duplicate of this translation already exists return TRANSLATION(TRANSLATION_Decorate, i); } } if (translationtables[TRANSLATION_Decorate].Size() >= MAX_DECORATE_TRANSLATIONS) { I_Error("Too many DECORATE translations"); } FRemapTable *newtrans = new FRemapTable; *newtrans = *this; i = translationtables[TRANSLATION_Decorate].Push(newtrans); return TRANSLATION(TRANSLATION_Decorate, i); }
BYTE *GetBlendMap(PalEntry blend, BYTE *blendwork) { switch (blend.a==0 ? int(blend) : -1) { case BLEND_ICEMAP: return TranslationToTable(TRANSLATION(TRANSLATION_Standard, 7))->Remap; default: if (blend >= BLEND_SPECIALCOLORMAP1 && blend < BLEND_SPECIALCOLORMAP1 + SpecialColormaps.Size()) { return SpecialColormaps[blend - BLEND_SPECIALCOLORMAP1].Colormap; } else if (blend >= BLEND_DESATURATE1 && blend <= BLEND_DESATURATE31) { return DesaturateColormap[blend - BLEND_DESATURATE1]; } else { blendwork[0]=0; if (blend.a == 255) { for(int i=1;i<256;i++) { int rr = (blend.r * GPalette.BaseColors[i].r) / 255; int gg = (blend.g * GPalette.BaseColors[i].g) / 255; int bb = (blend.b * GPalette.BaseColors[i].b) / 255; blendwork[i] = ColorMatcher.Pick(rr, gg, bb); } return blendwork; } else if (blend.a != 0) { for(int i=1;i<256;i++) { int rr = (blend.r * blend.a + GPalette.BaseColors[i].r * (255-blend.a)) / 255; int gg = (blend.g * blend.a + GPalette.BaseColors[i].g * (255-blend.a)) / 255; int bb = (blend.b * blend.a + GPalette.BaseColors[i].b * (255-blend.a)) / 255; blendwork[i] = ColorMatcher.Pick(rr, gg, bb); } return blendwork; } } } return NULL; }
DEFINE_ACTION_FUNCTION(AActor, A_GenericFreezeDeath) { self->Translation = TRANSLATION(TRANSLATION_Standard, 7); CALL_ACTION(A_FreezeDeath, self); }
//========================================================================== // // // //========================================================================== void gl_DrawTexture(FTexInfo *texInfo) { float x, y, w, h; float ox, oy, cx, cy, r, g, b; float light = 1.f; x = texInfo->x; y = texInfo->y; w = texInfo->width; h = texInfo->height; FGLTexture * gltex = FGLTexture::ValidateTexture(texInfo->tex); const PatchTextureInfo * pti; if (!texInfo->tex->bHasCanvas) { if (!texInfo->loadAlpha) { int translationindex; if (texInfo->tex->UseType == FTexture::TEX_FontChar) { // Try to get the true color mapping from the paletted mapping which is being passed here // // Too bad that there is no decent way to get the index directly so the only way to get it // is to analyze the table's contents. byte * index0 = texInfo->font->GetColorTranslation(CR_BRICK); byte * index1 = texInfo->font->GetColorTranslation(CR_TAN); translationindex = (texInfo->translation - index0) / (index1 - index0); if (translationindex<0 || translationindex>=NUM_TEXT_COLORS) { translationindex=CR_UNTRANSLATED; } // now get the corrseponding True Color table from the font. byte * tctstart = index0 + (NUM_TEXT_COLORS * (index1-index0)); texInfo->translation = tctstart + 3 * (index1-index0) * translationindex; } else { // If ZDoom changes its use of translation tables this has to be adjusted for it // because the texture manager doesn't implement a generic translation table handling. // if (texInfo->translation == DIM_MAP) { // reducing the light produces better results than using a palette-limited translation table. light = .5f; translationindex = 0; } else if (texInfo->translation >= translationtables[TRANSLATION_Players] && texInfo->translation < translationtables[TRANSLATION_Players] + (MAXPLAYERS+1)*256) { // Aside from fonts these are the only ones being used by ZDoom and they are better passed by ID. // int in = texInfo->translation - translationtables[TRANSLATION_Players]; translationindex = TRANSLATION(TRANSLATION_Players, in); } else { translationindex=0; } texInfo->translation=NULL; } pti = gltex->BindPatch(CM_DEFAULT, translationindex, texInfo->translation); } else { // This is an alpha texture pti = gltex->BindPatch(CM_SHADE, 0); } if (!pti) return; cx = pti->GetUR(); cy = pti->GetVB(); } else { gltex->Bind(CM_DEFAULT); cx=1.f; cy=-1.f; } ox = oy = 0.f; if (texInfo->flipX) { float temp = ox; ox = cx; cx = temp; } // also take into account texInfo->windowLeft and texInfo->windowRight // just ignore for now... if (texInfo->windowLeft || texInfo->windowRight != texInfo->tex->GetScaledWidth()) return; if (texInfo->fillColor > 0 || texInfo->RenderStyle == STYLE_Shaded || texInfo->RenderStyle == STYLE_TranslucentStencil || texInfo->RenderStyle == STYLE_Stencil) { r = RPART(texInfo->fillColor)/255.0f; g = GPART(texInfo->fillColor)/255.0f; b = BPART(texInfo->fillColor)/255.0f; } else { r = g = b = light; } // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; btm = SCREENHEIGHT - btm; gl.Enable(GL_SCISSOR_TEST); int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2; // ugh... gl.Scissor(texInfo->clipLeft, btm - texInfo->clipBottom+space, texInfo->clipRight - texInfo->clipLeft, texInfo->clipBottom - texInfo->clipTop); if (texInfo->RenderStyle == STYLE_TranslucentStencil || texInfo->RenderStyle == STYLE_Stencil) { gl_SetTextureMode(TM_MASK); } else if (!texInfo->masked) { gl_SetTextureMode(TM_OPAQUE); } gl.Color4f(r, g, b, texInfo->alpha); gl.Disable(GL_ALPHA_TEST); gl.Begin(GL_TRIANGLE_STRIP); gl.TexCoord2f(ox, oy); gl.Vertex2i(x, y); gl.TexCoord2f(ox, cy); gl.Vertex2i(x, y + h); gl.TexCoord2f(cx, oy); gl.Vertex2i(x + w, y); gl.TexCoord2f(cx, cy); gl.Vertex2i(x + w, y + h); gl.End(); gl.Enable(GL_ALPHA_TEST); gl.Scissor(0, 0, screen->GetWidth(), screen->GetHeight()); gl.Disable(GL_SCISSOR_TEST); if (!texInfo->masked || texInfo->RenderStyle == STYLE_TranslucentStencil || texInfo->RenderStyle == STYLE_Stencil) { gl_SetTextureMode(TM_MODULATE); } }
void cht_DoCheat (player_t *player, int cheat) { static const char * const BeholdPowers[9] = { "PowerInvulnerable", "PowerStrength", "PowerInvisibility", "PowerIronFeet", "MapRevealer", "PowerLightAmp", "PowerShadow", "PowerMask", "PowerTargeter", }; PClassActor *type; AInventory *item; const char *msg = ""; char msgbuild[32]; int i; switch (cheat) { case CHT_IDDQD: if (!(player->cheats & CF_GODMODE) && player->playerstate == PST_LIVE) { if (player->mo) player->mo->health = deh.GodHealth; player->health = deh.GodHealth; } // fall through to CHT_GOD case CHT_GOD: player->cheats ^= CF_GODMODE; if (player->cheats & CF_GODMODE) msg = GStrings("STSTR_DQDON"); else msg = GStrings("STSTR_DQDOFF"); ST_SetNeedRefresh(); break; case CHT_BUDDHA: player->cheats ^= CF_BUDDHA; if (player->cheats & CF_BUDDHA) msg = GStrings("TXT_BUDDHAON"); else msg = GStrings("TXT_BUDDHAOFF"); break; case CHT_GOD2: player->cheats ^= CF_GODMODE2; if (player->cheats & CF_GODMODE2) msg = GStrings("STSTR_DQD2ON"); else msg = GStrings("STSTR_DQD2OFF"); ST_SetNeedRefresh(); break; case CHT_BUDDHA2: player->cheats ^= CF_BUDDHA2; if (player->cheats & CF_BUDDHA2) msg = GStrings("TXT_BUDDHA2ON"); else msg = GStrings("TXT_BUDDHA2OFF"); break; case CHT_NOCLIP: player->cheats ^= CF_NOCLIP; if (player->cheats & CF_NOCLIP) msg = GStrings("STSTR_NCON"); else msg = GStrings("STSTR_NCOFF"); break; case CHT_NOCLIP2: player->cheats ^= CF_NOCLIP2; if (player->cheats & CF_NOCLIP2) { player->cheats |= CF_NOCLIP; msg = GStrings("STSTR_NC2ON"); } else { player->cheats &= ~CF_NOCLIP; msg = GStrings("STSTR_NCOFF"); } if (player->mo->Vel.X == 0) player->mo->Vel.X = MinVel; // force some lateral movement so that internal variables are up to date break; case CHT_NOVELOCITY: player->cheats ^= CF_NOVELOCITY; if (player->cheats & CF_NOVELOCITY) msg = GStrings("TXT_LEADBOOTSON"); else msg = GStrings("TXT_LEADBOOTSOFF"); break; case CHT_FLY: if (player->mo != NULL) { player->mo->flags7 ^= MF7_FLYCHEAT; if (player->mo->flags7 & MF7_FLYCHEAT) { player->mo->flags |= MF_NOGRAVITY; player->mo->flags2 |= MF2_FLY; msg = GStrings("TXT_LIGHTER"); } else { player->mo->flags &= ~MF_NOGRAVITY; player->mo->flags2 &= ~MF2_FLY; msg = GStrings("TXT_GRAVITY"); } } break; case CHT_MORPH: msg = cht_Morph (player, static_cast<PClassPlayerPawn *>(PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer)), true); break; case CHT_NOTARGET: player->cheats ^= CF_NOTARGET; if (player->cheats & CF_NOTARGET) msg = "notarget ON"; else msg = "notarget OFF"; break; case CHT_ANUBIS: player->cheats ^= CF_FRIGHTENING; if (player->cheats & CF_FRIGHTENING) msg = "\"Quake with fear!\""; else msg = "No more ogre armor"; break; case CHT_CHASECAM: player->cheats ^= CF_CHASECAM; if (player->cheats & CF_CHASECAM) msg = "chasecam ON"; else msg = "chasecam OFF"; R_ResetViewInterpolation (); break; case CHT_CHAINSAW: if (player->mo != NULL && player->health >= 0) { type = PClass::FindActor("Chainsaw"); if (player->mo->FindInventory (type) == NULL) { player->mo->GiveInventoryType (type); } msg = GStrings("STSTR_CHOPPERS"); } // [RH] The original cheat also set powers[pw_invulnerability] to true. // Since this is a timer and not a boolean, it effectively turned off // the invulnerability powerup, although it looks like it was meant to // turn it on. break; case CHT_POWER: if (player->mo != NULL && player->health >= 0) { item = player->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true); if (item != NULL) { item->Destroy (); msg = GStrings("TXT_CHEATPOWEROFF"); } else { player->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); msg = GStrings("TXT_CHEATPOWERON"); } } break; case CHT_IDKFA: cht_Give (player, "backpack"); cht_Give (player, "weapons"); cht_Give (player, "ammo"); cht_Give (player, "keys"); cht_Give (player, "armor"); msg = GStrings("STSTR_KFAADDED"); break; case CHT_IDFA: cht_Give (player, "backpack"); cht_Give (player, "weapons"); cht_Give (player, "ammo"); cht_Give (player, "armor"); msg = GStrings("STSTR_FAADDED"); break; case CHT_BEHOLDV: case CHT_BEHOLDS: case CHT_BEHOLDI: case CHT_BEHOLDR: case CHT_BEHOLDA: case CHT_BEHOLDL: case CHT_PUMPUPI: case CHT_PUMPUPM: case CHT_PUMPUPT: i = cheat - CHT_BEHOLDV; if (i == 4) { level.flags2 ^= LEVEL2_ALLMAP; } else if (player->mo != NULL && player->health >= 0) { item = player->mo->FindInventory(PClass::FindActor(BeholdPowers[i])); if (item == NULL) { if (i != 0) { cht_Give(player, BeholdPowers[i]); if (cheat == CHT_BEHOLDS) { P_GiveBody (player->mo, -100); } } else { // Let's give the item here so that the power doesn't need colormap information. cht_Give(player, "InvulnerabilitySphere"); } } else { item->Destroy (); } } msg = GStrings("STSTR_BEHOLDX"); break; case CHT_MASSACRE: { int killcount = P_Massacre (); // killough 3/22/98: make more intelligent about plural // Ty 03/27/98 - string(s) *not* externalized mysnprintf (msgbuild, countof(msgbuild), "%d Monster%s Killed", killcount, killcount==1 ? "" : "s"); msg = msgbuild; } break; case CHT_HEALTH: if (player->mo != NULL && player->playerstate == PST_LIVE) { player->health = player->mo->health = player->mo->GetDefault()->health; msg = GStrings("TXT_CHEATHEALTH"); } break; case CHT_KEYS: cht_Give (player, "keys"); msg = GStrings("TXT_CHEATKEYS"); break; // [GRB] case CHT_RESSURECT: if (player->playerstate != PST_LIVE && player->mo != nullptr) { if (player->mo->IsKindOf(RUNTIME_CLASS(APlayerChunk))) { Printf("Unable to resurrect. Player is no longer connected to its body.\n"); } else { player->playerstate = PST_LIVE; player->health = player->mo->health = player->mo->GetDefault()->health; player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight; player->mo->flags = player->mo->GetDefault()->flags; player->mo->flags2 = player->mo->GetDefault()->flags2; player->mo->flags3 = player->mo->GetDefault()->flags3; player->mo->flags4 = player->mo->GetDefault()->flags4; player->mo->flags5 = player->mo->GetDefault()->flags5; player->mo->flags6 = player->mo->GetDefault()->flags6; player->mo->flags7 = player->mo->GetDefault()->flags7; player->mo->renderflags &= ~RF_INVISIBLE; player->mo->Height = player->mo->GetDefault()->Height; player->mo->radius = player->mo->GetDefault()->radius; player->mo->special1 = 0; // required for the Hexen fighter's fist attack. // This gets set by AActor::Die as flag for the wimpy death and must be reset here. player->mo->SetState (player->mo->SpawnState); if (!(player->mo->flags2 & MF2_DONTTRANSLATE)) { player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); } player->mo->DamageType = NAME_None; if (player->ReadyWeapon != nullptr) { P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetUpState()); } if (player->morphTics > 0) { P_UndoPlayerMorph(player, player); } } } break; case CHT_GIMMIEA: cht_Give (player, "ArtiInvulnerability"); msg = "Valador's Ring of Invunerability"; break; case CHT_GIMMIEB: cht_Give (player, "ArtiInvisibility"); msg = "Shadowsphere"; break; case CHT_GIMMIEC: cht_Give (player, "ArtiHealth"); msg = "Quartz Flask"; break; case CHT_GIMMIED: cht_Give (player, "ArtiSuperHealth"); msg = "Mystic Urn"; break; case CHT_GIMMIEE: cht_Give (player, "ArtiTomeOfPower"); msg = "Tyketto's Tome of Power"; break; case CHT_GIMMIEF: cht_Give (player, "ArtiTorch"); msg = "Torch"; break; case CHT_GIMMIEG: cht_Give (player, "ArtiTimeBomb"); msg = "Delmintalintar's Time Bomb of the Ancients"; break; case CHT_GIMMIEH: cht_Give (player, "ArtiEgg"); msg = "Torpol's Morph Ovum"; break; case CHT_GIMMIEI: cht_Give (player, "ArtiFly"); msg = "Inhilicon's Wings of Wrath"; break; case CHT_GIMMIEJ: cht_Give (player, "ArtiTeleport"); msg = "Darchala's Chaos Device"; break; case CHT_GIMMIEZ: for (int i=0; i<16; i++) { cht_Give (player, "artifacts"); } msg = "All artifacts!"; break; case CHT_TAKEWEAPS: if (player->morphTics || player->mo == NULL || player->mo->health <= 0) { return; } { // Take away all weapons that are either non-wimpy or use ammo. AInventory **invp = &player->mo->Inventory, **lastinvp; for (item = *invp; item != NULL; item = *invp) { lastinvp = invp; invp = &(*invp)->Inventory; if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) { AWeapon *weap = static_cast<AWeapon *> (item); if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) || weap->AmmoType1 != NULL) { item->Destroy (); invp = lastinvp; } } } } msg = GStrings("TXT_CHEATIDKFA"); break; case CHT_NOWUDIE: cht_Suicide (player); msg = GStrings("TXT_CHEATIDDQD"); break; case CHT_ALLARTI: for (int i=0; i<25; i++) { cht_Give (player, "artifacts"); } msg = GStrings("TXT_CHEATARTIFACTS3"); break; case CHT_PUZZLE: cht_Give (player, "puzzlepieces"); msg = GStrings("TXT_CHEATARTIFACTS3"); break; case CHT_MDK: if (player->mo == NULL) { Printf ("What do you want to kill outside of a game?\n"); } else if (!deathmatch) { // Don't allow this in deathmatch even with cheats enabled, because it's // a very very cheap kill. P_LineAttack (player->mo, player->mo->Angles.Yaw, PLAYERMISSILERANGE, P_AimLineAttack (player->mo, player->mo->Angles.Yaw, PLAYERMISSILERANGE), TELEFRAG_DAMAGE, NAME_MDK, NAME_BulletPuff); } break; case CHT_DONNYTRUMP: cht_Give (player, "HealthTraining"); msg = GStrings("TXT_MIDASTOUCH"); break; case CHT_LEGO: if (player->mo != NULL && player->health >= 0) { int oldpieces = ASigil::GiveSigilPiece (player->mo); item = player->mo->FindInventory (RUNTIME_CLASS(ASigil)); if (item != NULL) { if (oldpieces == 5) { item->Destroy (); } else { player->PendingWeapon = static_cast<AWeapon *> (item); } } } break; case CHT_PUMPUPH: cht_Give (player, "MedPatch"); cht_Give (player, "MedicalKit"); cht_Give (player, "SurgeryKit"); msg = GStrings("TXT_GOTSTUFF"); break; case CHT_PUMPUPP: cht_Give (player, "AmmoSatchel"); msg = GStrings("TXT_GOTSTUFF"); break; case CHT_PUMPUPS: cht_Give (player, "UpgradeStamina", 10); cht_Give (player, "UpgradeAccuracy"); msg = GStrings("TXT_GOTSTUFF"); break; case CHT_CLEARFROZENPROPS: player->cheats &= ~(CF_FROZEN|CF_TOTALLYFROZEN); msg = "Frozen player properties turned off"; break; case CHT_FREEZE: bglobal.changefreeze ^= 1; if (bglobal.freeze ^ bglobal.changefreeze) { msg = GStrings("TXT_FREEZEON"); } else { msg = GStrings("TXT_FREEZEOFF"); } break; } if (!*msg) // [SO] Don't print blank lines! return; if (player == &players[consoleplayer]) Printf ("%s\n", msg); else if (cheat != CHT_CHASECAM) Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg); }
const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int translation, FTexture *hirescheck) { int usebright = false; bool alphatrans = false; if (translation <= 0) translation = -translation; else { alphatrans = (gl.legacyMode && DWORD(translation) == TRANSLATION(TRANSLATION_Standard, 8)); translation = GLTranslationPalette::GetInternalTranslation(translation); } bool needmipmap = (clampmode <= CLAMP_XY); FHardwareTexture *hwtex = CreateHwTexture(); if (hwtex) { // Texture has become invalid if ((!tex->bHasCanvas && (!tex->bWarped || gl.legacyMode)) && tex->CheckModified()) { Clean(true); hwtex = CreateHwTexture(); } // Bind it to the system. if (!hwtex->Bind(texunit, translation, needmipmap)) { int w=0, h=0; // Create this texture unsigned char * buffer = NULL; if (!tex->bHasCanvas) { buffer = CreateTexBuffer(translation, w, h, hirescheck, true, alphatrans); if (tex->bWarped && gl.legacyMode && w*h <= 256*256) // do not software-warp larger textures, especially on the old systems that still need this fallback. { // need to do software warping FWarpTexture *wt = static_cast<FWarpTexture*>(tex); unsigned char *warpbuffer = new unsigned char[w*h*4]; WarpBuffer((DWORD*)warpbuffer, (const DWORD*)buffer, w, h, wt->WidthOffsetMultiplier, wt->HeightOffsetMultiplier, r_FrameTime, wt->Speed, tex->bWarped); delete[] buffer; buffer = warpbuffer; wt->GenTime = r_FrameTime; } tex->ProcessData(buffer, w, h, false); } if (!hwtex->CreateTexture(buffer, w, h, texunit, needmipmap, translation, "FGLTexture.Bind")) { // could not create texture delete[] buffer; return NULL; } delete[] buffer; } if (tex->bHasCanvas) static_cast<FCanvasTexture*>(tex)->NeedUpdate(); if (translation != lastTranslation) lastSampler = 254; if (lastSampler != clampmode) lastSampler = GLRenderer->mSamplerManager->Bind(texunit, clampmode, lastSampler); lastTranslation = translation; return hwtex; } return NULL; }