1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
|
/****
Windows functionality that is definitely
not project specific.
****/
// To link code to main C functions
extern "C" {
#include "3dc.h"
#include "inline.h"
// For modifications necessary to make Alt-Tabbing
// behaviour (WM_ACTIVATEAPP) work full screen.
// This is necessary to support full screen
// ActiveMovie play.
#define SupportAltTab Yes
// Globals
static HANDLE RasterThread;
// Externs
extern BOOL bActive;
// These function are here solely to provide a clean
// interface layer, since Win32 include files are fully
// available in both C and C++.
// All functions linking to standard windows code are
// in win_func.cpp or win_proj.cpp, and all DirectX
// interface functions
// should be in dd_func.cpp (in the Win95 directory)
// or d3_func.cpp, dp_func.cpp, ds_func.cpp etc.
// Project specific platfrom functionality for Win95
// should be in project/win95, in files called
// dd_proj.cpp etc.
// GetTickCount is the standard windows return
// millisecond time function, which isn't actually
// accurate to a millisecond. In order to get FRI
// to work properly with GetTickCount at high frame
// rates, you will have to switch KalmanTimer to Yes
// at the start of io.c to turn on a filtering algorithm
// in the frame counter handler.
// Alternately, we can use the mm function
// timeGetTime to get the time accurate to a millisecond.
// There is still enough variation in this to make
// the kalman filter probably worthwhile, however.
long GetWindowsTickCount(void)
{
#if 0
return GetTickCount();
#else
return timeGetTime();
#endif
}
// This function is set up using a PeekMessage check,
// with a return on a failure of GetMessage, on the
// grounds that it might be more stable than just
// GetMessage. But then again, maybe not.
// PM_NOREMOVE means do not take this message out of
// the queue. The while loop is designed to ensure
// that all messages are sent through to the Windows
// Procedure are associated with a maximum of one frame's
// delay in the main engine cycle, ensuring that e.g.
// keydown messages do not build up in the queue.
// if necessary, one could extern this flag
// to determine if a task-switch has occurred which might
// have trashed a static display, to decide whether to
// redraw the screen. After doing so, one should reset
// the flag
BOOL g_bMustRedrawScreen = FALSE;
void CheckForWindowsMessages(void)
{
MSG msg;
extern signed int MouseWheelStatus;
MouseWheelStatus = 0;
// Initialisation for the current embarassingly primitive mouse
// handler...
do
{
while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&msg, NULL, 0, 0))
return;
TranslateMessage(&msg);
DispatchMessage(&msg);
#if (!SupportAltTab)
// Panic
if (!bActive)
{
// Dubious hack...
#if 0
ExitSystem();
#else
ReleaseDirect3D();
exit(0x00);
#endif
}
#endif
}
// JH 13/2/98 - if the app is not active we should not return from the message lopp
// until the app is re-activated
if (!bActive)
{
ResetFrameCounter();
Sleep(0);
g_bMustRedrawScreen = TRUE;
}
}
while (!bActive);
}
// Experimental functions to handle a separate
// thread to run rasterisation on hardware at low
// priority.
// Note that the RenderD3DScene function does not need
// to call ExitThread explictly - the return at the
// end of the function will do this for this, giving
// thread exit code equal to the return value from
// the function.
/*
Note that this assumes DrawPerFrame mode!!!
necessary for some hardware accelerators anyway
(deferred texturing problem!!!)
*/
BOOL SpawnRasterThread()
{
DWORD RasterThreadId;
// Stack size of new thread in bytes.
// For the moment, we will set it to
// 128K, the normal size for the engine
// process.
// Note that this is in bytes.
// Note that stack size should grow as
// necessary. We hope.
DWORD StackSize = 128 * 1024;
// Create the thread
RasterThread = CreateThread(
NULL, // no security
StackSize, // default stack size
(LPTHREAD_START_ROUTINE) RenderD3DScene,
0, // no argument for function
0, // default creation flags
&RasterThreadId); // get thread ID
if (RasterThread == NULL)
{
#if debug
ReleaseDirect3D();
exit(0xabab);
#else
return FALSE;
#endif
}
#if 1
// Set the priority on the thread to
// below normal, since we want this thread
// to be unimportant --- it is only monitoring
// the hardware rasteriser. Hopefully.
// Note that this priority value maybe should
// be THREAD_PRIORITY_LOWEST or THREAD_PRIORITY_IDLE,
// or maybe we shouldn't call this function at all.
// Also, we must have a THREAD_SET_INFORMATION
// access right associated with the thread for this
// to work. Hopefully, this should be the default
// when using CreateThread.
SetThreadPriority(RasterThread,
THREAD_PRIORITY_NORMAL);
#endif
return TRUE;
}
BOOL WaitForRasterThread()
{
BOOL RetVal;
DWORD ThreadStatus;
int i;
// Note that if this is to work the
// rasterisation thread must have a
// THREAD_QUERY_INFORMATION access right,
// but we believe CreateThread should supply
// this as a default.
// Note!!! At some stage we may want to put a
// delay loop in the statement below, in the
// time honoured Saturn fashion, depending on how
// much impact calling GetExitCodeThread has on the
// rest of the system - hopefully not much...
do
{
RetVal = GetExitCodeThread(RasterThread,
&ThreadStatus);
}
while ((RetVal == TRUE) &&
(ThreadStatus == STILL_ACTIVE));
// Failed to get a status report on the thread
if (RetVal == FALSE)
{
#if debug
ReleaseDirect3D();
exit(0xabbb);
#else
return FALSE;
#endif
}
return TRUE;
}
/*
Pick up processor types,
either from assembler test (note
I have asm to do this, but it must
be converted from as / Motorola format
to masm / Intel), or (more likely) from
a text file left by the launcher, which
can use GetProcessorType from the
mssetup api
*/
#if defined(_MSC_VER)
static unsigned int GetCPUId(void)
{
unsigned int retval;
_asm
{
mov eax,1
_emit 0x0f ; CPUID (00001111 10100010) - This is a Pentium
; specific instruction which gets information on the
_emit 0xa2 ; processor. A Pentium family processor should set
; bits 11-8 of eax to 5.
mov retval,edx
}
return retval;
}
#else
#error "Unknown compiler"
#endif
PROCESSORTYPES ReadProcessorType(void)
{
SYSTEM_INFO SystemInfo;
int ProcessorType;
PROCESSORTYPES RetVal;
GetSystemInfo(&SystemInfo);
ProcessorType = SystemInfo.dwProcessorType;
switch (ProcessorType)
{
case PROCESSOR_INTEL_386:
RetVal = PType_OffBottomOfScale;
break;
case PROCESSOR_INTEL_486:
RetVal = PType_486;
break;
case PROCESSOR_INTEL_PENTIUM:
if (GetCPUId() & 0x00800000)
RetVal = PType_PentiumMMX;
else
RetVal = PType_Pentium;
break;
#if 0
case PROCESSOR_INTEL_SOMETHING:
RetVal = PType_Klamath;
break;
#endif
default:
RetVal = PType_OffTopOfScale;
break;
}
return RetVal;
}
// End of extern C declaration
};
|