Subversion Repositories Games.Chess Giants

Rev

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