Subversion Repositories Games.Chess Giants

Rev

Rev 140 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
// render.cpp
2
 
3
// thanks ChaotikMind for optimizing the engine a bit :)
4
 
5
#include "common.h"
6
 
7
 
8
// note: DirectX requires a C++ compiler.
9
#include "DirectX9/Include/d3d9.h"
10
#include "DirectX9/Include/d3dx9.h"
11
 
12
// include the Direct3D library files
13
#pragma comment (lib, "DirectX9/Lib/x86/d3d9.lib")
14
#pragma comment (lib, "DirectX9/Lib/x86/d3dx9.lib")
15
 
16
 
17
// handy macro to print a chatter channel reply
18
#define PRINT_CCREPLY(ccreply) \
19
{ \
124 pmbaty 20
   Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \
1 pmbaty 21
                   chat_fontindex, (ccreply)->color, &rect, \
22
                   L"["); \
124 pmbaty 23
   Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \
1 pmbaty 24
                   chat_fontindex, RGBA_TO_RGBACOLOR (159, 159, 159, RGBACOLOR_ALPHA ((ccreply)->color)), &rect, \
25
                   (ccreply)->channelname); \
124 pmbaty 26
   Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \
1 pmbaty 27
                   chat_fontindex, (ccreply)->color, &rect, \
28
                   L"] "); /* closing bracket + non-breakable space */ \
124 pmbaty 29
   Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \
1 pmbaty 30
                   chat_fontindex, RGBA_TO_RGBACOLOR (159, 159, 159, RGBACOLOR_ALPHA ((ccreply)->color)), &rect, \
31
                   (ccreply)->nickname); \
124 pmbaty 32
   Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \
1 pmbaty 33
                   chat_fontindex, (ccreply)->color, &rect, \
34
                   L": "); /* colon + non-breakable space */ \
35
   if ((ccreply)->text != NULL) \
124 pmbaty 36
      Render_wprintf (rect.right * 100.0f / initial_width, 100 - combinedheight_percent, (initial_width - rect.right) * 100.0f / initial_width, ALIGN_LEFT, ALIGN_TOP, ALIGN_LEFT, \
1 pmbaty 37
                      chat_fontindex, (ccreply)->color, &rect, \
38
                      (ccreply)->text); \
39
}
40
 
41
 
42
// handy macro to draw a GUI button
43
#define DRAW_BUTTON_IF_NEEDED(button) \
44
{ \
45
   if ((button).state != 0) \
124 pmbaty 46
   { \
1 pmbaty 47
      Render_DrawSprite (&sprites[(button).sprite_index], (button).left, (button).top, (button).width, (button).height, ((button).state == 2 ? 0xFF : 0x7F)); \
124 pmbaty 48
      if ((button).text[0] != 0) \
49
         Render_wprintf ((button).left + (button).width / 2.0f, (button).top + (button).height / 2.0f, (button).width, ALIGN_CENTER, ALIGN_CENTER, ALIGN_CENTER, chat_fontindex, D3DCOLOR_ARGB (255, 255, 255, /*alpha*/ ((button).state == 2 ? 0xFF : 0x7F)), NULL, (button).text); \
50
   } \
1 pmbaty 51
}
52
 
53
 
54
// handy macro to draw a GUI text
55
#define DRAW_TEXT_IF_NEEDED(text) \
56
{ \
57
   if ((text).is_displayed) \
58
   { \
124 pmbaty 59
      Render_wprintf ((text).xpos_percent, (text).ypos_percent, \
60
                      (text).maxwidth_percent, (text).horizontal_align, (text).vertical_align, (text).text_align, (text).font_index, \
1 pmbaty 61
                      ((text).want_fade ? \
62
                       RGBACOLOR_SETALPHA ((text).color, \
63
                                           (((text).appear_time + (text).disappear_time) * 0.5f > current_time ? \
64
                                           /* fading in  */ (int) FadeFloat (0, RGBACOLOR_ALPHA ((text).color), (text).appear_time, (text).appear_time + 0.5f) : \
65
                                           /* fading out */ (int) FadeFloat (RGBACOLOR_ALPHA ((text).color), 0, (text).disappear_time - 3.0f, (text).disappear_time))) : \
66
                       (text).color), \
67
                      NULL, (text).buffer); \
68
      if ((text).disappear_time < current_time) \
69
         (text).is_displayed = false; \
70
   } \
71
}
72
 
73
 
74
#pragma pack(push,1)
75
 
76
// definition for a vector
77
typedef struct vector_s
78
{
79
   float x; // X component
80
   float y; // Y component
81
   float z; // Z component
82
} vector_t;
83
 
84
 
85
// definition for a texture coordinates pair
86
typedef struct texcoord_s
87
{
88
   float u; // X coordinate of the texture point this vertex corresponds to
89
   float v; // Y coordinate of the texture point this vertex corresponds to
90
} texcoord_t;
91
 
92
 
93
// definition for a vertex (must be in that order for Direct3D)
94
typedef struct vertex_s
95
{
96
   vector_t position; // position in space
97
   vector_t normal; // coordinates of the unary normal vector of the plane this vertex is on (for illumination)
98
   texcoord_t texcoord; // coordinates of the texture point this vertex corresponds to
99
} vertex_t;
100
 
101
#pragma pack(pop)
102
 
103
 
104
// definition for a reflected object (qsort array element to sort reflections by distance)
105
typedef struct reflectedobject_s
106
{
107
   sceneobject_t *object; // pointer to the scene object
108
   float distance; // distance to viewer camera
109
} reflectedobject_t;
110
 
111
 
112
// definition for a material (light reflection type)
113
typedef struct material_s
114
{
115
   wchar_t name[32]; // material name
116
   float ambient; // ambient reflection value ranging from 0 to 1
117
   float diffuse; // diffuse reflection value ranging from 0 to 1
118
   float emissive; // emissive reflection value ranging from 0 to 1
119
   float specular; // specular reflection value ranging from 0 to 1
120
   float shininess; // shininess (specular factor)
121
   float transparency; // transparency value ranging from 0 (fully transparent) to 1 (opaque)
122
} material_t;
123
 
124
 
125
// definition for a mesh
126
typedef struct mesh_s
127
{
128
   unsigned long hash; // basic content hash, to avoid duplicates
129
   unsigned long vertex_format;
130
   IDirect3DVertexBuffer9 *d3dvertices; // handled opaquely by Direct3D
131
   int vertice_size;
132
   int vertice_count;
133
   bool is_indexed; // set to TRUE if this mesh has an index buffer
134
   IDirect3DIndexBuffer9 *d3dindices; // handled opaquely by Direct3D
135
   int indice_size;
136
   int indice_count;
137
} mesh_t;
138
 
139
 
140
// definition for a texture
141
typedef struct texture_s
142
{
143
   unsigned long hash; // basic content hash, to avoid duplicates
144
   int width;
145
   int height;
146
   IDirect3DTexture9 *texture;
147
} texture_t;
148
 
149
 
150
// definition for a font
151
typedef struct font_s
152
{
153
   unsigned long pathname_hash;
154
   ID3DXFont *font;
155
} font_t;
156
 
157
 
158
// definition for a sprite
159
typedef struct sprite_s
160
{
161
   unsigned long hash; // basic content hash, to avoid duplicates
162
   ID3DXSprite *sprite;
163
   int texture_index;
164
} sprite_t;
165
 
166
 
167
// global variables used in this module only
168
static IDirect3D9 *d3d = NULL; // our Direct3D interface
169
static IDirect3DDevice9 *d3ddev = NULL; // the device class
170
 
171
static material_t *materials = NULL;
172
static int material_count = 0;
173
static texture_t *textures = NULL;
174
static int texture_count = 0;
175
static mesh_t *meshes = NULL;
176
static int mesh_count = 0;
177
static font_t *fonts = NULL;
178
static int font_count = 0;
179
static sprite_t *sprites = NULL;
180
static int sprite_count = 0;
181
static const float fov_value = 45.0f; // field of view width, in degrees
182
static const float viewdist_near = 1.0f; // nearest view plane distance
183
static const float viewdist_far = 200.0f; // farthest view plane distance
6 pmbaty 184
static int initial_width = 0; // initial width of the render surface, in pixels (typically equal to the max displayable size)
185
static int initial_height = 0; // initial height of the render surface, in pixels (typically equal to the max displayable size)
1 pmbaty 186
static float current_width = 0.0f; // current width of the client area on which the render surface is rendered, in pixels
187
static float current_height = 0.0f; // current height of the client area on which the render surface is rendered, in pixels
188
static D3DCOLOR ambient_light;
189
static vector_t camera_position;
131 pmbaty 190
static vector_t scene_lookatpoint = { 0.0f, 0.0f, 0.0f };
1 pmbaty 191
static const vector_t upwards_direction = { 0.0f, 0.0f, 1.0f };
192
static int best_supported_filter;
5 pmbaty 193
static bool is_fsaa_supported = false;
1 pmbaty 194
 
195
static wchar_t printf_buffer[0xffff];
196
 
197
 
198
// prototypes of functions used in this module only
199
static bool Render_LoadMesh_X (mesh_t *mesh, const wchar_t *xfile_pathname);
200
static bool Render_LoadMesh_Obj (mesh_t *mesh, const wchar_t *objfile_pathname);
201
static void Render_DrawSceneObjectReflection (sceneobject_t *sceneobject);
202
static void Render_DrawSceneObject (sceneobject_t *sceneobject);
203
static void Render_DrawSceneTile (sceneobject_t *sceneobject);
204
static void Render_DrawSprite (sprite_t *sprite, float x_percent, float y_percent, float width_percent, float height_percent, int alpha);
124 pmbaty 205
static void Render_GetTextBoundaries (float maxwidth_percent, int font_id, wchar_t *text, RECT *rect);
206
static void Render_wprintf (float x_percent, float y_percent, float maxwidth_percent, int horiz_align, int vert_align, int text_align, int font_id, unsigned long color_rgba, RECT *out_rect, const wchar_t *fmt, ...);
1 pmbaty 207
static float DistanceToCamera (float x, float y, float z);
208
static float FadeFloat (float from, float to, float start_time, float end_time);
209
static unsigned long HashString (const wchar_t *string_buffer);
210
static unsigned long HashFile (const wchar_t *file_pathname);
211
static void ResolveWildcard (wchar_t *file_pathname, wchar_t *extensions_separated_by_bars);
212
static int SortReflectedObjects (const void *object1, const void *object2);
213
 
214
 
116 pmbaty 215
bool Render_Init (const wchar_t *fmt, ...)
1 pmbaty 216
{
217
   // this function sets up and initializes Direct3D
218
 
116 pmbaty 219
   static wchar_t splashscreen_pathname[MAX_PATH];
1 pmbaty 220
   static wchar_t *default_materialname = L"default";
116 pmbaty 221
   va_list argptr;
1 pmbaty 222
 
223
   D3DCAPS9 device_capabilities;
224
   unsigned long behaviour_flags;
5 pmbaty 225
   unsigned long multisample_quality_count;
1 pmbaty 226
   D3DPRESENT_PARAMETERS d3dpp;
2 pmbaty 227
   wchar_t errorfile_path[MAX_PATH];
1 pmbaty 228
   wchar_t line_buffer[256];
229
   material_t material;
2 pmbaty 230
   HRESULT ret;
1 pmbaty 231
   RECT rect;
6 pmbaty 232
   RECT viewport_rect;
1 pmbaty 233
   FILE *fp;
234
 
116 pmbaty 235
   // concatenate all the arguments in one string
236
   va_start (argptr, fmt);
237
   wvsprintf (splashscreen_pathname, fmt, argptr);
238
   va_end (argptr);
239
 
1 pmbaty 240
   // create the Direct3D interface
241
   d3d = Direct3DCreate9 (D3D_SDK_VERSION);
242
 
243
   // get hardware capabilities
244
   if (FAILED (d3d->GetDeviceCaps (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &device_capabilities)))
245
   {
246
      MessageBox (NULL, LOCALIZE (L"Error_CouldNotCreateD3DDevGetDeviceCapsFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);
11 pmbaty 247
      terminate_everything = true; // this is a fatal error
1 pmbaty 248
      return (false);
249
   }
250
 
251
   // grab info from that and adjust our D3D settings
252
   best_supported_filter = (device_capabilities.RasterCaps & D3DPRASTERCAPS_ANISOTROPY ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR);
253
   behaviour_flags = (device_capabilities.VertexProcessingCaps != 0 ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING);
254
 
5 pmbaty 255
   // see if simple (non-maskable) full-scene antialiasing is supported and in how many quality flavors
256
   if (SUCCEEDED (d3d->CheckDeviceMultiSampleType (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, false, D3DMULTISAMPLE_NONMASKABLE, &multisample_quality_count)))
257
      is_fsaa_supported = true; // remember FSAA is supported
1 pmbaty 258
 
259
   memset (&d3dpp, 0, sizeof (d3dpp)); // clear out the struct for use
260
   d3dpp.Windowed = true; // always windowed (because we can't display dialog boxes in fullscreen mode)
261
   d3dpp.BackBufferCount = 1;
262
   d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
263
   d3dpp.hDeviceWindow = hMainWnd; // set the window to be used by Direct3D
264
   d3dpp.EnableAutoDepthStencil = true; // enable Z-buffer and stencil buffer
265
   d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; // D3DFMT_D15S1 15 bits should be enough to store each pixel's Z depth
5 pmbaty 266
   if (is_fsaa_supported)
267
   {
268
      d3dpp.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE; // use multisampling (full scene antialiasing) if supported
269
      d3dpp.MultiSampleQuality = multisample_quality_count - 1; // use the best available multisample quality
270
   }
271
   else
272
   {
273
      d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; // do not use multisampling (full scene antialiasing)
274
      d3dpp.MultiSampleQuality = 0;
275
   }
1 pmbaty 276
 
6 pmbaty 277
   // get main window's current rectangle and full screen size
278
   GetWindowRect (hMainWnd, &rect);
279
 
280
   // create a device class using this information and the info from the d3dpp stuct. Resize the window to the max displayable
281
   // size before creating the DirectX device, so as to guarantee the viewport will never be upscaled in case of window resize.
282
   MoveWindow (hMainWnd, rect.left, rect.top, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), false);
2 pmbaty 283
   if (FAILED (ret = d3d->CreateDevice (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hMainWnd, behaviour_flags, &d3dpp, &d3ddev)))
1 pmbaty 284
   {
285
      MessageBox (NULL, LOCALIZE (L"Error_CouldNotCreateD3DDevCreateDeviceFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);
2 pmbaty 286
 
287
      // on error, write a log file on the user's desktop
288
      errorfile_path[0] = 0;
289
      SHGetSpecialFolderPath (NULL, errorfile_path, CSIDL_DESKTOP, true);
290
      wcscat_s (errorfile_path, WCHAR_SIZEOF (errorfile_path), L"\\Chess Giants error.log");
291
      _wfopen_s (&fp, errorfile_path, L"w, ccs=UNICODE");
292
      if (fp != NULL)
293
      {
294
         fwprintf (fp, L"device_capabilities.DeviceType = %d\n", device_capabilities.DeviceType);
295
         fwprintf (fp, L"device_capabilities.AdapterOrdinal = %ul\n", device_capabilities.AdapterOrdinal);
296
         fwprintf (fp, L"device_capabilities.Caps = %ul\n", device_capabilities.Caps);
297
         fwprintf (fp, L"device_capabilities.Caps2 = %ul\n", device_capabilities.Caps2);
298
         fwprintf (fp, L"device_capabilities.Caps3 = %ul\n", device_capabilities.Caps3);
299
         fwprintf (fp, L"device_capabilities.PresentationIntervals = %ul\n", device_capabilities.PresentationIntervals);
300
         fwprintf (fp, L"device_capabilities.CursorCaps = %ul\n", device_capabilities.CursorCaps);
301
         fwprintf (fp, L"device_capabilities.DevCaps = %ul\n", device_capabilities.DevCaps);
302
         fwprintf (fp, L"device_capabilities.PrimitiveMiscCaps = %ul\n", device_capabilities.PrimitiveMiscCaps);
303
         fwprintf (fp, L"device_capabilities.RasterCaps = %ul\n", device_capabilities.RasterCaps);
304
         fwprintf (fp, L"device_capabilities.ZCmpCaps = %ul\n", device_capabilities.ZCmpCaps);
305
         fwprintf (fp, L"device_capabilities.SrcBlendCaps = %ul\n", device_capabilities.SrcBlendCaps);
306
         fwprintf (fp, L"device_capabilities.DestBlendCaps = %ul\n", device_capabilities.DestBlendCaps);
307
         fwprintf (fp, L"device_capabilities.AlphaCmpCaps = %ul\n", device_capabilities.AlphaCmpCaps);
308
         fwprintf (fp, L"device_capabilities.ShadeCaps = %ul\n", device_capabilities.ShadeCaps);
309
         fwprintf (fp, L"device_capabilities.TextureCaps = %ul\n", device_capabilities.TextureCaps);
310
         fwprintf (fp, L"device_capabilities.TextureFilterCaps = %ul\n", device_capabilities.TextureFilterCaps);
311
         fwprintf (fp, L"device_capabilities.CubeTextureFilterCaps = %ul\n", device_capabilities.CubeTextureFilterCaps);
312
         fwprintf (fp, L"device_capabilities.VolumeTextureFilterCaps = %ul\n", device_capabilities.VolumeTextureFilterCaps);
313
         fwprintf (fp, L"device_capabilities.TextureAddressCaps = %ul\n", device_capabilities.TextureAddressCaps);
314
         fwprintf (fp, L"device_capabilities.VolumeTextureAddressCaps = %ul\n", device_capabilities.VolumeTextureAddressCaps);
315
         fwprintf (fp, L"device_capabilities.LineCaps = %ul\n", device_capabilities.LineCaps);
316
         fwprintf (fp, L"device_capabilities.MaxTextureWidth = %ul\n", device_capabilities.MaxTextureWidth);
317
         fwprintf (fp, L"device_capabilities.MaxTextureHeight = %ul\n", device_capabilities.MaxTextureHeight);
318
         fwprintf (fp, L"device_capabilities.MaxVolumeExtent = %ul\n", device_capabilities.MaxVolumeExtent);
319
         fwprintf (fp, L"device_capabilities.MaxTextureRepeat = %ul\n", device_capabilities.MaxTextureRepeat);
320
         fwprintf (fp, L"device_capabilities.MaxTextureAspectRatio = %ul\n", device_capabilities.MaxTextureAspectRatio);
321
         fwprintf (fp, L"device_capabilities.MaxAnisotropy = %ul\n", device_capabilities.MaxAnisotropy);
322
         fwprintf (fp, L"device_capabilities.MaxVertexW = %f\n", device_capabilities.MaxVertexW);
323
         fwprintf (fp, L"device_capabilities.GuardBandLeft = %f\n", device_capabilities.GuardBandLeft);
324
         fwprintf (fp, L"device_capabilities.GuardBandTop = %f\n", device_capabilities.GuardBandTop);
325
         fwprintf (fp, L"device_capabilities.GuardBandRight = %f\n", device_capabilities.GuardBandRight);
326
         fwprintf (fp, L"device_capabilities.GuardBandBottom = %f\n", device_capabilities.GuardBandBottom);
327
         fwprintf (fp, L"device_capabilities.ExtentsAdjust = %f\n", device_capabilities.ExtentsAdjust);
328
         fwprintf (fp, L"device_capabilities.StencilCaps = %ul\n", device_capabilities.StencilCaps);
329
         fwprintf (fp, L"device_capabilities.FVFCaps = %ul\n", device_capabilities.FVFCaps);
330
         fwprintf (fp, L"device_capabilities.TextureOpCaps = %ul\n", device_capabilities.TextureOpCaps);
331
         fwprintf (fp, L"device_capabilities.MaxTextureBlendStages = %ul\n", device_capabilities.MaxTextureBlendStages);
332
         fwprintf (fp, L"device_capabilities.MaxSimultaneousTextures = %ul\n", device_capabilities.MaxSimultaneousTextures);
333
         fwprintf (fp, L"device_capabilities.VertexProcessingCaps = %ul\n", device_capabilities.VertexProcessingCaps);
334
         fwprintf (fp, L"device_capabilities.MaxActiveLights = %ul\n", device_capabilities.MaxActiveLights);
335
         fwprintf (fp, L"device_capabilities.MaxUserClipPlanes = %ul\n", device_capabilities.MaxUserClipPlanes);
336
         fwprintf (fp, L"device_capabilities.MaxVertexBlendMatrices = %ul\n", device_capabilities.MaxVertexBlendMatrices);
337
         fwprintf (fp, L"device_capabilities.MaxVertexBlendMatrixIndex = %ul\n", device_capabilities.MaxVertexBlendMatrixIndex);
338
         fwprintf (fp, L"device_capabilities.MaxPointSize = %f\n", device_capabilities.MaxPointSize);
339
         fwprintf (fp, L"device_capabilities.MaxPrimitiveCount = %ul\n", device_capabilities.MaxPrimitiveCount);
340
         fwprintf (fp, L"device_capabilities.MaxVertexIndex = %ul\n", device_capabilities.MaxVertexIndex);
341
         fwprintf (fp, L"device_capabilities.MaxStreams = %ul\n", device_capabilities.MaxStreams);
342
         fwprintf (fp, L"device_capabilities.MaxStreamStride = %ul\n", device_capabilities.MaxStreamStride);
343
         fwprintf (fp, L"device_capabilities.VertexShaderVersion = %ul\n", device_capabilities.VertexShaderVersion);
344
         fwprintf (fp, L"device_capabilities.MaxVertexShaderConst = %ul\n", device_capabilities.MaxVertexShaderConst);
345
         fwprintf (fp, L"device_capabilities.PixelShaderVersion = %ul\n", device_capabilities.PixelShaderVersion);
346
         fwprintf (fp, L"device_capabilities.PixelShader1xMaxValue = %f\n", device_capabilities.PixelShader1xMaxValue);
347
         fwprintf (fp, L"device_capabilities.DevCaps2 = %ul\n", device_capabilities.DevCaps2);
348
         fwprintf (fp, L"device_capabilities.MaxNpatchTessellationLevel = %f\n", device_capabilities.MaxNpatchTessellationLevel);
349
         fwprintf (fp, L"device_capabilities.Reserved5 = %ul\n", device_capabilities.Reserved5);
350
         fwprintf (fp, L"device_capabilities.MasterAdapterOrdinal = %ul\n", device_capabilities.MasterAdapterOrdinal);
351
         fwprintf (fp, L"device_capabilities.AdapterOrdinalInGroup = %ul\n", device_capabilities.AdapterOrdinalInGroup);
352
         fwprintf (fp, L"device_capabilities.NumberOfAdaptersInGroup = %ul\n", device_capabilities.NumberOfAdaptersInGroup);
353
         fwprintf (fp, L"device_capabilities.DeclTypes = %ul\n", device_capabilities.DeclTypes);
354
         fwprintf (fp, L"device_capabilities.NumSimultaneousRTs = %ul\n", device_capabilities.NumSimultaneousRTs);
355
         fwprintf (fp, L"device_capabilities.StretchRectFilterCaps = %ul\n", device_capabilities.StretchRectFilterCaps);
356
         fwprintf (fp, L"device_capabilities.VS20Caps.Caps = %ul\n", device_capabilities.VS20Caps.Caps);
357
         fwprintf (fp, L"device_capabilities.VS20Caps.DynamicFlowControlDepth = %d\n", device_capabilities.VS20Caps.DynamicFlowControlDepth);
358
         fwprintf (fp, L"device_capabilities.VS20Caps.NumTemps = %d\n", device_capabilities.VS20Caps.NumTemps);
359
         fwprintf (fp, L"device_capabilities.VS20Caps.StaticFlowControlDepth = %d\n", device_capabilities.VS20Caps.StaticFlowControlDepth);
360
         fwprintf (fp, L"device_capabilities.PS20Caps.Caps = %ul\n", device_capabilities.PS20Caps.Caps);
361
         fwprintf (fp, L"device_capabilities.PS20Caps.DynamicFlowControlDepth = %d\n", device_capabilities.PS20Caps.DynamicFlowControlDepth);
362
         fwprintf (fp, L"device_capabilities.PS20Caps.NumTemps = %d\n", device_capabilities.PS20Caps.NumTemps);
363
         fwprintf (fp, L"device_capabilities.PS20Caps.StaticFlowControlDepth = %d\n", device_capabilities.PS20Caps.StaticFlowControlDepth);
364
         fwprintf (fp, L"device_capabilities.PS20Caps.NumInstructionSlots = %d\n", device_capabilities.PS20Caps.NumInstructionSlots);
365
         fwprintf (fp, L"device_capabilities.VertexTextureFilterCaps = %ul\n", device_capabilities.VertexTextureFilterCaps);
366
         fwprintf (fp, L"device_capabilities.MaxVShaderInstructionsExecuted = %ul\n", device_capabilities.MaxVShaderInstructionsExecuted);
367
         fwprintf (fp, L"device_capabilities.MaxPShaderInstructionsExecuted = %ul\n", device_capabilities.MaxPShaderInstructionsExecuted);
368
         fwprintf (fp, L"device_capabilities.MaxVertexShader30InstructionSlots = %ul\n", device_capabilities.MaxVertexShader30InstructionSlots);
369
         fwprintf (fp, L"device_capabilities.MaxPixelShader30InstructionSlots = %ul\n", device_capabilities.MaxPixelShader30InstructionSlots);
370
         fwprintf (fp, L"========\n");
371
         fwprintf (fp, L"(guessed) behaviour_flags = %ul\n", behaviour_flags);
372
         fwprintf (fp, L"========\n");
5 pmbaty 373
         fwprintf (fp, L"d3dpp.MultiSampleType = %d\n", d3dpp.MultiSampleType);
374
         fwprintf (fp, L"d3dpp.MultiSampleQuality = %d\n", d3dpp.MultiSampleQuality);
375
         fwprintf (fp, L"========\n");
2 pmbaty 376
         fwprintf (fp, L"d3d->CreateDevice() returned %d\n", (int) ret);
377
         fclose (fp);
378
 
379
         MessageBox (NULL, LOCALIZE (L"Error_GameCouldNotStartPleaseSendLogToAuthor"), LOCALIZE (L"Information"), MB_ICONINFORMATION | MB_OK);
380
      }
381
      else
382
         MessageBox (NULL, LOCALIZE (L"Error_CouldNotWriteToLogFile"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);
383
 
11 pmbaty 384
      terminate_everything = true; // this is a fatal error
1 pmbaty 385
      return (false);
386
   }
387
 
6 pmbaty 388
   // save the viewport's width and height
389
   GetClientRect (hMainWnd, &viewport_rect);
390
   initial_width = viewport_rect.right;
391
   initial_height = viewport_rect.bottom;
1 pmbaty 392
 
6 pmbaty 393
   // now resize the window to its original size
394
   MoveWindow (hMainWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, false);
395
 
1 pmbaty 396
   // set the texture parameters
397
   d3ddev->SetSamplerState (0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); // wrap textures around their edges
398
   d3ddev->SetSamplerState (0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
399
   d3ddev->SetTextureStageState (0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); // and modulate their alpha with the material's alpha
400
   d3ddev->SetTextureStageState (0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
401
   d3ddev->SetTextureStageState (0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
402
 
403
   // enable the Z buffer
404
   d3ddev->SetRenderState (D3DRS_ZENABLE, true);
405
 
406
   // disable the stencil buffer
407
   d3ddev->SetRenderState (D3DRS_STENCILENABLE, false);
408
 
409
   // normalize the face normals (if we don't, scaling will cause problems with lighting computations)
410
   d3ddev->SetRenderState (D3DRS_NORMALIZENORMALS, true);
411
 
412
   // turn on alpha blending
413
   d3ddev->SetRenderState (D3DRS_ALPHABLENDENABLE, true);
414
   d3ddev->SetRenderState (D3DRS_BLENDOP, D3DBLENDOP_ADD);
415
   d3ddev->SetRenderState (D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
416
   d3ddev->SetRenderState (D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
417
 
418
   // use all of the materials' light reflection properties
419
   d3ddev->SetRenderState (D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
420
   d3ddev->SetRenderState (D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
421
   d3ddev->SetRenderState (D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
422
   d3ddev->SetRenderState (D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
423
   d3ddev->SetRenderState (D3DRS_COLORVERTEX, false);
424
 
425
   // enable 3D lighting
426
   d3ddev->SetRenderState (D3DRS_LIGHTING, true);
427
 
116 pmbaty 428
   // load the splash screen sprite and display it
429
   int bgsprite_index = Render_LoadSprite (splashscreen_pathname);
430
   d3ddev->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB (0, 0, 0), 1.0f, 0);
431
   d3ddev->BeginScene (); // begins the 3D scene
432
   Render_DrawSprite (&sprites[bgsprite_index], 0.0f, 0.0f, 100.0f, 100.0f, 0xFF); // draw the background sprite
433
   d3ddev->EndScene (); // ends the 3D scene
434
   d3ddev->Present (NULL, NULL, NULL, NULL); // displays the created frame on the screen
435
 
1 pmbaty 436
   // open and parse the materials file and build the materials list
437
   materials = NULL;
438
   material_count = 0;
439
   _wfopen_s (&fp, L"materials.cfg", L"r, ccs=UNICODE");
440
   if (fp != NULL)
441
   {
442
      // read line per line...
443
      while (fgetws (line_buffer, WCHAR_SIZEOF (line_buffer), fp) != NULL)
444
      {
445
         // can we read a complete material line ?
446
         if (swscanf_s (line_buffer, L"\"%[^\"]\" %f %f %f %f %f %f", material.name, WCHAR_SIZEOF (material.name), &material.ambient, &material.diffuse, &material.emissive, &material.specular, &material.shininess, &material.transparency) == 7)
447
         {
448
            materials = (material_t *) SAFE_realloc (materials, material_count, material_count + 1, sizeof (material_t), false);
449
            memcpy (&materials[material_count], &material, sizeof (material_t));
450
            material_count++; // if so, append this new material to the materials array
451
         }
452
      }
453
      fclose (fp); // finished, close the file
454
   }
455
   materials = (material_t *) SAFE_realloc (materials, material_count, material_count + 1, sizeof (material_t), false);
456
   wcscpy_s (materials[material_count].name, WCHAR_SIZEOF (materials[material_count].name), default_materialname);
457
   materials[material_count].ambient = 1.0f;
458
   materials[material_count].diffuse = 1.0f;
459
   materials[material_count].emissive = 0.0f;
460
   materials[material_count].specular = 0.0f;
461
   materials[material_count].shininess = 0.0f;
462
   materials[material_count].transparency = 1.0f;
463
   material_count++; // append a default material at the end of the array and we're all set
464
 
465
   return (true); // finished
466
}
467
 
468
 
469
void Render_Shutdown (void)
470
{
471
   // this function shuts down the Direct3D interfaces and releases the Direct3D COM objects
472
 
473
   int array_index;
474
 
475
   // close and release font data
476
   SAFE_free ((void **) &fonts);
477
   font_count = 0;
478
 
479
   // close and release sprite data
480
   SAFE_free ((void **) &sprites);
481
   sprite_count = 0;
482
 
483
   // close and release meshes data
484
   if (meshes != NULL)
485
   {
486
      for (array_index = 0; array_index < mesh_count; array_index++)
487
      {
488
         if (meshes[array_index].d3dindices != NULL)
489
            meshes[array_index].d3dindices->Release ();
490
         meshes[array_index].d3dindices = NULL;
491
 
492
         if (meshes[array_index].d3dvertices != NULL)
493
            meshes[array_index].d3dvertices->Release ();
494
         meshes[array_index].d3dvertices = NULL;
495
      }
496
   }
497
   meshes = NULL;
498
   mesh_count = 0;
499
 
500
   // close and release texture data
501
   if (textures != NULL)
502
   {
503
      for (array_index = 0; array_index < texture_count; array_index++)
504
         if (textures[array_index].texture != NULL)
505
            textures[array_index].texture->Release ();
506
      SAFE_free ((void **) &textures);
507
   }
508
   texture_count = 0;
509
 
510
   // close and release materials data
511
   SAFE_free ((void **) &materials);
512
   material_count = 0;
513
 
514
   // close and release the 3D device
515
   if (d3ddev != NULL)
516
      d3ddev->Release ();
517
   d3ddev = NULL;
518
 
519
   // close and release Direct3D
520
   if (d3d != NULL)
521
      d3d->Release ();
522
   d3d = NULL;
523
 
524
   return; // finished
525
}
526
 
527
 
528
void Render_RenderFrame (scene_t *scene)
529
{
530
   // this is the function used to render a single frame
531
 
532
   static int framerate_value = 0;
533
   static int framerate_count = 0;
534
   static float framerate_time = 0;
535
 
536
   D3DXMATRIX scaling_matrix;
537
   D3DXMATRIX translation_matrix;
538
   D3DXMATRIX view_matrix; // the view transform matrix
539
   D3DXMATRIX projection_matrix; // the projection transform matrix
540
   D3DLIGHT9 dxlight;
541
   RECT rect;
542
   float angle;
543
   float sin_pitch;
544
   float sin_yaw;
545
   float cos_pitch;
546
   float cos_yaw;
547
   int light_index;
548
   int object_index;
549
   int cchistory_index;
550
   int cchistory_index2;
124 pmbaty 551
   float combinedwidth_percent;
552
   float combinedheight_percent;
1 pmbaty 553
   light_t *light;
554
   ccreply_t *ccreply;
555
   sceneobject_t *sceneobject;
556
   reflectedobject_t *reflectedobjects; // mallocated
557
   int reflectedobject_count;
558
   reflectedobject_t *otherobjects; // mallocated
559
   int otherobject_count;
560
 
11 pmbaty 561
   if (terminate_everything)
562
      return; // consistency check
563
 
1 pmbaty 564
   // get the device view port and save the actual width and height
565
   GetClientRect (hMainWnd, &rect);
566
   current_width = (float) rect.right; // they may differ from window width and window height
567
   current_height = (float) rect.bottom; // because of title bars, menus, borders, etc.
568
 
569
   // clear the back buffer, the Z buffer and the stencil buffer
570
   d3ddev->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB (0, 0, 0), 1.0f, 0);
571
   d3ddev->BeginScene (); // begins the 3D scene
572
 
573
   ////////////////////////////////////////
574
   // Setup scene lights
575
 
576
   // There are three types of light : ambient, diffuse and specular.
577
   // Diffuse lights can be of type directional (sun), point (bulb) or spot (flashlight).
578
 
579
   // The attenuation formula for point lights is :
580
   // Atten = 1 / (att0 + (att1 * d) + (att2 * d²))
581
 
582
   // In spot lights, Phi is the outer cone angle. Theta is the inner cone angle.
583
 
584
   // set the default lighting color
585
   ambient_light = RGBACOLOR_TO_ARGBCOLOR (RGBACOLOR_FULLALPHA (theme->illum.ambient_light));
586
   d3ddev->SetRenderState (D3DRS_AMBIENT, ambient_light);
587
 
588
   // for each light...
589
   for (light_index = 0; light_index < theme->illum.light_count; light_index++)
590
   {
591
      light = &theme->illum.lights[light_index]; // quick access to light
592
 
593
      memset (&dxlight, 0, sizeof (dxlight)); // clear out the dxlight struct for use
594
 
595
      // set its type
596
      if (light->type == LIGHT_DIRECTIONAL)
597
         dxlight.Type = D3DLIGHT_DIRECTIONAL; // directional light (e.g, sun)
598
      else if (light->type == LIGHT_POINT)
599
         dxlight.Type = D3DLIGHT_POINT; // point light (e.g, light bulb)
600
      else if (light->type == LIGHT_SPOT)
601
         dxlight.Type = D3DLIGHT_SPOT; // spot light (e.g, flash light)
602
      else
603
      {
604
         d3ddev->LightEnable (light_index, false); // unknown light ; turn off light #index
605
         continue; // and proceed to the next one
606
      }
607
 
608
      // set its parameters
609
      dxlight.Diffuse = D3DXCOLOR (RGBACOLOR_TO_ARGBCOLOR (RGBACOLOR_FULLALPHA (light->color)));
610
      dxlight.Specular = D3DXCOLOR (0xffffffff);
611
      dxlight.Position.x = light->pos_x;
612
      dxlight.Position.y = light->pos_y;
613
      dxlight.Position.z = light->pos_z;
614
      dxlight.Direction.x = light->direction_x;
615
      dxlight.Direction.y = light->direction_y;
616
      dxlight.Direction.z = light->direction_z;
617
      dxlight.Range = light->range; // light won't be computed after this distance
618
      dxlight.Attenuation0 = light->attenuation_constant; // constant attenuation, see formula
619
      dxlight.Attenuation1 = light->attenuation_proportional; // proportional attenuation, see formula
620
      dxlight.Attenuation2 = light->attenuation_square; // square attenuation, see formula
621
      dxlight.Phi = light->cone_outer * TO_RADIANS; // outer spot cone
622
      dxlight.Theta = light->cone_inner * TO_RADIANS; // inner spot cone
623
 
624
      d3ddev->SetLight (light_index, &dxlight); // send the light struct properties to light #index
625
      d3ddev->LightEnable (light_index, true); // turn on light #index
626
   }
627
 
628
   ////////////////////////////////
629
   // View transform
630
 
131 pmbaty 631
   // update the point looked at
632
   scene_lookatpoint.x = lookatpoint_x;
633
   scene_lookatpoint.y = lookatpoint_y;
634
 
1 pmbaty 635
   // compute the sine and cosine of the pitch component
636
   angle = current_pitch * TO_RADIANS;
637
   sin_pitch = sinf (angle);
638
   cos_pitch = cosf (angle);
639
 
640
   // compute the sine and cosine of the yaw component
641
   angle = current_yaw * TO_RADIANS;
642
   sin_yaw = sinf (angle);
643
   cos_yaw = cosf (angle);
644
 
645
   // build the camera position
131 pmbaty 646
   camera_position.x = scene_lookatpoint.x + (float) -(cos_pitch * cos_yaw) * current_distance;
647
   camera_position.y = scene_lookatpoint.y + (float) -(cos_pitch * sin_yaw) * current_distance;
1 pmbaty 648
   camera_position.z = (float) sin_pitch * current_distance;
649
 
650
   // set up a view matrix
651
   D3DXMatrixLookAtLH (&view_matrix,
652
                       (D3DXVECTOR3 *) &camera_position, // camera position
131 pmbaty 653
                       (D3DXVECTOR3 *) &scene_lookatpoint, // look-at position
1 pmbaty 654
                       (D3DXVECTOR3 *) &upwards_direction); // up direction
655
 
656
   // tell Direct3D about our matrix
657
   d3ddev->SetTransform (D3DTS_VIEW, &view_matrix);
658
 
659
   /////////////////////////////////////
660
   // Projection transform
661
 
662
   // set up a projection matrix
663
   D3DXMatrixPerspectiveFovLH (&projection_matrix,
664
                               fov_value * TO_RADIANS, // field of view width
665
                               current_width / current_height, // aspect ratio
666
                               viewdist_near, viewdist_far); // view plane distances
667
 
668
   // tell Direct3D about our matrix
669
   d3ddev->SetTransform (D3DTS_PROJECTION, &projection_matrix);
670
 
671
   /////////////////////////////////////
672
   // End of the transforms
673
 
674
   // if we want it, enable specular lighting
675
   d3ddev->SetRenderState (D3DRS_SPECULARENABLE, options.want_specularlighting);
676
 
677
   // turn on texture filtering if needed
678
   if (options.want_filtering)
679
   {
680
      d3ddev->SetSamplerState (0, D3DSAMP_MINFILTER, best_supported_filter);
681
      d3ddev->SetSamplerState (0, D3DSAMP_MAGFILTER, best_supported_filter);
682
      d3ddev->SetSamplerState (0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
683
 
684
      // turn on fullscene antialiasing only if capable
5 pmbaty 685
      d3ddev->SetRenderState (D3DRS_MULTISAMPLEANTIALIAS, is_fsaa_supported);
1 pmbaty 686
   }
687
   else
688
   {
689
      d3ddev->SetSamplerState (0, D3DSAMP_MINFILTER, D3DTEXF_NONE);
690
      d3ddev->SetSamplerState (0, D3DSAMP_MAGFILTER, D3DTEXF_NONE);
691
      d3ddev->SetSamplerState (0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
692
 
693
      // turn off fullscene antialiasing
694
      d3ddev->SetRenderState (D3DRS_MULTISAMPLEANTIALIAS, false);
695
   }
696
 
697
   /////////////////////////////////////////////////////////////
698
   // draw the background elements. No need for a Z buffer here.
699
 
700
   d3ddev->SetRenderState (D3DRS_ZENABLE, false); // disable depth testing
701
 
702
   // draw the background sprite, if any
703
   if (scene->background_spriteindex >= 0)
704
      Render_DrawSprite (&sprites[scene->background_spriteindex], 0.0f, 0.0f, 100.0f, 100.0f, 0xFF);
705
 
706
   // draw the table border
707
   Render_DrawSceneObject (&scene->objects[0]);
708
   Render_DrawSceneObject (&scene->objects[1]);
709
 
710
   // draw the table and build the stencil buffer at the same time
711
   d3ddev->SetRenderState (D3DRS_STENCILENABLE, true); // enable the stencil buffer (i.e. the "frame" for drawing table reflections)
712
   d3ddev->SetRenderState (D3DRS_STENCILFUNC, D3DCMP_ALWAYS); // instruct how to fill it
713
   d3ddev->SetRenderState (D3DRS_STENCILPASS, D3DSTENCILOP_INCRSAT); // instruct how to fill it
714
   Render_DrawSceneObject (&scene->objects[2]); // draw the table squares in the stencil buffer
715
   d3ddev->SetRenderState (D3DRS_STENCILENABLE, false); // finished drawing the stencil buffer
716
 
717
   d3ddev->SetRenderState (D3DRS_ZENABLE, true); // re-enable depth testing
718
 
719
   ////////////////////////////////////////////////////////////
720
   // draw the scene objects and their reflections on the table
721
 
722
   // start with the reflections if we want them, and if the table does it
723
   if (options.want_reflections && (theme->reflection_alpha > 0))
724
   {
725
      // build an array of reflected objects with their distances
726
      reflectedobjects = NULL;
727
      reflectedobject_count = 0;
728
      otherobjects = NULL;
729
      otherobject_count = 0;
730
 
731
      // cycle through all parts and see which ones need to be reflected
732
      for (object_index = 3; object_index < scene->object_count; object_index++)
733
      {
734
         sceneobject = &scene->objects[object_index]; // quick access to scene object
735
 
736
         // is this object a mesh AND it's above the ground ?
737
         if ((sceneobject->mesh_index != -1) && (sceneobject->z > 0))
738
         {
739
            // yes it is. It thus needs to be reflected, so add it to the list
740
            reflectedobjects = (reflectedobject_t *) SAFE_realloc (reflectedobjects, reflectedobject_count, reflectedobject_count + 1, sizeof (reflectedobject_t), false);
741
            reflectedobjects[reflectedobject_count].object = sceneobject; // save scene object
742
            reflectedobjects[reflectedobject_count].distance = DistanceToCamera (sceneobject->x, sceneobject->y, sceneobject->z);
743
            reflectedobject_count++; // we have now one object more to reflect
744
         }
745
         else
746
         {
747
            // no it's not. It doesn't need to be reflected, so add it to the other list
748
            otherobjects = (reflectedobject_t *) SAFE_realloc (otherobjects, otherobject_count, otherobject_count + 1, sizeof (reflectedobject_t), false);
749
            otherobjects[otherobject_count].object = sceneobject; // save scene object
750
            otherobjects[otherobject_count].distance = 0;
751
            otherobject_count++; // we have now one object more to reflect
752
         }
753
      }
754
 
755
      // now sort them from farthest to closest and draw them in this order
756
      qsort (reflectedobjects, reflectedobject_count, sizeof (reflectedobject_t), SortReflectedObjects);
757
      for (object_index = 0; object_index < reflectedobject_count; object_index++)
758
         Render_DrawSceneObjectReflection (reflectedobjects[object_index].object); // draw the reflection
759
      for (object_index = 0; object_index < reflectedobject_count; object_index++)
760
         Render_DrawSceneObject (reflectedobjects[object_index].object); // and draw the objects afterwards
761
      for (object_index = 0; object_index < otherobject_count; object_index++)
762
         Render_DrawSceneObject (otherobjects[object_index].object); // finally, draw the non-reflected objects
763
 
764
      SAFE_free ((void **) &reflectedobjects); // and free the reflected objects array
765
      SAFE_free ((void **) &otherobjects); // and the non-reflected objects array
766
   }
767
   else
768
      for (object_index = 3; object_index < scene->object_count; object_index++)
769
         Render_DrawSceneObject (&scene->objects[object_index]); // else if no reflections, draw the objects, the Z-buffer will sort them
770
 
771
   // draw the overlay texture if required
772
   if (scene->overlay_spriteindex >= 0)
773
      Render_DrawSprite (&sprites[scene->overlay_spriteindex], 0.0f, 0.0f, 100.0f, 100.0f, 0x4F);
774
 
775
   ///////////////
776
   // draw the GUI
777
 
124 pmbaty 778
   DRAW_BUTTON_IF_NEEDED (scene->gui.newgamebutton); // new game
779
   DRAW_BUTTON_IF_NEEDED (scene->gui.opengamebutton); // open game
780
 
1 pmbaty 781
   // draw the arrows
140 pmbaty 782
   DRAW_BUTTON_IF_NEEDED (scene->gui.llarrow); // "jump to beginning" arrow
783
   DRAW_BUTTON_IF_NEEDED (scene->gui.larrow); // "previous move" arrow
784
   DRAW_BUTTON_IF_NEEDED (scene->gui.rarrow); // "next move" arrow
785
   DRAW_BUTTON_IF_NEEDED (scene->gui.rrarrow); // "jump to end" arrow
1 pmbaty 786
   DRAW_TEXT_IF_NEEDED (scene->gui.arrow_text); // arrow text
787
 
788
   if (want_framerate)
124 pmbaty 789
      Render_wprintf (99.0f, 1.0f, 0.0f, ALIGN_RIGHT, ALIGN_TOP, ALIGN_CENTER, arrow_fontindex, D3DCOLOR_RGBA (255, 255, 255, 255), NULL,
1 pmbaty 790
                      L"%d textures\n"
791
                      L"%d meshes\n"
792
                      L"%d fonts\n"
793
                      L"%d sprites\n"
794
                      L"%d fps", texture_count, mesh_count, font_count, sprite_count, framerate_value);
795
 
796
   // draw the other GUI buttons
797
   DRAW_BUTTON_IF_NEEDED (scene->gui.chatbutton); // chat button
798
   DRAW_BUTTON_IF_NEEDED (scene->gui.gamesbutton); // games button
799
   DRAW_BUTTON_IF_NEEDED (scene->gui.peoplebutton); // people button
800
 
801
   // does the parts pick line need to be displayed ?
802
   if (scene->gui.is_partspick_displayed)
803
   {
804
#define PARTSIZE_PCT (100.0f / 13.0f)
805
 
806
      if (scene->gui.partspick_selectedpart == 'P')      Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  0.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
807
      else if (scene->gui.partspick_selectedpart == 'R') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  1.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
808
      else if (scene->gui.partspick_selectedpart == 'N') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  2.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
809
      else if (scene->gui.partspick_selectedpart == 'B') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  3.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
810
      else if (scene->gui.partspick_selectedpart == 'Q') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  4.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
811
      else if (scene->gui.partspick_selectedpart == 'K') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  5.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
812
      else if (scene->gui.partspick_selectedpart == ' ') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  6.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
813
      else if (scene->gui.partspick_selectedpart == 'k') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  7.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
814
      else if (scene->gui.partspick_selectedpart == 'q') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  8.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
815
      else if (scene->gui.partspick_selectedpart == 'b') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex],  9.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
816
      else if (scene->gui.partspick_selectedpart == 'n') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 10.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
817
      else if (scene->gui.partspick_selectedpart == 'r') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 11.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
818
      else if (scene->gui.partspick_selectedpart == 'p') Render_DrawSprite (&sprites[theme->lastmovetarget_spriteindex], 12.0f * PARTSIZE_PCT, 0.0f, PARTSIZE_PCT, 11.0f, 0xFF);
819
 
820
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_PAWN]],       0.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'P') || (scene->gui.partspick_selectedpart == 'P')) ? 0xFF : 0x7F)); // white pawn
821
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_ROOK]],       1.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'R') || (scene->gui.partspick_selectedpart == 'R')) ? 0xFF : 0x7F)); // white rook
822
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_KNIGHT]],     2.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'N') || (scene->gui.partspick_selectedpart == 'N')) ? 0xFF : 0x7F)); // white knight
823
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_BISHOP]],     3.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'B') || (scene->gui.partspick_selectedpart == 'B')) ? 0xFF : 0x7F)); // white bishop
824
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_QUEEN]],      4.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'Q') || (scene->gui.partspick_selectedpart == 'Q')) ? 0xFF : 0x7F)); // white queen
825
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_WHITE][PART_KING]],       5.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'K') || (scene->gui.partspick_selectedpart == 'K')) ? 0xFF : 0x7F)); // white king
826
      Render_DrawSprite (&sprites[theme->lastmovesource_spriteindex],         6.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == ' ') || (scene->gui.partspick_selectedpart == ' ')) ? 0xFF : 0x7F)); // erase mark
827
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_KING]],       7.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'k') || (scene->gui.partspick_selectedpart == 'k')) ? 0xFF : 0x7F)); // black king
828
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_QUEEN]],      8.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'q') || (scene->gui.partspick_selectedpart == 'q')) ? 0xFF : 0x7F)); // black queen
829
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_BISHOP]],     9.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'b') || (scene->gui.partspick_selectedpart == 'b')) ? 0xFF : 0x7F)); // black bishop
830
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_KNIGHT]],    10.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'n') || (scene->gui.partspick_selectedpart == 'n')) ? 0xFF : 0x7F)); // black knight
831
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_ROOK]],      11.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'r') || (scene->gui.partspick_selectedpart == 'r')) ? 0xFF : 0x7F)); // black rook
832
      Render_DrawSprite (&sprites[theme->flatsprites[COLOR_BLACK][PART_PAWN]],      12.0f * PARTSIZE_PCT, 0, PARTSIZE_PCT, 11.0f, (((scene->gui.partspick_hoveredpart == 'p') || (scene->gui.partspick_selectedpart == 'p')) ? 0xFF : 0x7F)); // black pawn
833
 
834
#undef PARTSIZE_PCT
835
   }
836
 
837
   // draw GUI texts
838
   DRAW_TEXT_IF_NEEDED (scene->gui.comment_text); // move comments
839
   DRAW_TEXT_IF_NEEDED (scene->gui.history_text); // game history
840
   DRAW_TEXT_IF_NEEDED (scene->gui.clock_text); // game clock
841
 
842
   // draw the chatter channels text
843
   Render_GetTextBoundaries (-1, chat_fontindex, L"a", &rect);
124 pmbaty 844
   combinedheight_percent = (float) (rect.bottom * 100 / initial_height); // get a string's height
1 pmbaty 845
 
846
   // cycle through all the chat strings...
847
   ccreply = NULL;
848
   for (cchistory_index = 0; cchistory_index < scene->gui.cchistory_count; cchistory_index++)
849
   {
850
      ccreply = &scene->gui.cchistory[cchistory_index]; // quick access to CC reply
851
      if ((ccreply->text[0] != 0) && (ccreply->arrival_time + 60.0f > current_time))
852
         break; // break at the first one that we should display
853
   }
854
 
855
   // have we some to display ?
856
   if (cchistory_index < scene->gui.cchistory_count)
857
   {
858
      // first, get the remaining text's combined height
859
      for (cchistory_index2 = cchistory_index; cchistory_index2 < scene->gui.cchistory_count; cchistory_index2++)
860
      {
861
         ccreply = &scene->gui.cchistory[cchistory_index2]; // quick access to CC reply
862
 
124 pmbaty 863
         combinedwidth_percent = 1.0f;
864
         Render_GetTextBoundaries (100 - combinedwidth_percent, chat_fontindex, L"[] : ", &rect);
865
         combinedwidth_percent += (float) (rect.right * 100 / initial_width);
866
         Render_GetTextBoundaries (100 - combinedwidth_percent, chat_fontindex, ccreply->channelname, &rect);
867
         combinedwidth_percent += (float) (rect.right * 100 / initial_width);
868
         Render_GetTextBoundaries (100 - combinedwidth_percent, chat_fontindex, ccreply->nickname, &rect);
869
         combinedwidth_percent += (float) (rect.right * 100 / initial_width);
870
         Render_GetTextBoundaries (100 - combinedwidth_percent, chat_fontindex, ccreply->text, &rect);
871
         combinedheight_percent += (float) (rect.bottom * 100 / initial_height); // add this string's height 
1 pmbaty 872
      }
873
 
874
      // now for each string remaining...
875
      for (; cchistory_index < scene->gui.cchistory_count; cchistory_index++)
876
      {
877
         ccreply = &scene->gui.cchistory[cchistory_index]; // quick access to CC reply
878
         rect.right = 10;
879
         PRINT_CCREPLY (ccreply); // print CC reply on screen
124 pmbaty 880
         combinedheight_percent -= (float) ((rect.bottom - rect.top) * 100 / initial_height); // draw it from top of zone to bottom
1 pmbaty 881
      }
882
   }
883
 
884
   // are we online ?
885
   if (Player_FindByType (PLAYER_INTERNET) != NULL)
886
   {
887
      ccreply = &scene->gui.entered_ccreply;
888
      if (!scene->gui.is_entering_text)
889
         ccreply->color = RGBACOLOR_SETALPHA (ccreply->color, RGBACOLOR_ALPHA (ccreply->color) / 6); // if there's no text being entered, fade CC reply a lot
890
 
891
      rect.right = 10;
892
      PRINT_CCREPLY (ccreply); // print CC reply on screen
893
   }
894
 
895
   // print GUI texts
896
   DRAW_TEXT_IF_NEEDED (scene->gui.turn_text); // player turn's text
897
   DRAW_TEXT_IF_NEEDED (scene->gui.central_text); // central notification zone text
898
 
899
   // if needed, print the spinning wheel
900
   if (scene->gui.want_spinwheel)
901
      Render_DrawSprite (&sprites[spinner_spriteindex[(int) (10.0f * current_time) % 12]], 47.0f, 46.0f, 6.0f, 8.0f, 255);
902
 
903
   // are we in demo mode ? if so, display the program name as a watermark
164 pmbaty 904
#ifndef NO_REGISTRATION
14 pmbaty 905
   if (!is_registered)
124 pmbaty 906
      Render_wprintf (50.0f, 60.0f, 0.0f, ALIGN_CENTER, ALIGN_CENTER, ALIGN_CENTER, chat_fontindex,
18 pmbaty 907
                      D3DCOLOR_RGBA (255, 255, 255, 255),
14 pmbaty 908
                      NULL, PROGRAM_NAME L"%s - " PROGRAM_URL L"\n- %d:%02d -", LOCALIZE (L"EvaluationMode"), (int) (DEMO_TIMEOUT - current_time) / 60, (int) (DEMO_TIMEOUT - current_time) % 60);
164 pmbaty 909
#endif // !NO_REGISTRATION
1 pmbaty 910
 
911
   // end 3D rendering on the back buffer
912
   //////////////////////////////////////
913
 
914
   d3ddev->EndScene (); // ends the 3D scene
915
   d3ddev->Present (NULL, NULL, NULL, NULL); // displays the created frame on the screen
916
 
917
   // update the frame rate
918
   if (framerate_time < current_time)
919
   {
920
      framerate_value = framerate_count;
921
      framerate_count = 0;
922
      framerate_time = current_time + 1.0f;
923
   }
924
   framerate_count++; // one frame more elapsed
925
 
926
   return; // finished
927
}
928
 
929
 
930
int Render_LoadMesh (const wchar_t *fmt, ...)
931
{
932
   // this function appends a new mesh in the global meshes buffer and returns its index
933
 
934
   static wchar_t meshfile_pathname[MAX_PATH];
935
   unsigned long hash;
936
   mesh_t *mesh;
937
   int mesh_index;
938
   va_list argptr;
939
 
940
   // concatenate all the arguments in one string
941
   va_start (argptr, fmt);
942
   wvsprintf (meshfile_pathname, fmt, argptr);
943
   va_end (argptr);
944
 
945
   // resolve wildcards and get content hash
946
   ResolveWildcard (meshfile_pathname, L".obj");
947
   hash = HashFile (meshfile_pathname);
948
 
949
   // now cycle through all our loaded meshes and see if it's already loaded
950
   for (mesh_index = 0; mesh_index < mesh_count; mesh_index++)
951
      if (meshes[mesh_index].hash == hash)
952
         return (mesh_index); // if we can find it, return its index so as not to load it twice
953
 
954
   // reallocate space to hold one mesh more
955
   meshes = (mesh_t *) SAFE_realloc (meshes, mesh_count, mesh_count + 1, sizeof (mesh_t), false);
956
   mesh = &meshes[mesh_count]; // quick access to the mesh we'll be working on
957
 
958
   // load the mesh
959
   if (!Render_LoadMesh_Obj (mesh, meshfile_pathname))
960
      return (-1); // bomb out on error
961
 
962
   mesh->hash = hash; // save the hash
963
   mesh_count++; // we know now one mesh more
964
   return (mesh_count - 1); // return its index
965
}
966
 
967
 
968
int Render_LoadTexture (const wchar_t *fmt, ...)
969
{
970
   // this function appends a new texture in the global textures buffer and returns its index
971
 
972
   D3DSURFACE_DESC texture_description;
973
   wchar_t texturefile_pathname[MAX_PATH];
974
   static wchar_t *filename;
975
   unsigned long hash;
976
   int texture_index;
977
   va_list argptr;
978
 
979
   // concatenate all the arguments in one string
980
   va_start (argptr, fmt);
981
   wvsprintf (texturefile_pathname, fmt, argptr);
982
   va_end (argptr);
983
 
984
   // resolve wildcards and get content hash
985
   ResolveWildcard (texturefile_pathname, L".dds|.jpg|.jpeg|.png|.tga|.bmp");
986
   hash = HashFile (texturefile_pathname);
987
 
988
   // now cycle through all our loaded textures and see if it's already loaded
989
   for (texture_index = 0; texture_index < texture_count; texture_index++)
990
      if (textures[texture_index].hash == hash)
991
         return (texture_index); // if we can find it, return its index so as not to load it twice
992
 
993
   // reallocate space to hold one texture more
994
   textures = (texture_t *) SAFE_realloc (textures, texture_count, texture_count + 1, sizeof (texture_t), false);
995
 
996
   // ask Direct3D to prepare texture data
997
   if (FAILED (D3DXCreateTextureFromFile (d3ddev, texturefile_pathname, &textures[texture_count].texture)))
998
   {
999
      MessageBox (NULL, LOCALIZE (L"Error_UnableToAddTextureD3DXCreateTextureFromFileFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);
11 pmbaty 1000
      terminate_everything = true; // this is a fatal error
1 pmbaty 1001
      return (-1); // bomb out on error
1002
   }
1003
 
1004
   // get info on the newly loaded texture such as size etc.
1005
   textures[texture_count].texture->GetLevelDesc (0, &texture_description);
1006
   textures[texture_count].width = texture_description.Width; // save texture width (as loaded)
1007
   textures[texture_count].height = texture_description.Height; // save texture height (as loaded)
1008
   textures[texture_count].hash = hash; // save its hash
1009
   texture_count++; // we know now one texture more
1010
   return (texture_count - 1); // return its index
1011
}
1012
 
1013
 
1014
int Render_LoadFont (const wchar_t *font_name, int font_size, bool is_bold, bool is_italic)
1015
{
1016
   // this function appends a new font in the global fonts buffer and returns its index
1017
 
1018
   unsigned long pathname_hash;
1019
   int font_index;
1020
 
1021
   // first, get the hash of the requested pathname (include font size and weight parameters)
1022
   pathname_hash = HashString (font_name);
1023
   pathname_hash += 3 * (unsigned long) font_size + 2 * (unsigned long) is_bold + (unsigned long) is_italic;
1024
 
1025
   // now cycle through all our loaded fonts and see if it's already loaded
1026
   for (font_index = 0; font_index < font_count; font_index++)
1027
      if (fonts[font_index].pathname_hash == pathname_hash)
1028
         return (font_index); // if we can find it, return its index so as not to load it twice
1029
 
1030
   // reallocate space to hold one font more
1031
   fonts = (font_t *) SAFE_realloc (fonts, font_count, font_count + 1, sizeof (font_t), false);
1032
 
1033
   // create a Direct3D font object and record font data
1034
   if (FAILED (D3DXCreateFont (d3ddev, font_size, // font height
12 pmbaty 1035
                               2 * font_size / 5, // font width
1 pmbaty 1036
                               (is_bold ? FW_BOLD : FW_NORMAL), // font weight (bold, etc)
1037
                               0, // miplevels
1038
                               is_italic, // is italic
1039
                               DEFAULT_CHARSET, // charset
1040
                               OUT_DEFAULT_PRECIS, // precision
1041
                               CLEARTYPE_QUALITY, // font quality (antialiased or not)
1042
                               DEFAULT_PITCH | FF_DONTCARE, // font family
1043
                               font_name, // font name
1044
                               &fonts[font_count].font))) // and a pointer that will receive the font
1045
   {
1046
      MessageBox (NULL, LOCALIZE (L"Error_UnableToAddFontD3DXCreateFontFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);
11 pmbaty 1047
      terminate_everything = true; // this is a fatal error
1 pmbaty 1048
      return (-1); // bomb out on error
1049
   }
1050
 
1051
   fonts[font_count].pathname_hash = pathname_hash; // save its hash
1052
   font_count++; // we know now one font more
1053
   return (font_count - 1); // return its index
1054
}
1055
 
1056
 
1057
int Render_LoadSprite (const wchar_t *fmt, ...)
1058
{
1059
   // this function appends a new sprite in the global sprites buffer and returns its index
1060
 
1061
   wchar_t spritefile_pathname[MAX_PATH];
1062
   unsigned long hash;
1063
   int sprite_index;
1064
   va_list argptr;
1065
 
1066
   // concatenate all the arguments in one string
1067
   va_start (argptr, fmt);
1068
   wvsprintf (spritefile_pathname, fmt, argptr);
1069
   va_end (argptr);
1070
 
1071
   // resolve wildcards and get content hash
1072
   ResolveWildcard (spritefile_pathname, L".dds|.jpg|.jpeg|.png|.tga|.bmp");
1073
   hash = HashFile (spritefile_pathname);
1074
 
1075
   // now cycle through all our loaded sprites and see if it's already loaded
1076
   for (sprite_index = 0; sprite_index < sprite_count; sprite_index++)
1077
      if (sprites[sprite_index].hash == hash)
1078
         return (sprite_index); // if we can find it, return its index so as not to load it twice
1079
 
1080
   // reallocate space to hold one sprite more
1081
   sprites = (sprite_t *) SAFE_realloc (sprites, sprite_count, sprite_count + 1, sizeof (sprite_t), false);
1082
 
1083
   // ask Direct3D to prepare texture data
1084
   if (FAILED (D3DXCreateSprite (d3ddev, &sprites[sprite_count].sprite)))
1085
   {
1086
      MessageBox (NULL, LOCALIZE (L"Error_UnableToAddSpriteD3DXCreateSpriteFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);
11 pmbaty 1087
      terminate_everything = true; // this is a fatal error
1 pmbaty 1088
      return (-1); // bomb out on error
1089
   }
1090
   sprites[sprite_count].texture_index = Render_LoadTexture (spritefile_pathname); // register and save sprite texture
1091
   sprites[sprite_count].hash = hash; // save its hash
1092
 
1093
   sprite_count++; // we know now one sprite more
1094
   return (sprite_count - 1); // return its index
1095
}
1096
 
1097
 
1098
int Render_MaterialIndexOf (const wchar_t *material_name)
1099
{
1100
   // this function returns the index of the material in the global materials array which has the specified name
1101
 
1102
   int material_index;
1103
 
1104
   // cycle through all materials and look whether one with the specified name exists
1105
   for (material_index = 0; material_index < material_count; material_index++)
1106
      if (_wcsicmp (materials[material_index].name, material_name) == 0)
1107
         return (material_index); // if we find one, return its index
1108
 
1109
   return (material_count - 1); // else return the index of the last material in list, which is the default material
1110
}
1111
 
1112
 
1113
void Render_MouseToFloor (short mouse_x, short mouse_y, float *floor_x, float *floor_y)
1114
{
1115
   // this function converts a mouse coordinates into floor coordinates by doing vector
1116
   // projection on the floor plane from the eyepoint of the camera
1117
 
1118
   static D3DXPLANE floor_plane;
1119
   static bool is_planefound = false;
1120
 
1121
   D3DXMATRIX projection_matrix;
1122
   D3DXMATRIX view_matrix;
1123
   D3DXMATRIX invertedview_matrix;
1124
   float mouse_pitch;
1125
   float mouse_yaw;
1126
   vector_t v_lookat;
1127
   vector_t v_intersection;
1128
 
1129
   // find the floor plane (only do it once)
1130
   if (!is_planefound)
1131
   {
131 pmbaty 1132
      D3DXPlaneFromPointNormal (&floor_plane, (D3DXVECTOR3 *) &scene_lookatpoint, (D3DXVECTOR3 *) &upwards_direction);
1 pmbaty 1133
      is_planefound = true; // once and for all, as this plane will never change
1134
   }
1135
 
1136
   // get the current projection and view matrices, and invert the view matrix
1137
   d3ddev->GetTransform (D3DTS_PROJECTION, &projection_matrix);
1138
   d3ddev->GetTransform (D3DTS_VIEW, &view_matrix);
1139
   D3DXMatrixInverse (&invertedview_matrix, NULL, &view_matrix);
1140
 
1141
   // convert the mouse coordinates to relative pitch and yaw
1142
   mouse_pitch =  (((mouse_x * 2.0f) / current_width) - 1) / projection_matrix._11;
1143
   mouse_yaw = -(((mouse_y * 2.0f) / current_height) - 1) / projection_matrix._22;
1144
 
1145
   // now build a matrix that will describe the mouse direction vector, add it to the camera position, and make it 200 times longer
1146
   v_lookat.x = camera_position.x + (mouse_pitch * invertedview_matrix._11 + mouse_yaw * invertedview_matrix._21 + invertedview_matrix._31) * 200.0f;
1147
   v_lookat.y = camera_position.y + (mouse_pitch * invertedview_matrix._12 + mouse_yaw * invertedview_matrix._22 + invertedview_matrix._32) * 200.0f;
1148
   v_lookat.z = camera_position.z + (mouse_pitch * invertedview_matrix._13 + mouse_yaw * invertedview_matrix._23 + invertedview_matrix._33) * 200.0f;
1149
 
1150
   // and the intersection point with our ray
1151
   D3DXPlaneIntersectLine ((D3DXVECTOR3 *) &v_intersection, &floor_plane, (D3DXVECTOR3 *) &camera_position, (D3DXVECTOR3 *) &v_lookat);
1152
 
1153
   // now fill the return values
1154
   *floor_x = v_intersection.x;
1155
   *floor_y = v_intersection.y;
1156
 
1157
   return; // finished
1158
}
1159
 
1160
 
1161
bool Render_IsMouseInBox (short mouse_x, short mouse_y, float x_percent, float y_percent, float width_percent, float height_percent)
1162
{
1163
   // helper function that returns whether the mouse coordinates are inside a given square
1164
 
1165
   float mousex_percent;
1166
   float mousey_percent;
1167
 
1168
   // compute mouse coordinates in percents
136 pmbaty 1169
   mousex_percent = (float) mouse_x * 100.0f / current_width;
1170
   mousey_percent = (float) mouse_y * 100.0f / current_height;
1 pmbaty 1171
 
1172
   return ((mousex_percent >= x_percent) && (mousex_percent <= x_percent + width_percent)
1173
           && (mousey_percent >= y_percent) && (mousey_percent <= y_percent + height_percent));
1174
}
1175
 
1176
 
1177
static bool Render_LoadMesh_Obj (mesh_t *mesh, const wchar_t *objfile_pathname)
1178
{
1179
   // this function loads a mesh from a Wavefront Object file (.obj)
1180
 
1181
   #define OBJ_INCREASE_OR_RESIZE(count,maxcount,increment,arrayptr,type,erase) { \
1182
      (count)++; \
1183
      if ((count) == (maxcount)) \
1184
      { \
1185
         (arrayptr) = (type *) SAFE_realloc ((arrayptr), (maxcount), (maxcount) + (increment), sizeof (type), erase); \
1186
         (maxcount) += (increment); \
1187
      } \
1188
   }
1189
   #define OBJ_CONVERT_INDEX(element,current_element_count) if ((element) < 0) (element) = (current_element_count) + (element); else (element)--;
1190
   #define OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX(uniquevertex) \
1191
   { \
1192
      hash = &hashtable[*((unsigned long *) &obj.vs[(uniquevertex).iv].x) & 0xFF]; \
1193
      for (vertex_index = 0; vertex_index < hash->count; vertex_index++) \
1194
         if ((memcmp (&vertices[hash->indices[vertex_index]].position, &obj.vs[(uniquevertex).iv], sizeof (vector_t)) == 0) \
1195
             && (memcmp (&vertices[hash->indices[vertex_index]].normal, &obj.ns[(uniquevertex).in], sizeof (vector_t)) == 0) \
1196
             && (memcmp (&vertices[hash->indices[vertex_index]].texcoord, &obj.tcs[(uniquevertex).itc], sizeof (texcoord_t)) == 0)) \
1197
            break; \
1198
      if (vertex_index == hash->count) \
1199
      { \
1200
         vertex_index = mesh->vertice_count; \
1201
         current_vertex = &vertices[vertex_index]; \
1202
         memset (current_vertex, 0, sizeof (vertex_t)); \
1203
         memcpy (&current_vertex->position, &obj.vs[(uniquevertex).iv], sizeof (vector_t)); \
1204
         if ((uniquevertex).in > -1) \
1205
            memcpy (&current_vertex->normal, &obj.ns[(uniquevertex).in], sizeof (vector_t)); \
1206
         if ((uniquevertex).itc > -1) \
1207
            memcpy (&current_vertex->texcoord, &obj.tcs[(uniquevertex).itc], sizeof (texcoord_t)); \
1208
         hash = &hashtable[*((unsigned long *) &current_vertex->normal.x) & 0xFF]; \
1209
         hash->indices = (long *) SAFE_realloc (hash->indices, hash->count, hash->count + 1, sizeof (long), false); \
1210
         hash->indices[hash->count] = vertex_index; \
1211
         hash->count++; \
1212
         mesh->vertice_count++; \
1213
      } \
1214
      else \
1215
         vertex_index = hash->indices[vertex_index]; \
1216
   }
1217
 
1218
   typedef struct obj_uniquevertex_s { long iv, in, itc; } obj_uniquevertex_t;
1219
   typedef struct obj_face_s { obj_uniquevertex_t v1, v2, v3; } obj_face_t;
1220
   typedef struct obj_hashbucket_s { int count; long *indices; /* mallocated */ } obj_hashbucket_t;
1221
   typedef struct objfile_s
1222
   {
1223
      vector_t *vs; long v_count; long v_maxcount; // array mallocated to v_maxcount
1224
      vector_t *ns; long n_count; long n_maxcount; // array mallocated to n_maxcount
1225
      texcoord_t *tcs; long tc_count; long tc_maxcount; // array mallocated to tc_maxcount
1226
      obj_face_t *fs; long f_count; long f_maxcount; // array mallocated to f_maxcount
1227
   } objfile_t;
1228
 
1229
   static obj_hashbucket_t hashtable[256];
1230
   objfile_t obj;
1231
   obj_hashbucket_t *hash;
1232
   obj_face_t *f;
1233
   vertex_t *vertices; // mallocated
1234
   unsigned long *indices; // mallocated
1235
   vertex_t *current_vertex;
81 pmbaty 1236
   unsigned long file_size;
1 pmbaty 1237
   char *filedata; // mallocated
1238
   char *fileptr;
1239
   int vertex_index;
1240
   int array_index;
1241
   void *ptr_to;
1242
   FILE *fp;
1243
 
1244
   // open the mesh file and read it as a whole
1245
   _wfopen_s (&fp, objfile_pathname, L"rb");
1246
   if (fp == NULL)
1247
      return (false); // bomb out on error
81 pmbaty 1248
   fseek (fp, 0, SEEK_END); // seek at end of file...
1249
   file_size = ftell (fp); // ...read file length...
1250
   fseek (fp, 0, SEEK_SET); // and rewind
1251
   filedata = (char *) SAFE_malloc (file_size, sizeof (char), false); // mallocate space for data
1252
   fread (filedata, file_size, 1, fp); // read file as a whole
1 pmbaty 1253
   fclose (fp); // file is read, close it
1254
 
1255
   // allocate space for an arbitrary amount of vertices, texture coordinates, normals and faces
1256
   memset (&obj, 0, sizeof (obj));
1257
   obj.v_maxcount = 10000; obj.vs = (vector_t *) SAFE_malloc (obj.v_maxcount, sizeof (vector_t), false);
1258
   obj.n_maxcount = 10000; obj.ns = (vector_t *) SAFE_malloc (obj.n_maxcount, sizeof (vector_t), false);
1259
   obj.tc_maxcount = 10000; obj.tcs = (texcoord_t *) SAFE_malloc (obj.tc_maxcount, sizeof (texcoord_t), false);
1260
   obj.f_maxcount = 5000; obj.fs = (obj_face_t *) SAFE_malloc (obj.f_maxcount, sizeof (obj_face_t), true); // zero out the faces array (IMPORTANT !)
1261
 
1262
   // read file line per line...
1263
   fileptr = filedata - 1; // start parsing line after line
1264
   while (fileptr != NULL)
1265
   {
1266
      fileptr++; // skip the line feed (or reach the first character, if it's the first pass)
1267
 
1268
      // is it a vertex-related line ?
1269
      if (fileptr[0] == L'v')
1270
      {
1271
         // is it a vertex, a normal or a texture coordinate ?
1272
         if ((fileptr[1] == L' ') && (sscanf_s (&fileptr[2], "%f %f %f", &obj.vs[obj.v_count].x, &obj.vs[obj.v_count].y, &obj.vs[obj.v_count].z) == 3))
1273
            OBJ_INCREASE_OR_RESIZE (obj.v_count, obj.v_maxcount, 10000, obj.vs, vector_t, false) // one vertex more has been read
1274
         else if ((fileptr[1] == L'n') && (sscanf_s (&fileptr[3], "%f %f %f", &obj.ns[obj.n_count].x, &obj.ns[obj.n_count].y, &obj.ns[obj.n_count].z) == 3))
1275
            OBJ_INCREASE_OR_RESIZE (obj.n_count, obj.n_maxcount, 10000, obj.ns, vector_t, false) // one normal more has been read
1276
         else if ((fileptr[1] == L't') && (sscanf_s (&fileptr[3], "%f %f", &obj.tcs[obj.tc_count].u, &obj.tcs[obj.tc_count].v) == 2))
1277
            OBJ_INCREASE_OR_RESIZE (obj.tc_count, obj.tc_maxcount, 10000, obj.tcs, texcoord_t, false) // one texture coordinate more has been read
1278
      }
1279
 
1280
      // else is it a face-related line ?
1281
      else if (fileptr[0] == L'f')
1282
      {
1283
         // get a quick pointer to current face (note: it's been already blanked out by malloc())
1284
         f = &obj.fs[obj.f_count];
1285
 
1286
         // is it a face with normals, a face without normals or a face without normals and texture coordinates ?
1287
         if ((sscanf_s (&fileptr[2], "%d/%d/%d %d/%d/%d %d/%d/%d", &f->v1.iv, &f->v1.itc, &f->v1.in, &f->v2.iv, &f->v2.itc, &f->v2.in, &f->v3.iv, &f->v3.itc, &f->v3.in) == 9)
1288
             || (sscanf_s (&fileptr[2], "%d/%d %d/%d %d/%d", &f->v3.iv, &f->v3.itc, &f->v2.iv, &f->v2.itc, &f->v3.iv, &f->v3.itc) == 6)
1289
             || (sscanf_s (&fileptr[2], "%d %d %d", &f->v3.iv, &f->v2.iv, &f->v3.iv) == 6))
1290
         {
1291
            OBJ_CONVERT_INDEX (f->v1.iv, obj.v_count);
1292
            OBJ_CONVERT_INDEX (f->v1.in, obj.n_count); // if no normal could be read, its index will be converted from 0 to -1
1293
            OBJ_CONVERT_INDEX (f->v1.itc, obj.tc_count); // if no texcoord could be read, its index will be converted from 0 to -1
1294
            OBJ_CONVERT_INDEX (f->v2.iv, obj.v_count);
1295
            OBJ_CONVERT_INDEX (f->v2.in, obj.n_count); // if no normal could be read, its index will be converted from 0 to -1
1296
            OBJ_CONVERT_INDEX (f->v2.itc, obj.tc_count); // if no texcoord could be read, its index will be converted from 0 to -1
1297
            OBJ_CONVERT_INDEX (f->v3.iv, obj.v_count);
1298
            OBJ_CONVERT_INDEX (f->v3.in, obj.n_count); // if no normal could be read, its index will be converted from 0 to -1
1299
            OBJ_CONVERT_INDEX (f->v3.itc, obj.tc_count); // if no texcoord could be read, its index will be converted from 0 to -1
1300
            OBJ_INCREASE_OR_RESIZE (obj.f_count, obj.f_maxcount, 5000, obj.fs, obj_face_t, true) // one face more has been read
1301
         }
1302
      }
1303
 
1304
      fileptr = strchr (fileptr, '\n'); // proceed to next line
1305
   }
1306
 
1307
   // now build our final vertex and index list
1308
   vertices = (vertex_t *) SAFE_malloc (3 * obj.f_count, sizeof (vertex_t), false); // mallocate for the max number of vertices we can have
1309
   indices = (unsigned long *) SAFE_malloc (3 * obj.f_count, sizeof (unsigned long), false); // mallocate for the right amount of indices
1310
 
1311
   // t3h mighty l00p ^^ (builds vertex and index buffers)
1312
   memset (hashtable, 0, sizeof (hashtable)); // wipe out the hashtable
1313
   mesh->vertice_count = 0; // start with an unoptimized list
1314
   for (array_index = 0; array_index < obj.f_count; array_index++)
1315
   {
1316
      f = &obj.fs[array_index]; // quick access to current face
1317
      OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX (f->v1);
1318
      indices[3 * array_index + 0] = vertex_index;
1319
      OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX (f->v2);
1320
      indices[3 * array_index + 1] = vertex_index;
1321
      OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX (f->v3);
1322
      indices[3 * array_index + 2] = vertex_index;
1323
   }
1324
 
1325
   // now create a correctly-sized DirectX vertex buffer and populate it
1326
   mesh->vertex_format = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
1327
   mesh->vertice_size = sizeof (vertex_t);
1328
   d3ddev->CreateVertexBuffer (mesh->vertice_count * mesh->vertice_size, // length
1329
                               D3DUSAGE_DYNAMIC, // usage
1330
                               mesh->vertex_format, // vertex format
1331
                               D3DPOOL_DEFAULT, // pool type
1332
                               &mesh->d3dvertices, // pointer to the vertex buffer pointer
1333
                               NULL); // shared handle
1334
   mesh->d3dvertices->Lock (0, mesh->vertice_count * mesh->vertice_size, &ptr_to, D3DLOCK_DISCARD);
1335
   memcpy (ptr_to, vertices, mesh->vertice_count * mesh->vertice_size);
1336
   mesh->d3dvertices->Unlock ();
1337
 
1338
   // create a correctly-sized DirectX index buffer and populate it
1339
   mesh->is_indexed = true; // remember that we're building an index buffer
1340
   mesh->indice_count = obj.f_count * 3;
1341
   mesh->indice_size = (mesh->indice_count <= (int) USHRT_MAX ? 2 : 4);
1342
   d3ddev->CreateIndexBuffer (mesh->indice_count * mesh->indice_size, // length
1343
                              D3DUSAGE_DYNAMIC, // usage
1344
                              (mesh->indice_size == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32), // format (here, 16 or 32-bit)
1345
                              D3DPOOL_DEFAULT, // pool type
1346
                              &mesh->d3dindices, // pointer to the index buffer pointer
1347
                              NULL); // shared handle
1348
   mesh->d3dindices->Lock (0, mesh->indice_count * mesh->indice_size, &ptr_to, D3DLOCK_DISCARD);
1349
   if (mesh->indice_size == 2)
1350
      for (array_index = 0; array_index < mesh->indice_count; array_index++)
1351
         ((unsigned short *) ptr_to)[array_index] = (unsigned short) indices[array_index];
1352
   else
1353
      memcpy (ptr_to, indices, mesh->indice_count * mesh->indice_size);
1354
   mesh->d3dindices->Unlock ();
1355
 
1356
   // finished, free the temporary objects
1357
   for (array_index = 0; array_index < sizeof (hashtable) / sizeof (obj_hashbucket_t); array_index++)
1358
      SAFE_free ((void **) &hashtable[array_index].indices);
1359
   SAFE_free ((void **) &indices);
1360
   SAFE_free ((void **) &vertices);
1361
   SAFE_free ((void **) &obj.vs);
1362
   SAFE_free ((void **) &obj.ns);
1363
   SAFE_free ((void **) &obj.tcs);
1364
   SAFE_free ((void **) &obj.fs);
1365
   SAFE_free ((void **) &filedata);
1366
 
1367
   return (true); // Wavefront Object successfully loaded, return TRUE
1368
 
1369
   #undef OBJ_GET_EXISTING_INDEX_OR_APPEND_VERTEX
1370
   #undef OBJ_CONVERT_INDEX
1371
   #undef OBJ_INCREASE_OR_RESIZE
1372
}
1373
 
1374
 
1375
static void Render_DrawSceneObjectReflection (sceneobject_t *sceneobject)
1376
{
1377
   // fast helper to draw a mesh at a specified location with certain pitch and yaw angles
1378
 
1379
   D3DXMATRIX rotation_matrix;
1380
   D3DXMATRIX translation_matrix;
1381
   D3DXMATRIX reflect_matrix;
1382
   D3DXMATRIX scaling_matrix;
1383
   material_t *material;
1384
   D3DMATERIAL9 d3dmaterial;
1385
   D3DXPLANE plane;
1386
   mesh_t *mesh;
1387
   mesh_t *tile_mesh;
1388
   float alpha;
1389
 
1390
   // draw the reflection below this mesh
1391
 
1392
   // quick access to meshes
1393
   mesh = &meshes[sceneobject->mesh_index];
1394
   tile_mesh = &meshes[theme->tile_meshindex];
1395
 
1396
   // set the world transform at location
131 pmbaty 1397
   D3DXPlaneFromPointNormal (&plane, (D3DXVECTOR3 *) &scene_lookatpoint, (D3DXVECTOR3 *) &upwards_direction);
1 pmbaty 1398
   D3DXMatrixReflect (&reflect_matrix, &plane);
1399
   D3DXMatrixRotationYawPitchRoll (&rotation_matrix, -sceneobject->pitch * TO_RADIANS, 0.0f, -sceneobject->yaw * TO_RADIANS);
1400
   D3DXMatrixTranslation (&translation_matrix, sceneobject->x, sceneobject->y, -sceneobject->z);
1401
   D3DXMatrixScaling (&scaling_matrix, sceneobject->scale, sceneobject->scale, 1.0f);
1402
 
1403
   // tell Direct3D about our matrix
1404
   d3ddev->SetTransform (D3DTS_WORLD, &(reflect_matrix * scaling_matrix * rotation_matrix * translation_matrix));
1405
 
1406
   d3ddev->SetRenderState (D3DRS_STENCILENABLE, true); // enable the stencil buffer
1407
   d3ddev->SetRenderState (D3DRS_STENCILFUNC, D3DCMP_LESS); // instruct how to fill the stencil buffer
1408
   d3ddev->SetRenderState (D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); // instruct how to fill the stencil buffer
1409
 
1410
   // set the texture for this mesh
1411
   if (sceneobject->texture_index != -1)
1412
      d3ddev->SetTexture (0, textures[sceneobject->texture_index].texture);
1413
   else
1414
      d3ddev->SetTexture (0, NULL);
1415
 
1416
   // adjust the light reflection properties by setting the material
1417
   if (sceneobject->material_index != -1)
1418
      material = &materials[sceneobject->material_index]; // use the specified scene object material
1419
   else
1420
      material = &materials[material_count - 1]; // scene object material unspecified, use default material
1421
   alpha = theme->reflection_alpha / 256.0f;
1422
   d3dmaterial.Ambient = D3DXCOLOR (material->ambient, material->ambient, material->ambient, material->transparency * alpha); // Alpha value not used according to SDK
1423
   d3dmaterial.Diffuse = D3DXCOLOR (material->diffuse, material->diffuse, material->diffuse, material->transparency * alpha);
1424
   d3dmaterial.Emissive = D3DXCOLOR (material->emissive, material->emissive, material->emissive, material->transparency * alpha); // Alpha value not used according to SDK
1425
   d3dmaterial.Specular = D3DXCOLOR (material->specular, material->specular, material->specular, material->transparency * alpha); // Alpha value not used according to SDK
1426
   d3dmaterial.Power = material->shininess;
1427
   d3ddev->SetMaterial (&d3dmaterial);
1428
 
1429
   // draw the mesh subset
1430
   d3ddev->SetStreamSource (0, mesh->d3dvertices, 0, sizeof (vertex_t));
1431
   d3ddev->SetFVF (mesh->vertex_format);
1432
   d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CW); // draw the faces backwards
1433
   if (mesh->is_indexed)
1434
   {
1435
      d3ddev->SetIndices (mesh->d3dindices);
1436
      d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, mesh->vertice_count, 0, mesh->indice_count / 3);
1437
   }
1438
   else
1439
      d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, mesh->vertice_count / 3);
1440
 
1441
   d3ddev->SetRenderState (D3DRS_STENCILENABLE, false); // and disable the stencil buffer
1442
 
1443
   // now draw the simple shadow below this mesh
1444
 
1445
   // grab the tools we need in hand
1446
   d3ddev->SetRenderState (D3DRS_ZENABLE, false); // disable the Z buffer
1447
   d3ddev->SetRenderState (D3DRS_AMBIENT, D3DCOLOR_XRGB (255, 255, 255)); // raise ambient light
1448
 
1449
   // position the simple shadow sprite
1450
   D3DXMatrixScaling (&scaling_matrix, max (sceneobject->simpleshadow_size, sceneobject->z / 5.0f), max (sceneobject->simpleshadow_size, sceneobject->z / 5.0f), 0.0f);
1451
   D3DXMatrixTranslation (&translation_matrix, sceneobject->x, sceneobject->y, 0.0f);
1452
   d3ddev->SetTransform (D3DTS_WORLD, &(scaling_matrix * translation_matrix));
1453
 
1454
   // adjust the light reflection properties by setting the material
1455
   material = &materials[material_count - 1]; // use the default material
1456
   d3dmaterial.Ambient = D3DXCOLOR (material->ambient, material->ambient, material->ambient, material->transparency);
1457
   d3dmaterial.Diffuse = D3DXCOLOR (material->diffuse, material->diffuse, material->diffuse, material->transparency);
1458
   d3dmaterial.Emissive = D3DXCOLOR (material->emissive, material->emissive, material->emissive, material->transparency);
1459
   d3dmaterial.Specular = D3DXCOLOR (material->specular, material->specular, material->specular, material->transparency);
1460
   d3dmaterial.Power = material->shininess;
1461
   d3ddev->SetMaterial (&d3dmaterial);
1462
 
1463
   d3ddev->SetTexture (0, textures[theme->shadow_textureindex].texture); // select the texture we want
1464
 
1465
   // and then draw it
1466
   d3ddev->SetStreamSource (0, tile_mesh->d3dvertices, 0, sizeof (vertex_t)); // set stream source
1467
   d3ddev->SetFVF (tile_mesh->vertex_format); // select which vertex format we are using
1468
   d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CW); // draw the faces backwards
1469
   if (tile_mesh->is_indexed)
1470
   {
1471
      d3ddev->SetIndices (tile_mesh->d3dindices);
1472
      d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, tile_mesh->vertice_count, 0, tile_mesh->indice_count / 3);
1473
   }
1474
   else
1475
      d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, tile_mesh->vertice_count / 3);
1476
 
1477
   // finished, reset ambient light to its previous value and enable the Z buffer back
1478
   d3ddev->SetRenderState (D3DRS_AMBIENT, ambient_light);
1479
   d3ddev->SetRenderState (D3DRS_ZENABLE, true);
1480
 
1481
   return; // finished
1482
}
1483
 
1484
 
1485
static void Render_DrawSceneObject (sceneobject_t *sceneobject)
1486
{
1487
   // fast helper to draw a mesh at a specified location with certain pitch and yaw angles
1488
 
1489
   D3DXMATRIX rotation_matrix;
1490
   D3DXMATRIX translation_matrix;
1491
   D3DXMATRIX scaling_matrix;
1492
   material_t *material;
1493
   D3DMATERIAL9 d3dmaterial;
1494
   mesh_t *mesh;
1495
 
1496
   // is this object a tile (i.e, it has no mesh) ?
1497
   if (sceneobject->mesh_index == -1)
1498
   {
1499
      Render_DrawSceneTile (sceneobject); // then draw it as a tile instead
1500
      return; // and return
1501
   }
1502
 
1503
   // quick access to mesh
1504
   mesh = &meshes[sceneobject->mesh_index];
1505
 
1506
   // set the world transform at location
1507
   D3DXMatrixRotationYawPitchRoll (&rotation_matrix, sceneobject->pitch * TO_RADIANS, 0.0f, sceneobject->yaw * TO_RADIANS);
1508
   D3DXMatrixTranslation (&translation_matrix, sceneobject->x, sceneobject->y, sceneobject->z);
1509
   D3DXMatrixScaling (&scaling_matrix, sceneobject->scale, sceneobject->scale, 1.0f);
1510
 
1511
   // tell Direct3D about our matrix
1512
   d3ddev->SetTransform (D3DTS_WORLD, &(scaling_matrix * rotation_matrix * translation_matrix));
1513
 
1514
   // set the texture for this mesh
1515
   if (sceneobject->texture_index != -1)
1516
      d3ddev->SetTexture (0, textures[sceneobject->texture_index].texture);
1517
   else
1518
      d3ddev->SetTexture (0, NULL);
1519
 
1520
   // adjust the light reflection properties by setting the material
1521
   if (sceneobject->material_index != -1)
1522
      material = &materials[sceneobject->material_index];
1523
   else
1524
      material = &materials[material_count - 1];
1525
   d3dmaterial.Ambient = D3DXCOLOR (material->ambient, material->ambient, material->ambient, material->transparency);
1526
   d3dmaterial.Diffuse = D3DXCOLOR (material->diffuse, material->diffuse, material->diffuse, material->transparency);
1527
   d3dmaterial.Emissive = D3DXCOLOR (material->emissive, material->emissive, material->emissive, material->transparency);
1528
   d3dmaterial.Specular = D3DXCOLOR (material->specular, material->specular, material->specular, material->transparency);
1529
   d3dmaterial.Power = material->shininess;
1530
   d3ddev->SetMaterial (&d3dmaterial);
1531
 
1532
   // draw the mesh subset
1533
   d3ddev->SetStreamSource (0, mesh->d3dvertices, 0, sizeof (vertex_t));
1534
   d3ddev->SetFVF (mesh->vertex_format);
1535
 
1536
   // is there transparency on this mesh ?
1537
   if (material->transparency < 1)
1538
   {
1539
      d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CW); // draw the back faces
1540
      if (mesh->is_indexed)
1541
      {
1542
         d3ddev->SetIndices (mesh->d3dindices);
1543
         d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, mesh->vertice_count, 0, mesh->indice_count / 3);
1544
      }
1545
      else
1546
         d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, mesh->vertice_count / 3);
1547
   }
1548
 
1549
   // now draw the front faces
1550
   d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CCW); // draw the front faces
1551
   if (mesh->is_indexed)
1552
   {
1553
      d3ddev->SetIndices (mesh->d3dindices);
1554
      d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, mesh->vertice_count, 0, mesh->indice_count / 3);
1555
   }
1556
   else
1557
      d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, mesh->vertice_count / 3);
1558
 
1559
   return; // finished
1560
}
1561
 
1562
 
1563
static void Render_DrawSceneTile (sceneobject_t *sceneobject)
1564
{
1565
   // fast helper to draw a tile (i.e, an object that doesn't have a mesh) at a specified location
1566
 
1567
   D3DXMATRIX rotation_matrix;
1568
   D3DXMATRIX translation_matrix;
1569
   D3DXMATRIX scaling_matrix;
1570
   material_t *material;
1571
   D3DMATERIAL9 d3dmaterial;
1572
   mesh_t *tile_mesh;
1573
 
1574
   tile_mesh = &meshes[theme->tile_meshindex]; // quick access to tile mesh
1575
 
1576
   // grab the tools we need in hand
1577
   d3ddev->SetRenderState (D3DRS_AMBIENT, D3DCOLOR_RGBA (0xFF, 0xFF, 0xFF, 0xFF)); // raise light
1578
 
1579
   // set the world transform at location
1580
   D3DXMatrixRotationYawPitchRoll (&rotation_matrix, sceneobject->pitch * TO_RADIANS, 0.0f, sceneobject->yaw * TO_RADIANS);
1581
   D3DXMatrixTranslation (&translation_matrix, sceneobject->x, sceneobject->y, sceneobject->z);
1582
   D3DXMatrixScaling (&scaling_matrix, sceneobject->scale, sceneobject->scale, 1.0f);
1583
 
1584
   // tell Direct3D about our matrix
1585
   d3ddev->SetTransform (D3DTS_WORLD, &(scaling_matrix * rotation_matrix * translation_matrix));
1586
 
1587
   // adjust the light reflection properties by setting the material
1588
   material = &materials[material_count - 1]; // use the default material for tiles
1589
   d3dmaterial.Ambient = D3DXCOLOR (material->ambient, material->ambient, material->ambient, material->ambient);
1590
   d3dmaterial.Diffuse = D3DXCOLOR (material->diffuse, material->diffuse, material->diffuse, material->diffuse);
1591
   d3dmaterial.Emissive = D3DXCOLOR (material->emissive, material->emissive, material->emissive, material->emissive);
1592
   d3dmaterial.Specular = D3DXCOLOR (material->specular, material->specular, material->specular, material->specular);
1593
   d3dmaterial.Power = material->shininess;
1594
   d3ddev->SetMaterial (&d3dmaterial);
1595
 
1596
   // select the texture we want
1597
   d3ddev->SetTexture (0, textures[sceneobject->texture_index].texture);
1598
 
1599
   // and then draw it
1600
   d3ddev->SetStreamSource (0, tile_mesh->d3dvertices, 0, sizeof (vertex_t)); // set stream source
1601
   d3ddev->SetFVF (tile_mesh->vertex_format); // select which vertex format we are using
1602
   d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_CW); // draw the back faces
1603
   if (tile_mesh->is_indexed)
1604
   {
1605
      d3ddev->SetIndices (tile_mesh->d3dindices);
1606
      d3ddev->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, 0, 0, tile_mesh->vertice_count, 0, tile_mesh->indice_count / 3);
1607
   }
1608
   else
1609
      d3ddev->DrawPrimitive (D3DPT_TRIANGLELIST, 0, tile_mesh->vertice_count / 3);
1610
 
1611
   // finished, reset ambient light to its previous value
1612
   d3ddev->SetRenderState (D3DRS_AMBIENT, ambient_light);
1613
 
1614
   return; // finished
1615
}
1616
 
1617
 
1618
static void Render_DrawSprite (sprite_t *sprite, float x_percent, float y_percent, float width_percent, float height_percent, int alpha)
1619
{
1620
   // fast helper to draw a sprite at a specified location with certain parameters
1621
 
1622
   D3DXMATRIX scaling_matrix;
1623
   texture_t *texture;
1624
   float scale_x;
1625
   float scale_y;
1626
 
1627
   texture = &textures[sprite->texture_index]; // quick access to sprite's texture
1628
 
1629
   scale_x = (width_percent * (float) initial_width) / (float) (100 * texture->width);
1630
   scale_y = (height_percent * (float) initial_height) / (float) (100 * texture->height);
1631
 
1632
   // start rendering the sprite (an optimized version would draw all sprites in a row...)
1633
   sprite->sprite->Begin (D3DXSPRITE_ALPHABLEND);
1634
 
1635
   // scale and position the sprite
1636
   D3DXMatrixTransformation2D (&scaling_matrix, // output matrix
1637
                               NULL, // scaling center
1638
                               0.0f, // scaling rotation
1639
                               &D3DXVECTOR2 (scale_x, scale_y), // scaling ratio
1640
                               &D3DXVECTOR2 (0, 0), // rotation center
1641
                               0.0f, // rotation
1642
                               &D3DXVECTOR2 (x_percent * (float) initial_width / 100.0f, y_percent * (float) initial_height / 100.0f)); // translation
1643
   sprite->sprite->SetTransform (&scaling_matrix); // tell the sprite about the scaling and position transform
1644
 
1645
   // now draw the sprite with the specified alpha and finish rendering
1646
   sprite->sprite->Draw (texture->texture, NULL, NULL, NULL, D3DCOLOR_ARGB (alpha, 255, 255, 255));
1647
   sprite->sprite->End ();
1648
 
1649
   return; // finished
1650
}
1651
 
1652
 
124 pmbaty 1653
static void Render_GetTextBoundaries (float maxwidth_percent, int font_id, wchar_t *text, RECT *rect)
1 pmbaty 1654
{
1655
   // this function computes and returns the size of the rectangle the specified text will fit into. Note that text may be modified
1656
   // to insert new lines if it doesn't fit in a single line.
1657
 
1658
   int char_index;
1659
   int length;
1660
   int optimal_length;
1661
   bool have_split;
124 pmbaty 1662
   int max_width;
1 pmbaty 1663
 
1664
   // blank out the output rectangle
1665
   memset (rect, 0, sizeof (RECT));
1666
 
1667
   // ask direct3D to compute the text size a first time
1668
   fonts[font_id].font->DrawText (NULL, text, -1, rect, DT_CALCRECT, D3DCOLOR (0));
1669
 
1670
   // if max width is not set, set it to viewport width
124 pmbaty 1671
   if (maxwidth_percent <= 0)
1 pmbaty 1672
      max_width = initial_width; // then use it to compute the real max width
124 pmbaty 1673
   else
1674
      max_width = (int) ((maxwidth_percent * (float) initial_width) / 100.0f); // else if specified, convert this percentage to an absolute pixel width
1 pmbaty 1675
 
1676
   // do we need more than one line ?
1677
   if (rect->right > max_width)
1678
   {
1679
      // see how many lines we need and compute the optimal length of one line
1680
      length = wcslen (text);
1681
      optimal_length = length / (1 + rect->right / (int) max_width);
1682
      have_split = false;
1683
      for (char_index = optimal_length; char_index < length; char_index++)
1684
         if (iswspace (text[char_index]))
1685
         {
1686
            text[char_index] = L'\n'; // interpolate linefeeds into string
1687
            have_split = true; // remember string has been split
1688
            char_index += optimal_length;
1689
         }
1690
 
1691
      // and ask direct3D to compute the text size again
1692
      fonts[font_id].font->DrawText (NULL, text, -1, rect, DT_CALCRECT, D3DCOLOR (0));
1693
   }
1694
 
1695
   return; // finished
1696
}
1697
 
1698
 
124 pmbaty 1699
static void Render_wprintf (float x_percent, float y_percent, float maxwidth_percent, int horiz_align, int vert_align, int text_align, int font_id, unsigned long color_rgba, RECT *out_rect, const wchar_t *fmt, ...)
1 pmbaty 1700
{
1701
   // this function displays text on the Direct3D interface according to the given parameters. X and Y are the base coordinates of
1702
   // the text's bounding rectangle. Max_width is the maximum allowed width of this rectangle before wrapping words on a new line.
1703
   // Horiz_align and vert_align are the alignment parameters of the RECTANGLE relatively to X and Y. Text_align is the alignment of
1704
   // the TEXT inside this rectangle (meaning, you can have right-aligned text in a rectangle that is centered on a point). Font_id
1705
   // and color.alphargb define the font and color of the text. Out_rect, if filled, will point to a RECT structure describing the text's
1706
   // bounding rectangle, after any word wrapping corrections have been made. Fmt is a format string containing the text itself,
1707
   // printf-style.
1708
 
1709
   va_list argptr;
1710
   RECT rect;
1711
   int left;
1712
   int top;
124 pmbaty 1713
   int x;
1714
   int y;
1 pmbaty 1715
 
1716
   // concatenate all the arguments in one string
1717
   va_start (argptr, fmt);
1718
   wvsprintf (printf_buffer, fmt, argptr);
1719
   va_end (argptr);
1720
 
124 pmbaty 1721
   // translate percent coordinates into absolute coordinates
1722
   x = (int) ((x_percent * (float) initial_width) / 100.0f);
1723
   y = (int) ((y_percent * (float) initial_height) / 100.0f);
1724
 
1 pmbaty 1725
   // get the text boundaries
124 pmbaty 1726
   Render_GetTextBoundaries (maxwidth_percent, font_id, printf_buffer, &rect);
1 pmbaty 1727
 
1728
   // horizontal alignment
1729
   if (horiz_align == ALIGN_LEFT)
1730
      left = x;
1731
   else if (horiz_align == ALIGN_RIGHT)
1732
      left = x - rect.right;
1733
   else
1734
      left = x - rect.right / 2;
1735
 
1736
   // vertical alignment
1737
   if (vert_align == ALIGN_TOP)
1738
      top = y;
1739
   else if (vert_align == ALIGN_BOTTOM)
1740
      top = y - rect.bottom;
1741
   else
1742
      top = y - rect.bottom / 2;
1743
 
1744
   // now reposition our rectangle correctly acording to alignment
1745
   OffsetRect (&rect, left, top);
1746
 
1747
   // and draw the text
1748
   if (text_align == ALIGN_LEFT)
1749
      fonts[font_id].font->DrawText (NULL, printf_buffer, -1, &rect, DT_LEFT, RGBACOLOR_TO_ARGBCOLOR (color_rgba));
1750
   else if (horiz_align == ALIGN_RIGHT)
1751
      fonts[font_id].font->DrawText (NULL, printf_buffer, -1, &rect, DT_RIGHT, RGBACOLOR_TO_ARGBCOLOR (color_rgba));
1752
   else
1753
      fonts[font_id].font->DrawText (NULL, printf_buffer, -1, &rect, DT_CENTER, RGBACOLOR_TO_ARGBCOLOR (color_rgba));
1754
 
1755
   // do we want the output rectangle ?
1756
   if (out_rect != NULL)
1757
      memcpy (out_rect, &rect, sizeof (rect)); // if so, copy it in the given variable
1758
 
1759
   return; // finished
1760
}
1761
 
1762
 
1763
static float DistanceToCamera (float x, float y, float z)
1764
{
1765
   // this function computes the distance of the point at coordinates x,y,z to the camera
1766
 
1767
   vector_t displacement;
1768
 
1769
   // compute displacement...
1770
   displacement.x = x - camera_position.x;
1771
   displacement.y = y - camera_position.y;
1772
   displacement.z = z - camera_position.z;
1773
 
1774
   // ...and then Pythagores in 3D
1775
   return (sqrtf (displacement.x * displacement.x + displacement.y * displacement.y + displacement.z * displacement.z));
1776
}
1777
 
1778
 
1779
static float FadeFloat (float from, float to, float start_time, float end_time)
1780
{
1781
   // helper function to return a progressive variation between from and to based on time
1782
 
1783
   if (end_time < current_time)
1784
      return (to);
1785
 
1786
   //      base + (variation) * (               fraction of completion               )
1787
   return (from + (to - from) * (current_time - start_time) / (end_time - start_time));
1788
}
1789
 
1790
 
1791
static unsigned long HashString (const wchar_t *string_buffer)
1792
{
1793
   // super fast string hash function, code courtesy of
1794
   // http://www.azillionmonkeys.com/qed/hash.html
1795
 
1796
   unsigned long length;
1797
   unsigned long hash;
1798
   unsigned long tmp;
1799
   int remaining;
1800
 
1801
   // first, get the string length and start with this as a hash value
1802
   length = wcslen (string_buffer) * sizeof (wchar_t);
1803
   hash = length;
1804
 
1805
   // figure out how many bytes there will remain after 32-bit processing
1806
   remaining = length & 3;
1807
   length >>= 2;
1808
 
1809
   // main loop, process 32-bit blocks
1810
   for ( ; length > 0; length--)
1811
   {
1812
      hash += *((const unsigned short *) string_buffer);
1813
      tmp = ((*((const unsigned short *) (string_buffer + 2))) << 11) ^ hash;
1814
      hash = (hash << 16) ^ tmp;
1815
      string_buffer += 2 * sizeof (unsigned short);
1816
      hash += hash >> 11;
1817
   }
1818
 
1819
   // handle the remaining bytes
1820
   if (remaining == 3)
1821
   {
1822
      hash += *((const unsigned short *) string_buffer);
1823
      hash ^= hash << 16;
1824
      hash ^= string_buffer[sizeof (unsigned short)] << 18;
1825
      hash += hash >> 11;
1826
   }
1827
   else if (remaining == 2)
1828
   {
1829
      hash += *((const unsigned short *) string_buffer);
1830
      hash ^= hash << 11;
1831
      hash += hash >> 17;
1832
   }
1833
   else if (remaining == 1)
1834
   {
1835
      hash += *string_buffer;
1836
      hash ^= hash << 10;
1837
      hash += hash >> 1;
1838
   }
1839
 
1840
   // force "avalanching" of final 127 bits
1841
   hash ^= hash << 3;
1842
   hash += hash >> 5;
1843
   hash ^= hash << 4;
1844
   hash += hash >> 17;
1845
   hash ^= hash << 25;
1846
   hash += hash >> 6;
1847
 
1848
   return (hash); // finished, return the hash value
1849
}
1850
 
1851
 
1852
static unsigned long HashFile (const wchar_t *file_pathname)
1853
{
1854
   // super fast file content pseudo-hash function
1855
 
1856
   unsigned short value;
81 pmbaty 1857
   unsigned long file_size;
1 pmbaty 1858
   FILE *fp;
1859
 
1860
   // open the file
1861
   _wfopen_s (&fp, file_pathname, L"rb");
1862
   if (fp == NULL)
1863
      return ((unsigned long) time (NULL)); // if file can't be open, return a random number
1864
 
81 pmbaty 1865
   // seek at end of file, read file size, and rewind
1866
   fseek (fp, 0, SEEK_END);
1867
   file_size = ftell (fp);
1868
   fseek (fp, 0, SEEK_SET);
1869
 
1 pmbaty 1870
   // seek at 2/3 of file size (if file is small enough, return only its content)
81 pmbaty 1871
   if (file_size >= 4)
1 pmbaty 1872
   {
81 pmbaty 1873
      fseek (fp, file_size * 2 / 3, SEEK_SET); // seek at 2/3 of file
1 pmbaty 1874
      fread (&value, 2, 1, fp); // and read a word here
1875
   }
81 pmbaty 1876
   else if (file_size >= 2)
1 pmbaty 1877
      fread (&value, 2, 1, fp);
81 pmbaty 1878
   else if (file_size == 1)
1 pmbaty 1879
      value = fgetc (fp);
1880
   else
1881
      value = 0;
1882
 
1883
   // finished, close the file
1884
   fclose (fp);
1885
 
1886
   // and return a hash composed of the 16 lower bits of the file size and the value we read
81 pmbaty 1887
   return ((unsigned long) (file_size << 16) | (unsigned long) value);
1 pmbaty 1888
}
1889
 
1890
 
1891
static void ResolveWildcard (wchar_t *file_pathname, wchar_t *extensions_separated_by_bars)
1892
{
1893
   // this function resolves a pathname ending with .* by testing with various possible
1894
   // file extensions until one of the files formed that way is found to exist.
1895
 
1896
   static wchar_t extension_list[256]; // needs to be modifiable for strtok()
1897
   wchar_t *current_extension;
1898
   wchar_t *wcstok_context;
1899
   int length;
1900
 
1901
   wcscpy_s (extension_list, WCHAR_SIZEOF (extension_list), extensions_separated_by_bars);
1902
   length = wcslen (file_pathname); // get pathname length
1903
 
1904
   // does the pathname we want NOT end with a wildcard ?
1905
   if ((length < 2) || (wcscmp (&file_pathname[length - 2], L".*") != 0))
1906
      return; // no need to resolve anything
1907
 
1908
   // test each extension and see if a corresponding file exists
1909
   current_extension = wcstok_s (extension_list, L"|", &wcstok_context);
1910
   while (current_extension != NULL)
1911
   {
1912
      if (*current_extension == L'.')
1913
         current_extension++; // if current extension starts with a dot, skip it
81 pmbaty 1914
 
1 pmbaty 1915
      wcscpy_s (&file_pathname[length - 1], wcslen (current_extension) + 1, current_extension);
81 pmbaty 1916
      if (_waccess (file_pathname, 0) == 0)
1 pmbaty 1917
         return; // found a file with this extension
1918
      current_extension = wcstok_s (NULL, L"|", &wcstok_context);
1919
   }
1920
 
1921
   wcscpy_s (&file_pathname[length - 1], 2, L"*");
1922
   return; // if none of these extensions match, put the wildcard back and return
1923
}
1924
 
1925
 
1926
static int SortReflectedObjects (const void *object1, const void *object2)
1927
{
1928
   // callback function used by qsort() when sorting the reflected objects according to their distance to the viewer
1929
 
1930
   return ((int) (1000.0f * (((reflectedobject_t *) object2)->distance - ((reflectedobject_t *) object1)->distance)));
1931
}