View difference between Paste ID: GpGHCiBY and VCEKXrWB
SHOW: | | - or go back to the newest paste.
1
//cl /EHsc /O2 DuneGroundEdit.cpp gdi32.lib user32.lib opengl32.lib comdlg32.lib
2
#include <windows.h>
3
#include <GL/gl.h>
4
#include <GL/glu.h>
5
#include <stdio.h>
6
#include <time.h>
7
#include "dunes.h"
8
#include "dunestructures.h"
9
#include <vector>
10
11
#define GET_X_LPARAM(a) ((short)LOWORD(a))
12
#define GET_Y_LPARAM(a) ((short)HIWORD(a))
13
14
unsigned short PlaneB[0x1000/2];
15-
bool showgray = false;
15+
16
POINT camera = {0,0};
17
POINT mouse;
18
double zoom = 1;
19
bool showgrey = false;
20
bool showunits = true;
21
int state = 0;
22
int drawtype = 0;
23
int drawsize = 1;
24
bool drawinverse = false;
25
26
struct Ground
27
{
28
	int width;
29
	int height;
30
	double *data;
31
	Ground(int _width, int _height)
32
	{
33
		width = _width;
34
		height = _height;
35
		data = (double *)malloc(width*height*sizeof(double));
36
		for (int x=0; x<width; ++x)
37
			for (int y=0; y<height; ++y)
38
				(*this)[x][y] = 0;
39
	}
40
	
41
	bool in(int x, int y)
42
	{
43
		if (x<0
44
		 || y<0
45
		 || x>=width
46
		 || y>=height)
47
			return false;
48
		return true;
49
	}
50
	
51
	double *operator [](int x)
52
	{
53
		return data+x*height;
54
	}
55
	
56
	~Ground()
57
	{
58
		if (data)
59
			free(data);
60
	}
61
};
62
63
struct DuneGround
64
{
65
	enum Types {Dust, Ground, SpiceLow, SpiceHigh, Dune};
66
	int width;
67
	int height;
68
	BYTE *data;
69
	BYTE *types;
70
	DuneGround(int _width, int _height)
71
	{
72
		width = _width;
73
		height = _height;
74
		data = (BYTE *)malloc(width*height*sizeof(BYTE));
75
		types = (BYTE *)malloc(twidth()*theight()*sizeof(BYTE));
76
		Clear();
77
	}
78
	
79
	~DuneGround()
80
	{
81
		if (data)
82-
		free(data);
82+
83
		if (types)
84
			free(types);
85
	}
86
	
87
	DuneGround(const DuneGround & g)
88
	{
89
		data = 0;
90
		types = 0;
91-
/*struct Point
91+
		width = 0;
92
		height = 0;
93-
	double x,y;
93+
		(*this) = g;
94-
}*/
94+
95
	
96
	const DuneGround & operator = (const DuneGround &g)
97
	{
98
		if (width != g.width
99
		 || height != g.height)
100
		{
101
			if (data)
102
				free(data);
103
			if (types)
104
				free(types);
105
			data = (BYTE *)malloc(g.width*g.height*sizeof(BYTE));
106
			types = (BYTE *)malloc(g.twidth()*g.theight()*sizeof(BYTE));
107
		}
108
		width = g.width;
109
		height = g.height;
110-
void LocalPick(int x, int y, int type);
110+
111
		memcpy(types,g.types,twidth()*theight()*sizeof(BYTE));
112
		return (*this);
113
	}
114
	
115
	void Clear()
116
	{
117
		for (int x=0; x<width; ++x)
118
			for (int y=0; y<height; ++y)
119
				(*this)[x][y] = 0xB0;
120
		for (int x=0; x<twidth(); ++x)
121
			for (int y=0; y<theight(); ++y)
122
				this->t(x,y) = Dust;
123
	}
124
	
125
	inline int twidth() const
126
	{
127
		return width*2+1;
128
	}
129
	
130-
  WNDCLASS wc;
130+
	inline int theight() const
131-
  HWND hWnd;
131+
132-
  HDC hDC;
132+
		return height*2+1;
133-
  HGLRC hRC;
133+
134-
  MSG msg;
134+
135-
  BOOL bQuit = FALSE;
135+
	inline bool tin(int x, int y) const
136
	{
137-
  // register window class
137+
		return (x>=0 && y>=0 && x<twidth() && y<theight());
138-
  wc.style = CS_OWNDC;
138+
139-
  wc.lpfnWndProc = WndProc;
139+
140-
  wc.cbClsExtra = 0;
140+
	inline bool in(int x, int y) const
141-
  wc.cbWndExtra = 0;
141+
142-
  wc.hInstance = hInstance;
142+
		return (x>=0 && y>=0 && x<width && y<height);
143-
  wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
143+
144-
  wc.hCursor = LoadCursor( NULL, IDC_ARROW );
144+
145-
  wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
145+
	void Draw(int x, int y, BYTE type)
146-
  wc.lpszMenuName = NULL;
146+
147-
  wc.lpszClassName = "GLSample";
147+
	    //   0   1   2
148-
  RegisterClass( &wc );
148+
	    // 0 1 2 3 4 5 6 
149
		this->t(x,y) = type;
150-
  // create main window
150+
		if (in(x/2, y/2))
151-
  hWnd = CreateWindow( 
151+
			Correct(x/2, y/2, type);
152-
    "GLSample", "OpenGL Texture Sample", 
152+
		if (in(x/2-1, y/2))
153-
    WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE | WS_MAXIMIZEBOX | WS_THICKFRAME,
153+
			Correct(x/2-1,y/2,type);
154-
    0, 0, 800, 600,
154+
		if (in(x/2, y/2-1))
155-
    NULL, NULL, hInstance, NULL );
155+
			Correct(x/2,y/2-1,type);
156
		if (in(x/2-1, y/2-1))
157-
  // enable OpenGL for the window
157+
			Correct(x/2-1-1,y/2-1,type);
158-
  EnableOpenGL( hWnd, &hDC, &hRC );
158+
159-
  UpdateViewport( hWnd);
159+
160
	
161-
  // load our texture
161+
	void Correct(int x, int y, BYTE type_draw)
162-
  GroundTiles = LoadTextureRAW( "tex1.bmp", TRUE );
162+
163-
  //LoadMap("map_18.bin");
163+
		if (type_draw == Ground)
164
		{
165-
  srand(time(0));
165+
166-
  GroundGrey = GenerateGround();
166+
167-
  //texture = LoadVRAM( "vram.bin", "pal.bin" );
167+
					if (t(i+x*2,j+y*2) != Ground
168
					 && t(i+x*2,j+y*2) != Dust)
169-
  int startTime = GetTickCount();
169+
						Draw(i+x*2,j+y*2,Dust);
170-
  int prevTime = startTime;
170+
171
		if (type_draw == SpiceLow)
172-
  // program main loop
172+
173-
  while ( !bQuit ) {
173+
174
				for (int j=0; j<3; ++j)
175-
    // check for messages
175+
					if (t(i+x*2,j+y*2) != SpiceLow
176-
    if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
176+
					 && t(i+x*2,j+y*2) != SpiceHigh
177
					 && t(i+x*2,j+y*2) != Dust)
178-
      // handle or dispatch messages
178+
						Draw(i+x*2,j+y*2,Dust);
179-
      if ( msg.message == WM_QUIT ) {
179+
180-
        bQuit = TRUE;
180+
		if (type_draw == SpiceHigh)
181-
      } else {
181+
182-
        TranslateMessage( &msg );
182+
183-
        DispatchMessage( &msg );
183+
184-
      }
184+
					if (t(i+x*2,j+y*2) != SpiceHigh
185
					 && t(i+x*2,j+y*2) != SpiceLow)
186-
    } else {
186+
						Draw(i+x*2,j+y*2,SpiceLow);
187-
		int n = GetTickCount();
187+
188-
		if (n - prevTime > 1000/40)
188+
		if (type_draw == SpiceHigh)
189
		{
190-
			Render(hWnd, hDC);
190+
191-
			prevTime = n;
191+
192
					if (t(i+x*2,j+y*2) != SpiceHigh
193
					 && t(i+x*2,j+y*2) != SpiceLow)
194-
			Sleep(1);
194+
						Draw(i+x*2,j+y*2,SpiceLow);
195-
    }
195+
196
		if (type_draw == Dune)
197-
  }
197+
198
			for (int i=0; i<3; ++i)
199-
  // free the texture
199+
200-
  FreeTexture( GroundTiles );
200+
					if (t(i+x*2,j+y*2) != Dune
201-
  FreeTexture( GroundGrey );
201+
					 && t(i+x*2,j+y*2) != Dust)
202
						Draw(i+x*2,j+y*2,Dust);
203-
  // shutdown OpenGL
203+
			/*int k = GetK(x,y,Dune);
204-
  DisableOpenGL( hWnd, hDC, hRC );
204+
			int mask = dunemask[k];
205
			for (int i=0; i<3; ++i)
206-
  // destroy the window explicitly
206+
207-
  DestroyWindow( hWnd );
207+
208
					if ((mask & (1<<(i+j*3)))
209-
  return msg.wParam;
209+
					 && t(i+x*2,j+y*2) != Dune)
210
						Draw(i+x*2,j+y*2,Dune);
211
					if (!(mask & (1<<(i+j*3)))
212
					 && t(i+x*2,j+y*2) == Dune)
213
						Draw(i+x*2,j+y*2,Dust);
214
				}*/
215
		}
216
		for (int i=-1; i<2; ++i)
217
			for (int j=-1; j<2; ++j)
218-
	double cx = int((camera.x+mouse.x-(rc.right/2))/32.0/zoom);
218+
				if (in(x+i,y+j))
219-
	double cy = int((camera.y+mouse.y-(rc.bottom/2))/32.0/zoom);
219+
					Update(x+i, y+j);
220-
	if (state == 1
220+
221-
	 && (int)(cx*2) <64*2+1 && (int)(cx*2)>=0
221+
222-
	 && (int)(cy*2) <64*2+1 && (int)(cy*2)>=0)
222+
	int GetK(int x, int y, BYTE type)
223-
		LocalPick(cx*2,cy*2,drawtype);//RangeGround(g[(int)(cx*2)][(int)(cy*2)]);*/
223+
224
		int mask = 0;
225
		int k = 0;
226
		for (int i=0; i<3; ++i)
227
			for (int j=0; j<3; ++j)
228
				if (t(i+x*2,j+y*2) == type)
229
					mask |= 1<<(i+j*3);	
230
		//1    2   4
231
		//8   16  32
232
		//64 128 256
233
		if ( type == Dune )
234
		{
235-
	// tiles
235+
			k = 0;
236-
	/*double tw = 1.0/64;
236+
			int min = 10;
237-
	for (int i=0; i<32; ++i)
237+
			for (int i=0; i<256; ++i)
238
				if (dunemask[i] != -1)
239-
		for (int j=0; j<64; ++j)
239+
240
					int d = DunemaskDist((dunemask[i] & DUNE_MASK), (mask & DUNE_MASK));
241-
			int id = PlaneB[i*64+j]&0x7FF;
241+
					if (((dunemask[i] & DUNE_MASK) & (mask & DUNE_MASK)) == (mask & DUNE_MASK)
242-
			int idx = id&63;
242+
					 && d < min)
243-
			int idy = id>>6;
243+
					{
244-
			glTexCoord2d(tw*(idx+0),tw*(idy+0)); glVertex2d(-1.0+tw*j,+1.0-tw*i);
244+
						k = i;
245-
			glTexCoord2d(tw*(idx+1),tw*(idy+0)); glVertex2d(-1.0+tw*(j+1),+1.0-tw*i);
245+
						min = d;
246-
			glTexCoord2d(tw*(idx+1),tw*(idy+1)); glVertex2d(-1.0+tw*(j+1),+1.0-tw*(i+1));
246+
					}
247-
			glTexCoord2d(tw*(idx+0),tw*(idy+1)); glVertex2d(-1.0+tw*j,+1.0-tw*(i+1));
247+
248
			for (int i=0; i<256; ++i)
249
				if (dunemask[i] != -1)
250-
	glTexCoord2d(0.0,0.0); glVertex2d(-8.0,+8.0);
250+
251-
	glTexCoord2d(1.0,0.0); glVertex2d(+8.0,+8.0);
251+
					if (((dunemask[k] & DUNE_MASK)|(mask&16)) == (dunemask[i] & DUNE_MASKMID))
252-
	glTexCoord2d(1.0,1.0); glVertex2d(+8.0,-8.0);
252+
						k = i;
253-
	glTexCoord2d(0.0,1.0); glVertex2d(-8.0,-8.0);*/
253+
254
			if (k == 0x9C && (mask & 2))
255
				k = 0x60;
256-
	for (int i=0; i<64; ++i)
256+
			if (dunemask[k] == 0)
257
				k = 0;
258-
		for (int j=0; j<64; ++j)
258+
259
		else
260-
			int id;
260+
261-
			if (state == 1)
261+
262-
				id = duneGroundNew[j][i];
262+
263
			if ( (mask&(4+32+256)) == (4+32+256))
264-
				id = duneGround[j][i];
264+
265
			if ( (mask&(64+128+256)) == (64+128+256))
266
				k |= 4;
267-
			glTexCoord2d(tw*(idx+0),1-tw*(idy+0)); glVertex2d(j,-i);
267+
268-
			glTexCoord2d(tw*(idx+1),1-tw*(idy+0)); glVertex2d(j+1,-i);
268+
269-
			glTexCoord2d(tw*(idx+1),1-tw*(idy+1)); glVertex2d(j+1,-(i+1));
269+
270-
			glTexCoord2d(tw*(idx+0),1-tw*(idy+1)); glVertex2d(j,-(i+1));
270+
			if ( type == Ground && k == 0 && (mask & 16)) // point
271
				k = 16;
272
			if ( k == 3 && !(mask & 16))
273
				k = 17;
274
			if ( k == 6 && !(mask & 16))
275
				k = 18;
276-
	if (showgray)
276+
277
				k = 20;
278-
	glBindTexture( GL_TEXTURE_2D, GroundGrey );
278+
279
				k = 19;
280-
		  glTexCoord2d(0,0); glVertex2d(0,-0);
280+
281-
		  glTexCoord2d(1,0); glVertex2d(64,-0);
281+
		return k;
282-
		  glTexCoord2d(1,1); glVertex2d(64,-64);
282+
283-
		  glTexCoord2d(0,1); glVertex2d(0,-64);
283+
	void Update(int x, int y)
284
	{
285
		int types_mask = 0;
286
		for (int type = 0; type < 5; ++type)
287-
	/*glBindTexture( GL_TEXTURE_2D, texture );
287+
288
			bool was = false;
289
			for (int i=0; i<3; ++i)
290-
		glTexCoord2d(tw*(3+0),1-tw*(0+0)); glVertex2d(cx,-cy);
290+
291-
		glTexCoord2d(tw*(3+1),1-tw*(0+0)); glVertex2d(cx+1,-cy);
291+
					if (t(i+x*2,j+y*2) == type)
292-
		glTexCoord2d(tw*(3+1),1-tw*(0+1)); glVertex2d(cx+1,-cy-1);
292+
						was = true;
293-
		glTexCoord2d(tw*(3+0),1-tw*(0+1)); glVertex2d(cx,-cy-1);
293+
		    if (was)
294-
	glEnd();*/
294+
				types_mask |= 1<<type;
295
		}
296
		
297
		int k = 0;
298
		int mask = 0;
299
		int id = 0xB0;
300
		if (types_mask & (1<<Ground))
301
		{
302
			k = GetK(x,y,Ground);
303-
// load a 256x256 RGB .RAW file as a texture
303+
			id = 0x80+k;
304
			if (k == 0)
305
				id = 0xB0;
306-
  GLuint texture;
306+
			if ( k == 16) // point
307-
  int width, height;
307+
308-
  BYTE * data;
308+
			if ( k == 17)
309-
  FILE * file;
309+
310-
  FILE *f;
310+
			if ( k == 18)
311-
  BYTE tmp;
311+
312-
  int i;
312+
			if ( k == 20)
313
				id = 0x3F;
314-
  // open texture data
314+
			if ( k == 19)
315-
  file = fopen( filename, "rb" );
315+
316-
  if ( file == NULL ) return 0;
316+
317
		
318-
  // allocate buffer
318+
		if (types_mask & (1<<SpiceLow))
319-
  width = 512;
319+
320-
  height = 512;
320+
			k = GetK(x,y,SpiceLow);
321-
  data = (BYTE*)malloc( width * height * 3 );
321+
			id = 0xB0+k;
322
			if ( k == 17)
323-
  // read texture data
323+
				id = 0x40;
324
			if ( k == 18)
325-
  fseek( file, 0x36, SEEK_SET);
325+
				id = 0x41;
326-
  fread( data, width * height * 3, 1, file );
326+
			if ( k == 20)
327-
  fclose( file );
327+
				id = 0x43;
328
			if ( k == 19)
329-
  for (i=0; i<width*height; ++i)
329+
				id = 0x42;
330-
  {
330+
331
		
332
		if (types_mask & (1<<SpiceHigh))
333
		{
334-
  }
334+
			k = GetK(x,y,SpiceHigh);
335
			id = 0xC0+k;
336-
  // allocate a texture name
336+
			if ( k == 17 )
337-
  glGenTextures( 1, &texture );
337+
				id = 0x44;
338
			if ( k == 18 )
339-
  // select our current texture
339+
				id = 0x45;
340-
  glBindTexture( GL_TEXTURE_2D, texture );
340+
			if ( k == 20 )
341
				id = 0x47;
342-
  // select modulate to mix texture with color for shading
342+
			if ( k == 19 )
343-
  glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
343+
				id = 0x46;
344
		}
345-
  // when texture area is small, bilinear filter the closest MIP map
345+
		if (types_mask & (1<<Dune))
346-
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
346+
347-
 
347+
			k = GetK(x,y,Dune);
348-
  // when texture area is large, bilinear filter the first MIP map
348+
			if (k)
349-
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
349+
				id = k;
350
			//id = 0x9F;
351-
  // if wrap is true, the texture wraps over at the edges (repeat)
351+
352-
  //       ... false, the texture ends at the edges (clamp)
352+
		(*this)[x][y] = id;
353-
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
353+
354-
                   wrap ? GL_REPEAT : GL_CLAMP );
354+
355-
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
355+
	void SetTileMask(int x, int y)
356-
                   wrap ? GL_REPEAT : GL_CLAMP );
356+
357
		int id = (*this)[x][y];
358-
  // build our texture MIP maps
358+
		int type = Dust;
359-
  //gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width,
359+
		int mask = 0;
360-
  //  height, GL_RGB, GL_UNSIGNED_BYTE, data );
360+
		int k = 0;
361-
  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width,
361+
		if (id > 0x80 && id <= 0x8F)
362-
    height, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
362+
363
			type = Ground; k = id-0x80;
364-
  // free buffer
364+
365-
  free( data );
365+
		if (id == 0x80)
366
		{
367-
  return texture;
367+
			type = Ground; k = 16;
368
		}
369
		if (id == 0x3C)
370
		{
371
			type = Ground; k = 17;
372
		}
373
		if (id == 0x3D)
374
		{
375
			type = Ground; k = 18;
376
		}
377
		if (id == 0x3F)
378
		{
379
			type = Ground; k = 20;
380
		}
381
		if (id == 0x3E)
382
		{
383
			type = Ground; k = 19;
384
		}
385
		
386
		if (id == 0x80)
387
		{
388
			type = Ground; k = 16;
389
		}
390
		
391
		if (id > 0xB0 && id <= 0xBF)
392
		{
393
			type = SpiceLow; k = id-0xB0;
394
		}
395
		
396
		if (id == 0x40)
397
		{
398
			type = SpiceLow; k = 17;
399
		}
400
		if (id == 0x41)
401
		{
402
			type = SpiceLow; k = 18;
403
		}
404-
void LocalPick(int x, int y, int type)
404+
		if (id == 0x43)
405
		{
406-
	static bool was[2*64+1][2*64+1];
406+
			type = SpiceLow; k = 20;
407
		}
408-
	for (int i=0; i<2*64+1; ++i)
408+
		if (id == 0x42)
409-
		for (int j=0; j<2*64+1; ++j)
409+
410-
			was[i][j] = false;
410+
			type = SpiceLow; k = 19;
411
		}
412
		
413
		if (id > 0xC0 && id <= 0xCF)
414-
	double z = g[x][y];
414+
415
			type = SpiceHigh; k = id-0xC0;
416
		}
417
		
418
		if (id == 0x44)
419
		{
420
			type = SpiceHigh; k = 17;
421
		}
422
		if (id == 0x45)
423
		{
424-
				if (X[s]+i>=0 && X[s]+i<2*64+1
424+
			type = SpiceHigh; k = 18;
425-
				 &&	Y[s]+j>=0 && Y[s]+j<2*64+1
425+
426
		if (id == 0x47)
427-
				 && g[X[s]+i][Y[s]+j]>=z)
427+
428
			type = SpiceHigh; k = 20;
429
		}
430
		if (id == 0x46)
431
		{
432
			type = SpiceHigh; k = 19;
433
		}
434
		
435
		if (type != Dust)
436
		{
437
			if (k<16)
438
			{
439
				mask = 0;
440
				if (k & 1)
441
					mask |= (1+2+4);
442
				if (k & 2)
443
					mask |= (4+32+256);
444-
					if (was[i+x*2][j+y*2])
444+
				if (k & 4)
445
					mask |= (64+128+256);
446
				if (k & 8)
447
					mask |= (1+8+64);
448
				if (k != 1
449
				 && k != 2
450
				 && k != 4
451
				 && k != 8)
452
					mask |= 16;
453
			}
454
			else
455
			{
456
				if (k == 16)
457
					mask = 16;
458
				if (k == 17)
459-
			int id = duneGround[x][y];
459+
					mask = make_dunemask(1,1,1,0,0,1,0,0,1);
460-
			if ( type == 0 )
460+
				if (k == 18)
461
					mask = make_dunemask(0,0,1,0,0,1,1,1,1);
462-
				id = 0x80+k;
462+
				if (k == 20)
463-
				if ( k == 0)
463+
					mask = make_dunemask(1,0,0,1,0,0,1,1,1);
464-
					id = duneGround[x][y];
464+
				if (k == 19)
465-
				if ( k == 0 && (mask & 16)) // point
465+
					mask = make_dunemask(1,1,1,1,0,0,1,0,0);
466-
					id = 0x80;
466+
467-
				if ( k == 3 && !(mask & 16))
467+
468-
					id = 0x3C;
468+
469-
				if ( k == 6 && !(mask & 16))
469+
		for (int i=0; i<256; ++i)
470-
					id = 0x3D;
470+
			if (dunemask[i] != -1 && i == id)
471-
				if ( k == 12 && !(mask & 16))
471+
472-
					id = 0x3F;
472+
				mask = dunemask[i];
473-
				if ( k == 9 && !(mask & 16))
473+
				type = Dune;
474-
					id = 0x3E;
474+
475
		int a = type;
476-
			if ( type == 1 )
476+
		int b = Dust;
477
		if (type == SpiceHigh)
478-
				id = 0xB0+k;
478+
			b = SpiceLow;
479-
				if ( k == 0)
479+
		for (int i=0; i<3; ++i)
480-
					id = duneGround[x][y];
480+
			for (int j=0; j<3; ++j)
481-
				if ( k == 3 && !(mask & 16))
481+
				if (mask & (1<<(i+j*3)))
482-
					id = 0x40;
482+
					t(i+x*2,j+y*2) = a;
483-
				if ( k == 6 && !(mask & 16))
483+
				else
484-
					id = 0x41;
484+
485-
				if ( k == 12 && !(mask & 16))
485+
					if (b == SpiceLow && t(i+x*2,j+y*2) != SpiceLow)
486-
					id = 0x43;
486+
						t(i+x*2,j+y*2) = b;
487-
				if ( k == 9 && !(mask & 16))
487+
488-
					id = 0x42;
488+
489
	
490-
			if ( type == 2 )
490+
491
	{
492-
				id = 0xC0+k;
492+
493-
				if ( k == 0)
493+
494-
					id = duneGround[x][y];
494+
495-
				if ( k == 3 && !(mask & 16))
495+
	BYTE & t(int x,int y)
496-
					id = 0x44;
496+
497-
				if ( k == 6 && !(mask & 16))
497+
		return types[y*twidth()+x];
498-
					id = 0x45;
498+
499-
				if ( k == 12 && !(mask & 16))
499+
500-
					id = 0x47;
500+
501-
				if ( k == 9 && !(mask & 16))
501+
struct DuneUnit
502-
					id = 0x46;
502+
503
	short house;
504-
			duneGroundNew[x][y] = id;
504+
	short id;
505
	short life;
506
	short pos;
507
	short angle;
508
	short ai;
509
};
510
511
struct DuneStructure
512
{
513
	short flag;
514
	short house;
515
	short id;
516
	short life;
517
	short pos;
518
};
519
520
DuneGround duneGround(64,64);
521
DuneGround duneGroundNew(64,64);
522
std::vector<DuneUnit> Units;
523
std::vector<DuneStructure> Structures;
524
525
Ground g(2*64+1,2*64+1);
526
GLuint GroundTiles;
527
GLuint GroundGrey;
528
GLuint StructuresTexture;
529
530
// Declarations //////////////////////////////////////////////////////
531
532
LPCSTR OpenFile(HWND hWnd, LPCSTR title);
533
LPCSTR SaveFile(HWND hWnd, LPCSTR title);
534
GLuint LoadTextureRAW( const char * filename, int wrap );
535
GLuint LoadGreyTexture( const char * filename);
536
GLuint LoadVRAM( const char * vram, const char * pal);
537
GLuint GenerateGround();
538
GLuint MakeGreyTexture();
539
void ChangeState(int _state);
540
void RangeGround(double z);
541
void LocalPick(int x, int y, int type, double z, bool inverse);
542
void LoadMap( const char * filename );
543
void LoadMission( const char * filename );
544
void SaveMap( const char * filename );
545
void FreeTexture( GLuint texture );
546
547
LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
548
                          WPARAM wParam, LPARAM lParam );
549
550
VOID EnableOpenGL( HWND hWnd, HDC * hDC, HGLRC * hRC );
551
VOID DisableOpenGL( HWND hWnd, HDC hDC, HGLRC hRC );
552
void UpdateViewport(HWND hWnd);
553
void Render(HWND hWnd, HDC hDC);
554
555
// WinMain ///////////////////////////////////////////////////////////
556
557
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
558-
	GenerateGroundRecursive(g, 0, 0, g.width-1, g.height-1);
558+
559
{
560
	WNDCLASS wc;
561
	HWND hWnd;
562
	HDC hDC;
563
	HGLRC hRC;
564
	MSG msg;
565
	BOOL bQuit = FALSE;
566
567
	// register window class
568
	wc.style = CS_OWNDC;
569
	wc.lpfnWndProc = WndProc;
570
	wc.cbClsExtra = 0;
571
	wc.cbWndExtra = 0;
572
	wc.hInstance = hInstance;
573
	wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
574
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
575
	wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
576
	wc.lpszMenuName = NULL;
577
	wc.lpszClassName = "DuneGroundEditor";
578
	RegisterClass( &wc );
579
  
580
	DunemaskInit();
581
582
	// create main window
583
	hWnd = CreateWindow( 
584
		"DuneGroundEditor", "DuneGroundEditor", 
585
		WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME,
586
		0, 0, 800, 600,
587
		NULL, NULL, hInstance, NULL );
588
589
	// enable OpenGL for the window
590
	EnableOpenGL( hWnd, &hDC, &hRC );
591
	UpdateViewport( hWnd);
592
593
	// load our texture
594
	GroundTiles = LoadTextureRAW( "tex1.bmp", TRUE );
595
	StructuresTexture = LoadTextureRAW( "structures.bmp", TRUE);
596
	srand(time(0));
597
	GroundGrey = GenerateGround();
598
599
	int startTime = GetTickCount();
600
	int prevTime = startTime;
601
602-
	for (int y=0; y<64; ++y)
602+
	// program main loop
603-
		for (int x=0; x<64; ++x)
603+
	while ( !bQuit )
604
	{
605
		// check for messages
606
		if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
607
		{
608
			// handle or dispatch messages
609
			if ( msg.message == WM_QUIT )
610
			{
611
				bQuit = TRUE;
612
			}
613
			else
614
			{
615
				TranslateMessage( &msg );
616-
	for (int y=0; y<64; ++y)
616+
				DispatchMessage( &msg );
617-
		for (int x=0; x<64; ++x)
617+
618
		}
619
		else
620
		{
621
			int n = GetTickCount();
622
			if (n - prevTime > 1000/40)
623
			{
624
				Render(hWnd, hDC);
625
				prevTime = n;
626
			}
627
			else
628
				Sleep(1);
629
		}
630
	}
631
632
	// free the texture
633
	FreeTexture( GroundTiles );
634
	FreeTexture( GroundGrey );
635
636
	// shutdown OpenGL
637
	DisableOpenGL( hWnd, hDC, hRC );
638
639
	// destroy the window explicitly
640
	DestroyWindow( hWnd );
641
642
	return msg.wParam;
643
644
}
645
646
void Render(HWND hWnd, HDC hDC)
647-
		duneGroundNew = duneGround;
647+
648
	// OpenGL animation code goes here
649
	RECT rc;
650
	GetClientRect(hWnd,&rc);
651
	double cx = (camera.x+mouse.x-(rc.right/2))/32.0/zoom*2+0.5;
652
	double cy = (camera.y+mouse.y-(rc.bottom/2))/32.0/zoom*2+0.5;
653
	if (state == 2 && duneGround.tin(cx,cy))
654
	{
655
		int x = cx; 
656
		int y = cy; 
657
		double n = 0;
658
		double z = 0;
659
		for (int i=0; i<2; ++i)
660
			for (int j=0; j<2; ++j)
661
				if ( duneGround.tin(x+i,y+j) )
662
				{
663
					double w = (1-(cx-x-i))*(1-(cy-y-j));
664
					n += w;
665
					z += w*g[x+i][y+j];
666
				}
667
		z /= n;
668
		LocalPick(cx,cy,drawtype,z,drawinverse);//RangeGround(g[(int)(cx*2)][(int)(cy*2)]);*/
669
	}
670
671
	glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
672
	glClear( GL_COLOR_BUFFER_BIT );
673
674
	// setup texture mapping
675
	glEnable( GL_TEXTURE_2D );
676
	glBindTexture( GL_TEXTURE_2D, GroundTiles );
677
678
	glPushMatrix();
679-
			SaveMap("map.bin");
679+
680
681
	GetClientRect(hWnd, &rc);
682
	double tw = 1.0/16;
683
	//else
684
	{
685
		for (int i=0; i<duneGround.width; ++i)
686
		{
687-
			ChangeState(state^1);
687+
			for (int j=0; j<duneGround.height; ++j)
688
			{
689
				int id;
690
				if (state == 2)
691
					id = duneGroundNew[j][i];
692
				else
693
					id = duneGround[j][i];
694
				int idx = id&15;
695
				int idy = (id>>4);
696
				glTexCoord2d(tw*(idx+0),1-tw*(idy+0)); glVertex2d(j,-i);
697
				glTexCoord2d(tw*(idx+1),1-tw*(idy+0)); glVertex2d(j+1,-i);
698
				glTexCoord2d(tw*(idx+1),1-tw*(idy+1)); glVertex2d(j+1,-(i+1));
699
				glTexCoord2d(tw*(idx+0),1-tw*(idy+1)); glVertex2d(j,-(i+1));
700
			}
701
		}
702-
			for (int x=0; x<duneGround.width; ++x)
702+
703-
				for (int y=0; y<duneGround.height; ++y)
703+
704-
					duneGround[x][y] = 0xB0;
704+
705
	if (state == 1)
706
	{
707
		glEnable( GL_BLEND );
708-
			showgray = !showgray;
708+
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
709
		glColor4f(1.f,1.f,1.f,0.5f);
710
		glBegin( GL_QUADS );
711
		for (int y=0; y<duneGround.theight(); ++y)
712
		{
713
			for (int x=0; x<duneGround.twidth(); ++x)
714
			{
715
				static int tid[]={0xB0,0x8F,0xC0,0xCF,0x9F};
716
				int id = duneGround.t(x,y);
717
				id = tid[id];
718
				int idx = id&15;
719
				int idy = (id>>4);
720
				glTexCoord2d(tw*(idx+0),1-tw*(idy+0)); glVertex2d(x*0.5-0.25,-(y*0.5-0.25));
721
				glTexCoord2d(tw*(idx+1),1-tw*(idy+0)); glVertex2d(x*0.5+0.5-0.25,-(y*0.5-0.25));
722
				glTexCoord2d(tw*(idx+1),1-tw*(idy+1)); glVertex2d(x*0.5+0.5-0.25,-(y*0.5+0.5-0.25));
723
				glTexCoord2d(tw*(idx+0),1-tw*(idy+1)); glVertex2d(x*0.5-0.25,-(y*0.5+0.5-0.25));
724
			}
725
		}
726
		glEnd();
727
		glDisable( GL_BLEND );
728
	}
729
730
	if (showunits)
731
	{
732
		glBindTexture( GL_TEXTURE_2D, StructuresTexture );
733
		glBegin( GL_QUADS );
734
		for (int i = 0; i < Structures.size(); ++i)
735
		{
736
			int x = (Structures[i].pos&0x3F);
737
			int y = (Structures[i].pos/0x40);
738
			int id = Structures[i].id;
739
			auto si = StructureDrawInfos[id];
740
			glTexCoord2d((si.x+       0)/512.0,1-(si.y+        0)/512.0); glVertex2d(x,            -y);
741
			glTexCoord2d((si.x+si.width)/512.0,1-(si.y+        0)/512.0); glVertex2d(x+si.width/32,-y);
742
			glTexCoord2d((si.x+si.width)/512.0,1-(si.y+si.height)/512.0); glVertex2d(x+si.width/32,-(y+si.height/32));
743-
		int cx = int((camera.x+mouse.x-(rc.right/2))/32.0/zoom);
743+
			glTexCoord2d((si.x+       0)/512.0,1-(si.y+si.height)/512.0); glVertex2d(x,            -(y+si.height/32));
744-
		int cy = int((camera.y+mouse.y-(rc.bottom/2))/32.0/zoom);
744+
745-
		if (state == 1)
745+
		glEnd();
746
	
747
	
748
		glBindTexture( GL_TEXTURE_2D, GroundGrey );
749
		glBegin( GL_QUADS );
750
		for (int i = 0; i < Units.size(); ++i)
751
		{
752
			int x = (Units[i].pos&0x3F);
753-
			int xPos = mouse.x; mouse.x = GET_X_LPARAM(lParam);
753+
			int y = (Units[i].pos/0x40);
754-
			int yPos = mouse.y; mouse.y = GET_Y_LPARAM(lParam);
754+
			int id = Units[i].id;
755-
			camera.x -= mouse.x-xPos;
755+
756-
			camera.y -= mouse.y-yPos;
756+
757
			glTexCoord2d(tw*(idx+0),1-tw*(idy+0)); glVertex2d(x,-y);
758
			glTexCoord2d(tw*(idx+1),1-tw*(idy+0)); glVertex2d(x+1,-y);
759
			glTexCoord2d(tw*(idx+1),1-tw*(idy+1)); glVertex2d(x+1,-(y+1));
760
			glTexCoord2d(tw*(idx+0),1-tw*(idy+1)); glVertex2d(x,-(y+1));
761
		}
762
		glEnd();
763
	}
764
765
	if (showgrey)
766
	{
767
		glBindTexture( GL_TEXTURE_2D, GroundGrey );
768
		glBegin( GL_QUADS );
769
			  glTexCoord2d(0,0); glVertex2d(0,-0);
770
			  glTexCoord2d(1,0); glVertex2d(64,-0);
771-
// OpenGL ////////////////////////////////////////////////////////////
771+
			  glTexCoord2d(1,1); glVertex2d(64,-64);
772
			  glTexCoord2d(0,1); glVertex2d(0,-64);
773
		glEnd();
774
	}
775
776
	glPopMatrix();
777
778
	SwapBuffers( hDC );
779
}
780
781
782
// Texture ///////////////////////////////////////////////////////////
783
784
// load a 512x512 24 bit RGB .BMP file as a texture
785
GLuint LoadTextureRAW( const char * filename, int wrap )
786
{
787
	GLuint texture;
788
	int width, height;
789
	BYTE * data;
790
	FILE * file;
791
	FILE *f;
792
	BYTE tmp;
793
	int i;
794
795
	// open texture data
796
	file = fopen( filename, "rb" );
797
	if ( file == NULL ) return 0;
798
799
	// allocate buffer
800
	width = 512;
801
	height = 512;
802
	data = (BYTE*)malloc( width * height * 3 );
803
804
	// read texture data
805
806
	fseek( file, 0x36, SEEK_SET);
807
	fread( data, width * height * 3, 1, file );
808
	fclose( file );
809
810
	for (i=0; i<width*height; ++i)
811
	{
812
		tmp = data[i*3];
813
		data[i*3] = data[i*3+2];
814
		data[i*3+2] = tmp;
815
	}
816
817
	// allocate a texture name
818
	glGenTextures( 1, &texture );
819
820
	// select our current texture
821
	glBindTexture( GL_TEXTURE_2D, texture );
822
823
	// select modulate to mix texture with color for shading
824
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
825
826
	// when texture area is small, bilinear filter the closest MIP map
827
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
828
829
	// when texture area is large, bilinear filter the first MIP map
830
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
831
832
	// if wrap is true, the texture wraps over at the edges (repeat)
833
	//       ... false, the texture ends at the edges (clamp)
834
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
835
				   wrap ? GL_REPEAT : GL_CLAMP );
836
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
837
				   wrap ? GL_REPEAT : GL_CLAMP );
838
839
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width,
840
	height, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
841
842
	// free buffer
843
	free( data );
844
845
	return texture;
846
847
}
848
849
GLuint LoadGreyTexture( const char * filename )
850
{
851
	GLuint texture;
852
	int width, height;
853
	BYTE * data;
854
	FILE * file;
855
	FILE *f;
856
	BYTE tmp;
857
	int i;
858
859
	// open texture data
860
	file = fopen( filename, "rb" );
861
	if ( file == NULL ) return 0;
862
863
	// allocate buffer
864
	width = 128;
865
	height = 128;
866
	data = (BYTE*)malloc( width * height * 4 );
867
868
	// read texture data
869
870
	fseek( file, 0x36, SEEK_SET);
871
	fread( data, width * height * 3, 1, file );
872
	fclose( file );
873
874
	for (i=0; i<width*height; ++i)
875
	{
876
		int all = 0;
877
		for (int j=0; j<3; ++j)
878
			all += data[i*3+j];
879
		all /= 3;
880
		g[i%width][width - 1 - i/width] = all/255.0;
881
	}
882
883
	free(data);
884
885
	return MakeGreyTexture();
886
}
887
888
double randf()
889
{
890
	return rand()/double(RAND_MAX);
891
}
892
893
// Midpoint displacement
894
void GenerateGroundRecursive(Ground &g, int x, int y, int width, int height)
895
{
896
	if (width <= 1 || height <= 1)
897
		return;
898
	double a,b,c,d;
899
	a = g[x      ][y      ];
900
	b = g[x+width][y      ];
901
	c = g[x      ][y+height];
902
	d = g[x+width][y+height];
903
904
	g[(x + (x + width))/2][ y                  ] = (a + b)/2;
905
	g[ x                 ][(y + (y + height))/2] = (a + c)/2;
906
	g[(x + (x + width))/2][ y + height         ] = (c + d)/2;
907
	g[ x + width         ][(y + (y + height))/2] = (b + d)/2;
908
	
909
	double z = (a+b+c+d)/4+((-1+randf()*2)*width/64/2);
910
	if (z > 1)
911
		z = 1;
912
	if (z < 0)
913
		z = 0;
914
	g[(x + (x + width))/2][(y + (y + height))/2] = z;
915
	
916
	GenerateGroundRecursive(g, x          , y           , width/2, height/2);
917
	GenerateGroundRecursive(g, x + width/2, y           , width/2, height/2);
918
	GenerateGroundRecursive(g, x          , y + height/2, width/2, height/2);
919
	GenerateGroundRecursive(g, x + width/2, y + height/2, width/2, height/2);
920
}
921
922
void LocalPick(int x, int y, int type, double z, bool inverse)
923
{
924
	/*static std::vector<bool> was(129*129);
925
	if (was.size() != duneGround.width * duneGround.height)
926
		was.resize(duneGround.width * duneGround.height);
927
	
928
	was.assign(was.size(), false);*/
929
	static bool was[129][129];
930
	memset(was,0,sizeof(was));
931
	
932
	duneGroundNew = duneGround;
933
934
	static int X[(2*64+1)*(2*64+1)];
935
	static int Y[(2*64+1)*(2*64+1)];
936
	int s = 0,e = 0;
937
	X[e] = x;
938
	Y[e] = y;
939
	was[x][y] = true;
940
	++e;
941
	while (s < e)
942
	{
943
		for (int i=-1; i<2; ++i)
944
			for (int j=-1; j<2; ++j)
945
				if (duneGround.tin(X[s]+i, Y[s]+j)
946
				 && !was[X[s]+i][Y[s]+j]
947
				 && ((!inverse && g[X[s]+i][Y[s]+j]>=z) || (inverse && g[X[s]+i][Y[s]+j]<=z) ))
948
				{
949
					X[e] = X[s]+i;
950
					Y[e] = Y[s]+j;
951
					was[X[e]][Y[e]] = true;
952
					duneGroundNew.Draw(X[e],Y[e],type);
953
					++e;
954
				}
955
		++s;
956
	}
957
	//char str[50];
958
	//sprintf(str,"%d %d < %d", s, e, (2*64+1)*(2*64+1));
959
	//MessageBox(NULL,"Oo",str,MB_OK);
960
}
961
962
void RangeGround(double z)
963
{
964
	for (int x=0; x<64; ++x)
965
	{
966
		for (int y=0; y<64; ++y)
967
		{
968
			int mask = 0;
969
			for (int i=0; i<3; ++i)
970
				for (int j=0; j<3; ++j)
971
					if (g[i+x*2][j+y*2]>z)
972
						mask |= 1<<(i+j*3);
973
			int k = 0;
974
			//1    2   4
975
			//8   16  32
976
			//64 128 256
977
			if ( (mask&(1+2+4)) == (1+2+4))
978
				k++;
979
			if ( (mask&(4+32+256)) == (4+32+256))
980
				k |= 2;
981
			if ( (mask&(64+128+256)) == (64+128+256))
982
				k |= 4;
983
			if ( (mask&(1+8+64)) == (1+8+64))
984
				k |= 8;
985
			int id = 0x80+k;
986
			if ( k == 0)
987
				id = 0xB0;
988
			if ( k == 0 && (mask & 16))
989
				id = 0x80;
990
			if ( k == 3 && !(mask & 16))
991
				id = 0x3C;
992
			if ( k == 6 && !(mask & 16))
993
				id = 0x3D;
994
			if ( k == 12 && !(mask & 16))
995
				id = 0x3F;
996
			if ( k == 9 && !(mask & 16))
997
				id = 0x3E;
998
999
			duneGround[x][y] = id;
1000
		}
1001
	}
1002
}
1003
1004
// Diamond Square algorithm
1005
void GenerateGroundCycle(Ground &g, int width)
1006
{
1007
	for (int step = width; step >= 1; step/=2)
1008
	{
1009
		int step2 = step/2;
1010
		for (int y=step2; y<width; y+=step)
1011
		{
1012
			for (int x=step2; x<width; x+=step)
1013
			{
1014
				g[x][y] = (g[x-step2][y-step2]
1015
						+ g[x+step2][y-step2]
1016
						+ g[x-step2][y+step2]
1017
						+ g[x+step2][y+step2])/4 + ((-1+randf()*2)*step2/64);
1018
				if (g[x][y]>1)
1019
					g[x][y]=1;
1020
				if (g[x][y]<0)
1021
					g[x][y]=0;
1022
			}
1023
		}
1024
		
1025
		for (int z=0; z<2; ++z)
1026
		{
1027
			for (int y=z*step2; y<width; y+=step)
1028
			{
1029
				for (int x=(1-z)*step2; x<width; x+=step)
1030
				{
1031
					double h = 0;
1032
					int n = 0;
1033
					if (g.in(x-step2,y))
1034
					{
1035
						h += g[x-step2][y];
1036
						++n;
1037
					}
1038
					if (g.in(x+step2,y))
1039
					{
1040
						h += g[x+step2][y];
1041
						++n;
1042
					}
1043
					if (g.in(x,y-step2))
1044
					{
1045
						h += g[x][y-step2];
1046
						++n;
1047
					}
1048
					if (g.in(x,y+step2))
1049
					{
1050
						h += g[x][y+step2];
1051
						++n;
1052
					}
1053
					h /= n;
1054
					h += ((-1+randf()*2)*step2/64);
1055
					if (h>1)
1056
						h=1;
1057
					if (h<0)
1058
						h=0;
1059
					g[x][y] = h;
1060
				}
1061
			}
1062
		}
1063
	}
1064
}
1065
1066
GLuint GenerateGround()
1067
{
1068
	g[        0][         0] = randf();
1069
	g[g.width-1][         0] = randf();
1070
	g[        0][g.height-1] = randf();
1071
	g[g.width-1][g.height-1] = randf();
1072
1073
	//GenerateGroundRecursive(g, 0, 0, g.width-1, g.height-1);
1074
	GenerateGroundCycle(g, g.width-1);
1075
	
1076
	return MakeGreyTexture();
1077
}
1078
1079
GLuint MakeGreyTexture()
1080
{
1081
	BYTE *data = (BYTE*)malloc( (g.width-1) * (g.height-1) * 3 );
1082
1083
	for (int x=0; x<g.width-1; ++x)
1084
	{
1085
		for (int y=0; y<g.height-1; ++y)
1086
		{
1087
			for (int i=0; i<3; ++i)
1088
				data[(x + y*(g.width-1))*3 + i] = g[x][y]*255;
1089
		}
1090
	}
1091
	
1092
	GLuint texture;
1093
	glGenTextures( 1, &texture );
1094
1095
	glBindTexture( GL_TEXTURE_2D, texture );
1096
	
1097
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1098
1099
	// when texture area is small, bilinear filter the closest MIP map
1100
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1101
	
1102
	// when texture area is large, bilinear filter the first MIP map
1103
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1104
1105
	// if wrap is true, the texture wraps over at the edges (repeat)
1106
	//       ... false, the texture ends at the edges (clamp)
1107
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
1108
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
1109
				  
1110
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, g.width-1, g.height-1, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
1111
1112
	free(data);
1113
1114
	return texture;
1115
}
1116
1117
void LoadMap( const char * filename )
1118
{
1119
	FILE *f = fopen(filename, "rb");
1120
	if (!f)
1121
		return;
1122
	BYTE tmp;
1123
	duneGround.Clear();
1124
	for (int y=0; y<duneGround.height; ++y)
1125
		for (int x=0; x<duneGround.width; ++x)
1126
		{
1127
			fread(&tmp,1,1,f);
1128
			duneGround[x][y]=tmp;
1129
			duneGround.SetTileMask(x,y);
1130
		}
1131
	fclose(f);
1132
}
1133
1134
void SaveMap( const char * filename )
1135
{
1136
	FILE *f = fopen(filename,"wb");
1137
	if (!f)
1138
		return;
1139
	for (int y=0; y<duneGround.height; ++y)
1140
		for (int x=0; x<duneGround.width; ++x)
1141
			fwrite(&duneGround[x][y],1,1,f);
1142
	fclose(f);
1143
}
1144
1145
void LoadMission( const char * filename )
1146
{
1147
	FILE *f = fopen(filename, "rb");
1148
	if (!f)
1149
		return;
1150
	//FILE *log = fopen("log.txt","w");
1151
	BYTE buff[20];
1152
	Units.clear();
1153
	Structures.clear();
1154
	DuneUnit unit;
1155
	DuneStructure structure;
1156
	for (;;)
1157
	{
1158
		BYTE cmd;
1159
		BYTE subcmd;
1160
		if (!fread(&cmd,1,1,f))
1161
			break;
1162
		fread(&subcmd,1,1,f);
1163
		//fprintf(log,"cmd = %d, subcmd = %d, offset = %X\n",cmd,subcmd,ftell(f)-2);
1164
		if (cmd & 0x80)
1165
			break;
1166
		switch(cmd)
1167
		{
1168
			// Settings
1169
			case 0:
1170
				switch(subcmd)
1171
				{
1172
					// LosePicture
1173
					case 0:
1174
					// WinPicture
1175
					case 1:
1176
					// BriefPicture
1177
					case 2:
1178
						fread(buff,1,2,f);
1179
						fseek(f,(buff[0]<<8)|buff[1],SEEK_CUR);
1180
						break;
1181
1182
					// TimeOut
1183
					case 3:
1184
					// MapScale
1185
					case 4:
1186
					// CursorPos
1187
					case 5:
1188
					// TacticalPos
1189
					case 6:
1190
					// LoseFlags
1191
					case 7:
1192
					// WinFlags
1193
					case 8:
1194
						fread(buff,1,2,f);
1195
						break;
1196
				}
1197
				break;
1198
			// MAP
1199
			case 1:
1200
				switch(subcmd)
1201
				{
1202
					// Bloom
1203
					case 'B':
1204
					// Field
1205
					case 'F':
1206
						fread(buff,1,2,f);
1207
						fseek(f,((buff[0]<<8)|buff[1])*2,SEEK_CUR);
1208
						break;
1209
					case 'S':
1210
						fread(buff,1,2,f);
1211
						//sprintf(buff,"%d",((buff[0]<<8)|buff[1]));
1212
						//MessageBox(NULL,buff,"Seed",MB_OK);
1213
						break;
1214
				}
1215
				break;
1216
			// Harkonnen
1217
			case 2:
1218
			// Atreides
1219
			case 3:
1220
			// Ordos
1221
			case 4:
1222
			// Fremen
1223
			case 5:
1224
				switch(subcmd)
1225
				{
1226
					// Quota
1227
					case 'Q':
1228
					// Credits
1229
					case 'C':
1230
					// Brain
1231
					case 'B':
1232
					// MaxUnits
1233
					case 'M':
1234
						fread(buff,1,2,f);
1235
						//sprintf(buff,"%d(%X)%c",cmd,ftell(f),subcmd);
1236
						//MessageBox(NULL,buff,"House",MB_OK);
1237
						break;
1238
				}
1239
				break;
1240
			// Starport (subcmd = unit)
1241
			case 6:
1242
				fread(buff,1,2,f);
1243
				break;
1244
			// Teams ( subcmd = team id )
1245
			case 7:
1246
				fseek(f,5*2,SEEK_CUR);
1247
				break;
1248
			// Units ( subcmd = unk )
1249
			case 8:
1250
				fread(buff,1,6*2,f);
1251
				unit.house = (buff[ 0]<<8) | buff[ 1];
1252
				unit.id    = (buff[ 2]<<8) | buff[ 3];
1253
				unit.life  = (buff[ 4]<<8) | buff[ 5];
1254
				unit.pos   = (buff[ 6]<<8) | buff[ 7];
1255
				unit.angle = (buff[ 8]<<8) | buff[ 9];
1256
				unit.ai    = (buff[10]<<8) | buff[12];
1257
				Units.push_back(unit);
1258
				break;
1259
			// Structures ( subcmd = unk )
1260
			case 9:
1261
				if (subcmd == 'G')
1262
				{
1263
					fread(buff,1,3*2,f);
1264
					structure.pos  = (buff[ 0]<<8) | buff[ 1];
1265
					structure.house = (buff[ 2]<<8) | buff[ 3];
1266
					structure.id    = (buff[ 4]<<8) | buff[ 5];
1267
				}
1268
				else
1269
				{
1270
					fread(buff,1,5*2,f);
1271
					structure.flag  = (buff[ 0]<<8) | buff[ 1];
1272
					structure.house = (buff[ 2]<<8) | buff[ 3];
1273
					structure.id    = (buff[ 4]<<8) | buff[ 5];
1274
					structure.life  = (buff[ 6]<<8) | buff[ 7];
1275
					structure.pos   = (buff[ 8]<<8) | buff[ 9];
1276
				}
1277
				Structures.push_back(structure);
1278
				break;
1279
			// Reinforcements 
1280
			case 10:
1281
				fread(buff,1,4*2,f);
1282
				break;
1283
		}
1284
	}
1285
	fclose(f);
1286
	//fclose(log);
1287
	//sprintf((char*)buff,"%d",Units.size());
1288
	//MessageBox(NULL,(char*)buff,"Units.size()",MB_OK);
1289
}
1290
1291
void FreeTexture( GLuint texture )
1292
{
1293
	glDeleteTextures( 1, &texture );
1294
}
1295
1296
bool mousedown = false;
1297
1298
void UpdateViewport(HWND hWnd)
1299
{
1300
	RECT rc;
1301
	GetClientRect(hWnd, &rc);
1302
	glViewport( 0, 0, rc.right, rc.bottom);
1303
	glMatrixMode( GL_PROJECTION ); 
1304
    glLoadIdentity(); 
1305
	//gluOrtho2D( 0,0,500,500);//camera.x, camera.y, camera.x+rc.right, camera.y+rc.bottom);
1306
	double scale = 1/32.0/zoom;
1307
	glScalef(64.0/rc.right*zoom,64.0/rc.bottom*zoom,1);
1308
	glTranslatef( -camera.x*scale, camera.y*scale, 0);
1309
	glMatrixMode( GL_MODELVIEW ); 
1310
}
1311
1312
void ChangeState(int _state)
1313
{
1314
	if (state == _state)
1315
		return;
1316
	state = _state;
1317
}
1318
1319
int CurrentMap = 0;
1320
1321
void TryQuit(HWND hWnd)
1322
{
1323
	int ret = MessageBox(hWnd,"Do you want to save map?","DuneGroundEditor",MB_YESNOCANCEL);
1324
	if (ret == IDYES)
1325
	{
1326
		LPCSTR filename = SaveFile(hWnd, NULL);
1327
		if (filename)
1328
		{
1329
			SaveMap(filename);
1330
			PostQuitMessage( 0 );
1331
		}
1332
	}
1333
	if (ret == IDNO)
1334
		PostQuitMessage( 0 );
1335
}
1336
// Window Proc ///////////////////////////////////////////////////////
1337
1338
LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
1339
                          WPARAM wParam, LPARAM lParam )
1340
{
1341
	switch ( message ) {
1342
1343
	case WM_CREATE:
1344
		return 0;
1345
1346
	case WM_CLOSE:
1347
		TryQuit(hWnd);
1348
		return 0;
1349
1350
	case WM_SIZE:
1351
		UpdateViewport(hWnd);
1352
		break;
1353
1354
	case WM_DESTROY:
1355
		return 0;
1356
1357
	case WM_KEYDOWN:
1358
		switch ( wParam ) {
1359
1360
		case VK_ESCAPE:
1361
			if (state == 0)
1362
				TryQuit(hWnd);
1363
			else
1364
				ChangeState(0);
1365
			return 0;
1366
			
1367
		case 'O':
1368
			{
1369
			LPCSTR filename = OpenFile(hWnd, "Choose Map");
1370
			if (filename)
1371
				LoadMap(filename);
1372
			}
1373
			return 0;
1374
		
1375
		case 'M':
1376
			{
1377
			LPCSTR filename = OpenFile(hWnd, "Choose Mission");
1378
			if (filename)
1379
				LoadMission(filename);
1380
			}
1381
			return 0;
1382
1383
		case 'S':
1384
			{
1385
			LPCSTR filename = SaveFile(hWnd, NULL);
1386
			if (filename)
1387
				SaveMap(filename);
1388
			}
1389
			return 0;
1390
		case 'G':
1391
			{
1392
			LPCSTR filename = OpenFile(hWnd, "Choose Grey Bitmap");
1393
			if (filename)
1394
			{
1395
				FreeTexture(GroundGrey);
1396
				GroundGrey = LoadGreyTexture(filename);
1397
			}
1398
			}
1399
			return 0;
1400
1401
		case 'R':
1402
			FreeTexture(GroundGrey);
1403
			GroundGrey = GenerateGround();
1404
			return 0;
1405
		case 'E':
1406
			if (state == 2)
1407
				ChangeState(1);
1408
			else
1409
				ChangeState(state^1);
1410
			return 0;
1411
		case 'F':
1412
			if (state == 2)
1413
				ChangeState(0);
1414
			else
1415
				ChangeState(2);
1416
			return 0;
1417
		case 'I':
1418
			drawinverse = !drawinverse;
1419
			return 0;
1420
		case '0':
1421
			drawtype = 0;
1422
			return 0;
1423
		case '1':
1424
			drawtype = 1;
1425
			return 0;
1426
		case '2':
1427
			drawtype = 2;
1428
			return 0;
1429
		case '3':
1430
			drawtype = 3;
1431
			return 0;
1432
		case '4':
1433
			drawtype = 4;
1434
			return 0;
1435
		case 'Q':
1436
			--drawsize;
1437
			if (drawsize == 0)
1438
				drawsize = 1;
1439
			return 0;
1440
		case 'W':
1441
			++drawsize;
1442
			return 0;
1443
		case 'C':
1444
			if (MessageBox(hWnd,"Do you really want to clear map?","DuneGroundEditor",MB_YESNO) == IDYES)
1445
				duneGround.Clear();
1446
			return 0;
1447
		 
1448
		case VK_SPACE:
1449
			showgrey = !showgrey;
1450
			return 0;
1451
		case 'U':
1452
			showunits = !showunits;
1453
			return 0;
1454
		}
1455
		return 0;
1456
1457
		case WM_MOUSEWHEEL:
1458
		{
1459
		RECT rc;
1460
		GetClientRect(hWnd,&rc);
1461
		mouse.x = GET_X_LPARAM(lParam); 
1462
		mouse.y = GET_Y_LPARAM(lParam);
1463
		short zDelta = HIWORD(wParam);
1464
		if (zDelta > 0)
1465
		{
1466
			zoom *= 1.2;
1467
			camera.x *= 1.2;//(camera.x + mouse.x) * (zoom/(zoom-0.1)) - mouse.x;
1468
			camera.y *= 1.2;//(camera.y + mouse.y) * (zoom/(zoom-0.1)) - mouse.y;
1469
		}
1470
		else
1471
		{
1472
			zoom /= 1.2;
1473
			camera.x /= 1.2;
1474
			camera.y /= 1.2;
1475
		}
1476
	
1477
		UpdateViewport(hWnd);
1478
		}
1479
		break;
1480
	case WM_LBUTTONDOWN:
1481
		{
1482
		SetCapture(hWnd);
1483
		mouse.x = GET_X_LPARAM(lParam); 
1484
		mouse.y = GET_Y_LPARAM(lParam);
1485
		//RECT rc;
1486
		//GetClientRect(hWnd,&rc);
1487
		//double cx = ((camera.x+mouse.x-(rc.right/2))/32.0/zoom);
1488
		//double cy = ((camera.y+mouse.y-(rc.bottom/2))/32.0/zoom);
1489
		if (state == 2)
1490
		{
1491
			duneGround = duneGroundNew;
1492
			ChangeState(0);
1493
		}
1494
		}
1495
		break;
1496
	case WM_MOUSEMOVE:
1497
		{
1498
		POINT pos = mouse;
1499
		mouse.x = GET_X_LPARAM(lParam);
1500
		mouse.y = GET_Y_LPARAM(lParam);
1501
		RECT rc;
1502
		GetClientRect(hWnd,&rc);
1503
		
1504
		if (mousedown)
1505
		{	
1506
			camera.x -= mouse.x-pos.x;
1507
			camera.y -= mouse.y-pos.y;
1508
			UpdateViewport(hWnd);
1509
		}
1510
		
1511
		double cx = ((camera.x+mouse.x-(rc.right/2))/32.0/zoom)*2+0.5;
1512
		double cy = ((camera.y+mouse.y-(rc.bottom/2))/32.0/zoom)*2+0.5;
1513
		if (state == 1 && duneGround.tin(cx,cy) && (GetKeyState(VK_LBUTTON) & 0x80))
1514
		{
1515
			for (int x=0; x<drawsize; ++x)
1516
			for (int y=0; y<drawsize; ++y)
1517
				if (duneGround.tin(cx+x,cx+y))
1518
					duneGround.Draw(cx+x,cy+y,drawtype);
1519
		}
1520
		}
1521
		break;
1522
	case WM_LBUTTONUP:
1523
		ReleaseCapture();
1524
		break;
1525
	case WM_RBUTTONDOWN:
1526
		SetCapture(hWnd);
1527
		mouse.x = GET_X_LPARAM(lParam); 
1528
		mouse.y = GET_Y_LPARAM(lParam);
1529
		mousedown = true;
1530
		break;
1531
	case WM_RBUTTONUP:
1532
		ReleaseCapture();
1533
		mousedown = false;
1534
		break;
1535
	}
1536
	return DefWindowProc( hWnd, message, wParam, lParam );
1537
}
1538
1539
1540
// Dialogs 
1541
1542
LPCSTR OpenFile(HWND hWnd, LPCSTR title)
1543
{
1544
	OPENFILENAME opn;
1545
	memset(&opn, 0, sizeof(opn));
1546
	opn.lStructSize = sizeof(opn);
1547
	opn.hwndOwner = hWnd;
1548
	opn.lpstrFilter = "All Files\0*.*\0\0";
1549
	opn.nFilterIndex = 1;
1550
	static char filename[MAX_PATH];
1551
	filename[0] = 0;
1552
	opn.lpstrFile = filename;
1553
	opn.nMaxFile = MAX_PATH;
1554
	opn.lpstrTitle = title;
1555
	opn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
1556
	if (GetOpenFileName(&opn))
1557
		return filename;
1558
	return NULL;
1559
}
1560
1561
LPCSTR SaveFile(HWND hWnd, LPCSTR title)
1562
{
1563
	OPENFILENAME opn;
1564
	memset(&opn, 0, sizeof(opn));
1565
	opn.lStructSize = sizeof(opn);
1566
	opn.hwndOwner = hWnd;
1567
	opn.lpstrFilter = "All Files\0*.*\0\0";
1568
	opn.nFilterIndex = 1;
1569
	static char filename[MAX_PATH];
1570
	filename[0] = 0;
1571
	opn.lpstrFile = filename;
1572
	opn.nMaxFile = MAX_PATH;
1573
	opn.lpstrTitle = title;
1574
	opn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
1575
	if (GetSaveFileName(&opn))
1576
		return filename;
1577
	return NULL;
1578
}
1579
1580
// Enable OpenGL
1581
1582
VOID EnableOpenGL( HWND hWnd, HDC * hDC, HGLRC * hRC )
1583
{
1584
	PIXELFORMATDESCRIPTOR pfd;
1585
	int iFormat;
1586
1587
	// get the device context (DC)
1588
	*hDC = GetDC( hWnd );
1589
1590
	// set the pixel format for the DC
1591
	ZeroMemory( &pfd, sizeof( pfd ) );
1592
	pfd.nSize = sizeof( pfd );
1593
	pfd.nVersion = 1;
1594
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | 
1595
		PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
1596
	pfd.iPixelType = PFD_TYPE_RGBA;
1597
	pfd.cColorBits = 24;
1598
	pfd.cDepthBits = 16;
1599
	pfd.iLayerType = PFD_MAIN_PLANE;
1600
	iFormat = ChoosePixelFormat( *hDC, &pfd );
1601
	SetPixelFormat( *hDC, iFormat, &pfd );
1602
1603
	// create and enable the render context (RC)
1604
	*hRC = wglCreateContext( *hDC );
1605
	wglMakeCurrent( *hDC, *hRC );
1606
1607
}
1608
1609
// Disable OpenGL
1610
1611
VOID DisableOpenGL( HWND hWnd, HDC hDC, HGLRC hRC )
1612
{
1613
	wglMakeCurrent( NULL, NULL );
1614
	wglDeleteContext( hRC );
1615
	ReleaseDC( hWnd, hDC );
1616
}