/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "watchmaker/ll/ll_util.h" #include "watchmaker/ll/ll_anim.h" #include "watchmaker/ll/ll_diary.h" #include "watchmaker/ll/ll_mesh.h" #include "watchmaker/ll/ll_regen.h" #include "watchmaker/3d/animation.h" #include "watchmaker/3d/geometry.h" #include "watchmaker/3d/loader.h" #include "watchmaker/3d/math/llmath.h" #include "watchmaker/3d/t3d_mesh.h" #include "watchmaker/classes/do_camera.h" #include "watchmaker/classes/do_operate.h" #include "watchmaker/classes/do_system.h" #include "watchmaker/define.h" #include "watchmaker/globvar.h" #include "watchmaker/main.h" #include "watchmaker/message.h" #include "watchmaker/renderer.h" #include "watchmaker/schedule.h" #include "watchmaker/sysdef.h" #include "watchmaker/t2d/t2d_internal.h" #include "watchmaker/types.h" #include "watchmaker/utils.h" #include "watchmaker/walk/act.h" #include "watchmaker/windows_hacks.h" namespace Watchmaker { /* -----------------17/03/98 16.19------------------- * LinkObjToMesh * --------------------------------------------------*/ uint16 LinkObjToMesh(WGame &game, t3dMESH *m, uint8 op) { uint16 a, b, c, i; t3dBODY *cr; int16 n; Init &init = game.init; if (!m) return (oNULL); NextPortalObj = oNULL; // Controllo tra gli altri personaggi for (c = ocCUOCO; c <= ocLASTCHAR; c++) { for (b = 0; b < MAX_OBJ_MESHLINKS; b++) if (Character[c] && Character[c]->Mesh) if ((!init.Obj[c].meshLinkIsEmpty(b)) && (m->name.equalsIgnoreCase(init.Obj[c].getMeshLink(b)))) return (c); } // Controllo in stanza attuale for (a = 0; a < MAX_OBJS_IN_ROOM; a++) { if (!(c = game.getCurRoom().objects[a])) continue; if ((init.Obj[c].flags & ON) && !(init.Obj[c].flags & HIDE) && (((bFirstPerson) && !(init.Obj[c].flags & HIDEIN1ST)) || (!(bFirstPerson) && !(init.Obj[c].flags & HIDEIN3RD)))) { for (b = 0; b < MAX_OBJ_MESHLINKS; b++) if ((!init.Obj[c].meshLinkIsEmpty(b)) && (m->name.equalsIgnoreCase(init.Obj[c].getMeshLink(b)))) for (i = 0; i < t3dCurRoom->NumMeshes(); i++) if ((m->name.equalsIgnoreCase(t3dCurRoom->MeshTable[i].name))) return (c); } } // Se non trova controlla in portali vicino for (i = 0; i < t3dCurRoom->NumMeshes(); i++) { if ((cr = t3dCurRoom->MeshTable[i].PortalList) != nullptr) { NextPortalAnim = aNULL; n = getRoomFromStr(init, cr->name); if ((op == ME_MRIGHT) || (op == ME_MLEFT)) { for (a = 0; a < MAX_ANIMS_IN_ROOM; a++) { b = game.getCurRoom().anims[a]; if ((b == aNULL) || !(init.Anim[b].flags & ANIM_PORTAL_LINK)) continue; if (t3dCurRoom->MeshTable[i].name.equalsIgnoreCase((const char *)init.Anim[b].RoomName.rawArray())) { NextPortalAnim = b; break; } } } for (a = 0; a < MAX_OBJS_IN_ROOM; a++) { if (!(c = init.Room[n].objects[a])) continue; if ((init.Obj[c].flags & ON) && !(init.Obj[c].flags & HIDE) && (((bFirstPerson) && !(init.Obj[c].flags & HIDEIN1ST)) || (!(bFirstPerson) && !(init.Obj[c].flags & HIDEIN3RD)))) { for (b = 0; b < MAX_OBJ_MESHLINKS; b++) { if ((!init.Obj[c].meshLinkIsEmpty(b)) && m->name.equalsIgnoreCase(init.Obj[c].getMeshLink(b))) { if ((op == ME_MRIGHT) || (op == ME_MLEFT)) NextPortalObj = c; return (c); } } } } if ((op == ME_MRIGHT) || (op == ME_MLEFT)) { for (a = 0; a < cr->NumMeshes(); a++) { if (m->name.equalsIgnoreCase(cr->MeshTable[a].name)) { NextPortalObj = oNEXTPORTAL; return (oNULL); } } } } } if ((op == ME_MRIGHT) || (op == ME_MLEFT)) NextPortalAnim = aNULL; return (oNULL); } /* -----------------16/04/98 11.33------------------- * WhatIObj * --------------------------------------------------*/ int32 WhatObj(WGame &game, int32 mx, int32 my, uint8 op) { t3dMESH *pm, *CurMesh; t3dF32 minz; int32 ret; uint16 n; op = ME_MRIGHT; ret = 0; CurMesh = nullptr; FloorHit = 0; minz = 999999999.9f; for (n = 0; n < t3d_NumMeshesVisible; n++) { // Prima cerca in mesh associate if (!(pm = t3d_VisibleMeshes[n])) continue; if ((pm->BBoxAverageZ < minz) && ((pm->Flags & T3D_MESH_RAYBAN) || (LinkObjToMesh(game, pm, 0)))) { minz = pm->BBoxAverageZ; CurMesh = pm; } } if (CurMesh == nullptr) { // Poi cerca nelle altre for (n = 0; n < t3d_NumMeshesVisible; n++) { if (!(pm = t3d_VisibleMeshes[n])) continue; if (!(pm->Flags & T3D_MESH_NOBOUNDBOX) && (pm->BBoxAverageZ < minz)) { minz = pm->BBoxAverageZ; CurMesh = pm; } } if (t3dCheckWithFloor() < minz) FloorHit = 1; } memset(ObjectUnderCursor, 0, 400); if (CurMesh || (FloorHit)) { if (!FloorHit) { Common::strlcpy(ObjectUnderCursor, CurMesh->name.c_str(), 400); ret = LinkObjToMesh(game, CurMesh, op); if (NextPortalObj) snprintf(ObjectUnderCursor, 400, "NextPortalObj -> %s", CurMesh->name.c_str()); mPos.x = CurMesh->Intersection.x; mPos.y = CurMesh->Intersection.y; mPos.z = CurMesh->Intersection.z; } else { if (CurMesh) snprintf(ObjectUnderCursor, 400, "Floor Hit -> %s", CurMesh->name.c_str()); else Common::strlcpy(ObjectUnderCursor, "Floor Hit", 400); LinkObjToMesh(game, CurMesh, op); if (NextPortalObj) snprintf(ObjectUnderCursor, 400, "NextPortalObj -> Floor Hit -> %s", CurMesh->name.c_str()); mPos.x = FloorHitCoords.x; mPos.y = FloorHitCoords.y; mPos.z = FloorHitCoords.z; } } return (ret); } /* -----------------13/07/98 12.05------------------- * getRoomFromStr * --------------------------------------------------*/ int16 getRoomFromStr(Init &init, const Common::String &s) { auto end = s.findLastOf(".-"); if (end == s.npos) { end = s.size() - 1; } auto start = s.findLastOf("\\/"); if (start == s.npos) { start = 0; } Common::String str = s.substr(start, end - start); for (int a = 0; a < MAX_ROOMS; a++) if (str.equalsIgnoreCase((const char *)init.Room[a].name)) return a; return (0); } /* -----------------19/01/99 11.03------------------- * CreateTooltipBitmap * --------------------------------------------------*/ int32 CreateTooltipBitmap(Renderer &renderer, char *tooltip, FontColor color, uint8 r, uint8 g, uint8 b) { int32 dimx, dimy, enlarge = 5; char info[100]; if (!tooltip || !strcmp(tooltip, "")) return -1; FontKind font = FontKind::Standard; renderer._fonts->getTextDim(tooltip, font, &dimx, &dimy); dimx += renderer.rFitX(enlarge * 2); dimy += renderer.rFitY(enlarge * 2); int32 surf = rCreateSurface(dimx, dimy, 0); if (surf <= 0) return -1; Common::strlcpy(info, "tooltip: ", 400); strncat(info, tooltip, 15); rSetBitmapName(surf, info); renderer.clearBitmap(surf, 0, 0, dimx, dimy, 18, 18, 18); // Bordino nero renderer.clearBitmap(surf, 1, 1, dimx - 2, dimy - 2, r, g, b); // Sfondo colorato renderer.printText(tooltip, surf, font, color, (uint16)renderer.rFitX(enlarge), (uint16)renderer.rFitY(enlarge)); return surf; } /* -----------------27/10/98 15.31------------------- * LoadDDBitmap * --------------------------------------------------*/ int32 LoadDDBitmap(WGame &game, const char *n, uint8 flags) { auto name = game.workDirs.join(game.workDirs._miscDir, n); int rez = rLoadBitmapImage(game, name.c_str(), (uint8)(rBITMAPSURFACE | rSURFACEFLIP | flags)); if (rez <= 0) { warning("Failed to load %s. Quitting ...", name.c_str()); CloseSys(game); } return (rez); } /* -----------------13/05/98 10.59------------------- * LinkMeshToStr * --------------------------------------------------*/ t3dMESH *LinkMeshToStr(Init &init, const Common::String &str) { // TODO: Refactor the callsites: return _vm->_roomManager->linkMeshToStr(init, str); } /* -----------------18/12/00 18.02------------------- * UpdateRoomInfo * --------------------------------------------------*/ void UpdateRoomInfo(WGame &game) { uint8 cr; if (!t3dCurRoom) return; cr = (uint8)getRoomFromStr(game.init, t3dCurRoom->name); if (!cr) return; // se � diversa dalla precedente... if (strcmp(RoomInfo.name, game.init.Room[cr].desc)) { game._messageSystem.removeEvent_bparam(EventClass::MC_SYSTEM, ME_STARTEFFECT, EFFECT_ROOMINFO); game._messageSystem.removeEvent_bparam(EventClass::MC_SYSTEM, ME_CONTINUEEFFECT, EFFECT_ROOMINFO); game._messageSystem.removeEvent_bparam(EventClass::MC_SYSTEM, ME_STOPEFFECT, EFFECT_ROOMINFO); _vm->_messageSystem.doEvent(EventClass::MC_SYSTEM, ME_STARTEFFECT, MP_DEFAULT, FRAME_PER_SECOND * 3, 0, EFFECT_ROOMINFO, nullptr, nullptr, nullptr); } } /* -----------------13/10/98 15.00------------------- * UpdateRoomVisibility * --------------------------------------------------*/ void UpdateRoomVisibility(WGame &game) { uint32 i, j; t3dBODY *pr; uint8 cr; Init &init = game.init; if (!t3dCurRoom) return; // Leva il flag visibile a tutte le stanze for (i = 0; i < MAX_ROOMS; i++) { if (init.Room[i].flags & ROOM_VISIBLE) init.Room[i].flags |= ROOM_OLDVISIBLE; init.Room[i].flags &= ~ROOM_VISIBLE; } // Aggiunge room attuale cr = (uint8)getRoomFromStr(init, t3dCurRoom->name); if (!cr) { init.Room[cr].flags |= ROOM_VISIBLE; } if (bShowRoomDescriptions) UpdateRoomInfo(game); // if( !( Room[cr].flags & ROOM_OLDVISIBLE ) ) // Event( EventClass::MC_SYSTEM, ME_STARTEFFECT, MP_DEFAULT, FRAME_PER_SECOND*3, 0, EFFECT_ROOMINFO, NULL, NULL, NULL ); // Prima volta che entra nella r45 if ((cr == r45) && !(init.Room[cr].flags & ROOM_VISITED)) init.Obj[o46SECONDODIAGRAMMA].flags |= EXTRA; if (!(LoaderFlags & T3D_DEBUGMODE)) { // Prima volta che entra nella r46 if ((cr == r46) && !(init.Room[cr].flags & ROOM_VISITED)) _vm->_messageSystem.doEvent(EventClass::MC_DIALOG, ME_DIALOGSTART, MP_DEFAULT, dR212, 0, 0, NULL, NULL, NULL); // Prima volta che entra nella r47 if ((cr == r47) && !(init.Room[cr].flags & ROOM_VISITED)) _vm->_messageSystem.doEvent(EventClass::MC_DIALOG, ME_DIALOGSTART, MP_DEFAULT, dR471, 0, 0, NULL, NULL, NULL); // Prima volta che entra nella r48 if ((cr == r48) && !(init.Room[cr].flags & ROOM_VISITED)) _vm->_messageSystem.doEvent(EventClass::MC_DIALOG, ME_DIALOGSTART, MP_DEFAULT, dR481, 0, 0, NULL, NULL, NULL); } #if 0 // Se ha cambiato stanza cambia anche l'environment sSetEnvironment(init.Room[cr].env); // Se ha cambiato stanza cambia anche la musica if (!(LoaderFlags & T3D_NOMUSIC) && (init.Room[cr].music != nNULL)) PlayMusic(init.Room[cr].music, 3000, 3000); #endif init.Room[cr].flags |= ROOM_VISITED; // Aggiorna oggetti speciali UpdateSpecial(game, cr); // Cerca nelle stanze visbili con ricorsione 2 for (i = 0; i < t3dCurRoom->NumMeshes(); i++) { if (!(pr = t3dCurRoom->MeshTable[i].PortalList) || (t3dCurRoom->MeshTable[i].Flags & T3D_MESH_NOPORTALCHECK)) continue; cr = (uint8)getRoomFromStr(init, pr->name); if (!cr) { init.Room[cr].flags |= ROOM_VISIBLE; } for (j = 0; j < pr->NumMeshes(); j++) { if ((pr->MeshTable[j].PortalList) && !(pr->MeshTable[j].Flags & T3D_MESH_NOPORTALCHECK)) { cr = (uint8)getRoomFromStr(init, pr->MeshTable[j].PortalList->name); if (!cr) { init.Room[cr].flags |= ROOM_VISIBLE; } } } } // Accende le animazioni di background delle stanze che si vedono // DebugFile("RoomVisibility %s",t3dCurRoom->Name); for (i = 0; i < MAX_ROOMS; i++) { if (init.Room[i].flags & ROOM_VISIBLE) { // Aggiunge effetti di background for (j = 0; j < MAX_SOUNDS_IN_ROOM; j++) if ((init.Room[i].sounds[j]) && (init.Sound[init.Room[i].sounds[j]].flags & SOUND_ON)) { //se la pompa non e' attivata non attivo nemmeno il suono if ((init.Room[i].sounds[j] == wPOMPA) && (init.Obj[o2GOFF].flags & ON)) continue; //di notte nella r1c la fontana e' spenta if ((init.Room[i].sounds[j] == wFONTANA) && (((t3dCurTime >= 1300) && (t3dCurTime <= 1310)) || (t3dCurTime >= 1800)) ) continue; #if 0 StartSound(init.Room[i].sounds[j]); #endif } // DebugFile("%d: %d %s",i,RoomVisibility[i],Room[RoomVisibility[i]].name); for (j = 0; j < MAX_ANIMS_IN_ROOM; j++) if ((init.Room[i].anims[j]) && (init.Anim[init.Room[i].anims[j]].flags & ANIM_ON)) if (!(init.Anim[init.Room[i].anims[j]].active)) { if ((init.Anim[init.Room[i].anims[j]].obj != aNULL) && (Character[init.Anim[init.Room[i].anims[j]].obj])) { Character[init.Anim[init.Room[i].anims[j]].obj]->Flags &= ~T3D_CHARACTER_HIDE; CharSetPosition(init.Anim[init.Room[i].anims[j]].obj, init.Anim[init.Room[i].anims[j]].pos, (const char*)init.Anim[init.Room[i].anims[j]].RoomName.rawArray()); } DebugLogWindow("Staring Bkg Anim %d | Obj %d Pos %d", init.Room[i].anims[j], init.Anim[init.Room[i].anims[j]].obj, init.Anim[init.Room[i].anims[j]].pos); StartAnim(game, init.Room[i].anims[j]); } StartDiary(game, i, NULL); } // Spegne le animazioni delle stanze che non si vedono piu' else if (init.Room[i].flags & ROOM_OLDVISIBLE) { // Leva effetti di background for (j = 0; j < MAX_SOUNDS_IN_ROOM; j++) { #if 0 if ((init.Room[i].sounds[j]) && (init.Sound[init.Room[i].sounds[j]].flags & SOUND_ON)) StopSound(init.Room[i].sounds[j]); #endif } // Se non e' piu' in vista for (j = 0; j < MAX_ANIMS_IN_ROOM; j++) if ((init.Room[i].anims[j]) && (init.Anim[init.Room[i].anims[j]].flags & ANIM_ON)) { if (Character[init.Anim[init.Room[i].anims[j]].obj]) Character[init.Anim[init.Room[i].anims[j]].obj]->Flags |= T3D_CHARACTER_HIDE; StopAnim(game, init.Room[i].anims[j]); } init.Room[i].flags &= ~ROOM_OLDVISIBLE; StopDiary(game, i, 0, 0); } } } /* -----------------12/06/00 10.12------------------- * SetBndLevel * --------------------------------------------------*/ bool SetBndLevel(WGame &game, const char *roomname, int32 lev) { t3dBODY *t = nullptr; if (roomname && (roomname[0] != '\0')) { _vm->_roomManager->getRoomIfLoaded(roomname); } else t = t3dCurRoom; if (!t) { DebugLogFile("SETBND FAILED: %s, %d", roomname, lev); return false; } if (lev >= t->NumLevels) { DebugLogFile("!!!! BND Lev too high: %s max %d ask %d", t->name.c_str(), t->NumLevels, lev); return false; } t->CurLevel = (int16)lev; if (t == t3dCurRoom) CurFloorY = t->PanelHeight[t->CurLevel]; _vm->addMeshModifier(t->name, MM_SET_BND_LEVEL, &lev); UpdateRoomVisibility(game); DebugLogFile("SETBND: %s, %d", t->name.c_str(), lev); if (Player) { Player->Walk.CurPanel = -1; Player->Walk.OldPanel = -1; } return true; } /* -----------------17/12/00 17.59------------------- * PrintLoading * --------------------------------------------------*/ void PrintLoading() { warning("STUBBED: PrintLoading"); #if 0 // Stampa la scritta loading DisplayDDBitmap(LoadingImage, 800 - 103 - 4, 600 - 85 - 4, 0, 0, 0, 0); Add2DStuff(); rShowFrame(); // rBlitSetStandardFont( StandardFont.Color[WHITE_FONT], StandardFont.Table ); // DebugQuick(10,-1,"Loading..."); // rBlitSetStandardFont( 0, NULL ); #endif } /* -----------------01/09/98 16.52-------------------- * ChangeRoom * --------------------------------------------------*/ void ChangeRoom(WGame &game, Common::String n, uint8 pos, int32 an) { t3dBODY *t; int32 i, j, k; if (n.equalsIgnoreCase("r21.t3d")) n = "r21-a.t3d"; bFirstPerson = false; if (t3dCurRoom && t3dCurRoom->name.equalsIgnoreCase(n)) { game.UpdateAll(); if (pos) CharSetPosition(ocCURPLAYER, pos, nullptr); if (an) StartAnim(game, an); return ; } PrintLoading(); StopAllAnims(game.init); // StopMusic(); // quando si cambia piano (e quindi si cancella quello attuale e si carica il nuovo) stoppo il diario in modo che // se esso aveva delle modifiche da fare al piano corrente le fa subito, e non dopo quando il piano non e' piu' disponibile StopDiary(game, 0, 0, 0); // Prima lo cerca tra le stanze in memoria t = _vm->_roomManager->getRoomIfLoaded(n); // Se non lo trova tra le stanze in memoria if (!t) { t3dResetPipeline(); _vm->_roomManager->releaseLoadedFiles(T3D_STATIC_SET0); for (i = 0; i < T3D_MAX_CHARACTERS; i++) { if (Character[i]) { for (j = 0; j < T3D_MAX_SHADOWBOX_PER_CHAR; j++) { if (Character[i]->ShadowBox[j]) { for (k = 0; k < MAX_SHADOWS_PER_LIGHT; k++) { Character[i]->ShadowBox[j]->ShadowsList[k].ProjectiveTexture.clear(); } } } Character[i]->Walk = t3dWALK(); } } rReleaseAllTextures(T3D_STATIC_SET0); rReleaseAllBitmaps(T3D_STATIC_SET0); // t3dFree( StandardFont.Table ); ReleasePreloadedAnims(); t3dReleaseParticles(); t3dCurRoom = nullptr; if (!game.LoadAndSetup(n, 0)) CloseSys(game); PortalCrossed = t3dCurRoom; ResetScreenBuffer(); //resetto in modo che la scritta di loading non faccia casini } else { ResetScreenBuffer(); //resetto in modo che la scritta di loading non faccia casini t3dResetPipeline(); t3dCurRoom = t; PortalCrossed = t3dCurRoom; t3dCurCamera = &t3dCurRoom->CameraTable[0]; t3dVectCopy(&t3dCurCamera->Target, &Player->Mesh->Trasl); game._cameraMan->ResetCameraSource(); game._cameraMan->ResetCameraTarget(); CurFloorY = t3dCurRoom->PanelHeight[t3dCurRoom->CurLevel]; } CameraTargetObj = 0; CameraTargetBone = 0; ForcedCamera = 0; game.UpdateAll(); if (pos) CharSetPosition(ocCURPLAYER, pos, nullptr); game._cameraMan->ProcessCamera(game); if (an) StartAnim(game, an); } /* -----------------21/08/00 15.48------------------- * GetBndLevel * --------------------------------------------------*/ int32 GetBndLevel(char *roomname) { t3dBODY *t = nullptr; if (roomname && (roomname[0] != '\0')) { t = _vm->_roomManager->getRoomIfLoaded(roomname); } else t = t3dCurRoom; if (!t) return FALSE; return (int32)t->CurLevel; } /* -----------------23/10/98 18.17------------------- * CheckRect * --------------------------------------------------*/ bool CheckRect(Renderer &renderer, struct SRect p, int32 cmx, int32 cmy) { return ((cmx >= renderer.rFitX(p.x1)) && (cmx < renderer.rFitX(p.x2)) && (cmy >= renderer.rFitY(p.y1)) && (cmy < renderer.rFitY(p.y2))); } /* -----------------03/05/99 17.31------------------- * DisplayD3DTriangle * --------------------------------------------------*/ void DisplayD3DTriangle(Renderer &renderer, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint8 r, uint8 g, uint8 b, uint8 al) { int32 a; for (a = 0; a < MAX_D3D_TRIANGLES; a++) { if ((D3DTrianglesList[a].x1 == renderer.rFitX(x1)) && (D3DTrianglesList[a].y1 == renderer.rFitY(y1)) && (D3DTrianglesList[a].x2 == renderer.rFitX(x2)) && (D3DTrianglesList[a].y2 == renderer.rFitY(y2)) && (D3DTrianglesList[a].x3 == renderer.rFitX(x3)) && (D3DTrianglesList[a].y3 == renderer.rFitY(y3))) break; if (!D3DTrianglesList[a].x1 && !D3DTrianglesList[a].y1 && !D3DTrianglesList[a].x2 && !D3DTrianglesList[a].y2) break; } if (a >= MAX_D3D_TRIANGLES) { warning("Too many D3D Triangles!"); return ; } D3DTrianglesList[a].x1 = renderer.rFitX(x1); D3DTrianglesList[a].y1 = renderer.rFitY(y1); D3DTrianglesList[a].x2 = renderer.rFitX(x2); D3DTrianglesList[a].y2 = renderer.rFitY(y2); D3DTrianglesList[a].x3 = renderer.rFitX(x3); D3DTrianglesList[a].y3 = renderer.rFitY(y3); D3DTrianglesList[a].r = r; D3DTrianglesList[a].g = g; D3DTrianglesList[a].b = b; D3DTrianglesList[a].a = al; } /* -----------------24/04/98 10.33------------------- * DisplayD3DRect * --------------------------------------------------*/ void DisplayD3DRect(Renderer &renderer, int32 px, int32 py, int32 dx, int32 dy, uint8 r, uint8 g, uint8 b, uint8 al) { int32 a; for (a = 0; a < MAX_D3D_RECTS; a++) { if ((D3DRectsList[a].px == renderer.rFitX(px)) && (D3DRectsList[a].py == renderer.rFitY(py)) && (D3DRectsList[a].dx == renderer.rFitX(dx)) && (D3DRectsList[a].dy == renderer.rFitY(dy))) break; if (!D3DRectsList[a].dx && !D3DRectsList[a].dy) break; } if (a >= MAX_D3D_RECTS) { warning("Too many D3D Rects!"); return ; } D3DRectsList[a].px = renderer.rFitX(px); D3DRectsList[a].py = renderer.rFitY(py); D3DRectsList[a].dx = renderer.rFitX(px + dx) - renderer.rFitX(px); D3DRectsList[a].dy = renderer.rFitY(py + dy) - renderer.rFitY(py); D3DRectsList[a].r = r; D3DRectsList[a].g = g; D3DRectsList[a].b = b; D3DRectsList[a].a = al; } /* -----------------15/01/99 18.15------------------- * GetDDBitmapExtends * --------------------------------------------------*/ void GetDDBitmapExtends(Renderer &renderer, struct SRect *r, struct SDDBitmap *b) { if (!r || !b) return ; r->x1 = b->px; r->y1 = b->py; // TODO: Somehow the original engine was able to handle this // even though rGetBitmapRealDimX used b->tnum as index // into gBitmapList, which becomes problematic when using // the upper bits for flagging. For now let's mask out // the high-bit. uint32 mask = T2D_BM_OFF ^ 0xFFFFFFFF; r->x2 = r->x1 + renderer.getBitmapRealDimX(b->tnum & mask); r->y2 = r->y1 + renderer.getBitmapRealDimY(b->tnum & mask); } /* -----------------05/11/98 10.36------------------- * DebugVideo * --------------------------------------------------*/ void DebugVideo(Renderer &renderer, int32 px, int32 py, const char *format, ...) { char str[500]; va_list args; va_start(args, format); vsnprintf(str, 500, format, args); va_end(args); renderer._2dStuff.displayDDText(str, FontKind::Standard, WHITE_FONT, px, py, 0, 0, 0, 0); // rPrintText( str, 0, StandardFont.Color[WHITE_FONT], StandardFont.Table, px, py ); } } // End of namespace Watchmaker