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