I'll describe the method I'm using and you can decide if it suits you. My method is inspired by (what I remember of) quake 3 code.
Your winMain has three entry points for "the game":
// called after window initialization and openGl setup
Game Setup
// called during the main windows loop
Game Loop
// called after the main windows loop during shutdown procedure
Game Shutdown
Your key object that is going to link everything together is your Game State object.
Heres a rough outline of that object
Code:
class GameState {
long currentTick;
long lastTick;
std::vector<entity_npc> npcEntites;
std::vector<entity_player> playerEntities;
std::vector<entity_projectile> projectileEntities;
std::vector<entity_emitter> emitterEntities;
Level * map;
}
The method is as follows:
Game Setup:
Initialize your GameState object and all the objects it consists of etc.
Game Loop:
Save the Current GameState as Last GameState.
Do all updates / calculations based on the Last GameState and put the new values
in Current GameState.
Do Rendering based on Current GameState.
Game Shutdown:
Free all your memory / standard shutdown etc.
Pseudo Code Example
Code:
GameState lastState;
GameState currentState;
function GameSetup() {
// first tick
currentState.currentTick = GetTickCount();
currentState.prevTick = GetTickCount() - GOAL_TICK_PER_FRAME; // start off with ideal difference
// load level
Level map = new Level();
currentState.map = map;
// load players
for(i = 0; i < clients; i++)
currentState.playerEntities.push_back(new entity_player(client[i]));
// load npc entities
for(i = 0; i < npcs; i++)
currentState.npcEntities.push_back(new entity_npc(npcs[i]));
// no projectile data yet
// no particle emitters yet
}
function gameLoop() {
// save currentState as last
lastState = currentState;
currentState.currentTick = GetTickCount();
currentState.prevTick = lastState.currentTick();
// update projectile entities
for(i = 0; i < projectileEntities.size(); i++) {
currentState.projectileEntities[i].position = lastState.projectileEntities[i].position + lastState.projectileEntities[i].velocity;
}
// update player entities
for(i = 0; i < playerEntities.size(); i++)
updatePlayerPositionFromInput(playerEntities[i]);
// update npc entities
for(i = 0; i < npcEntities.size(); i++)
updateNpcPositionFromAi(npcEntities[i]);
// etc
// now that currentState has been updated we do rendering based on objects in currentState.
// render map, players, npcs, projectiles, etc.
// render ui
// etc.
}
function gameShutdown() {
// free up memory etc.
}
Of course, your main game loop wont do any of the actual data updates, i did the projectile stuff in place as an example, but ideally it would be handled similar to player input and npc control in the example. You just pass all the needed info (entity object, entire entity list or even the entire game state object(s)) to your physics, ai, or input systems and let them do the updates.
It will be up to you to decide what objects are included in your game state and decide how you want to manage those objects (this example uses vectors).
Hope this helps you decide on a way to tie everything together.