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 (¤t_vertex->position, &obj.vs[(uniquevertex).iv], sizeof (vector_t)); \ |
||
1248 | if ((uniquevertex).in > -1) \ |
||
1249 | memcpy (¤t_vertex->normal, &obj.ns[(uniquevertex).in], sizeof (vector_t)); \ |
||
1250 | if ((uniquevertex).itc > -1) \ |
||
1251 | memcpy (¤t_vertex->texcoord, &obj.tcs[(uniquevertex).itc], sizeof (texcoord_t)); \ |
||
1252 | hash = &hashtable[*((unsigned long *) ¤t_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 | } |