Initial Git commit
[chess] / src / chess3D.ec
1 import "chess.ec"
2
3 static char * names[Player][PieceType] =
4 {
5    { "", "WhitePawn", "WhiteKnigh", "WhiteBisho", "WhiteRook", "WhiteQueen", "WhiteKing" },
6    { "", "BlackPawn", "BlackKnigh", "BlackBisho", "BlackRook", "BlackQueen", "BlackKing" },
7 };
8
9 define SQUARE = squareSize; // 160;
10 define SQUARE_OFFSET = SQUARE * 3.5f;
11
12 class Chess3D : Window
13 {
14    Camera camera 
15    { 
16       attached, fov = 45, zMin = 50,zMax = 5000, 
17       position = { 0, 0, -1000 },
18       orientation = Euler { 30, 30, 0 }
19    };
20
21    Object chessSet { };
22
23    Object chessBoard;
24    bool moving, lightMoving;
25    Point startPosition;
26    Euler startOrientation;
27    Light light;
28    FillModeValue fillMode;
29    ChessState * chessState;
30    double squareSize;
31    double offsetY;
32
33    bool pieceSelected;
34    Point start;
35
36    // Dragging
37    bool useDrag;
38    Point dragging;
39    double dragY;
40
41    bool antiAlias;
42
43    antiAlias = true;
44
45    menu = Menu {};
46    Menu viewMenu { menu, "View", v };
47    MenuItem itemAntiAlias
48    {
49       viewMenu, "Anti Aliased", s, checkable = true, checked = antiAlias;
50       bool NotifySelect(MenuItem selection, Modifiers mods)
51       {
52          antiAlias ^= true;
53          Update(null);
54          return true;
55       }
56    };
57
58    isActiveClient = true, background = black, borderStyle = sizable, hasMaximize = true, hasMinimize = true;
59
60    void RenderPiece(Piece atBoard, int x, int y, bool high)
61    {
62       Player player = atBoard.player;
63       PieceType type = atBoard.type;
64       
65       if(type)
66       {
67          char * name = names[player][type];
68          Object object = chessSet.Find(name);
69          if(object)
70          {
71          
72             float height = 0;
73             if(high)
74             {
75                Piece overAtBoard = chessState->board[y][x];
76                Player overPlayer = overAtBoard.player;
77                PieceType overType = overAtBoard.type;
78                if(overType)
79                {
80                   char * name = names[overPlayer][overType];
81                   Object over = chessSet.Find(name);
82                   if(over)
83                      height = over.max.y - over.min.y;
84                }
85             }
86
87             object.flags.root = true;
88
89             object.transform.position = {
90                x * SQUARE - SQUARE_OFFSET,
91                offsetY - height;
92                y * SQUARE - SQUARE_OFFSET };
93             
94             object.UpdateTransform();
95
96             object.tag = (void *)(((y)*8)+(x)+1);
97             display.DrawObject(object);
98          }
99       }
100    }
101
102    void RenderSquare(int x, int y)
103    {
104       if(x >= 0 && x < 8 && y >= 0 && y < 8)
105       {
106          Piece atBoard = chessState->board[y][x];
107
108          if(useDrag && pieceSelected)
109          {
110             if(x == start.x && y == start.y) return;
111             if(x == dragging.x && y == dragging.y)
112             {
113                Piece atBoardStart = chessState->board[start.y][start.x];
114                if(atBoard && atBoard.player != atBoardStart.player) return;
115             }
116          }
117          RenderPiece(atBoard, x, y, false);
118       }
119    }
120    
121    void RenderBoard()
122    {
123       display.DrawObject(chessBoard);
124   
125       if(chessState->gameRunning)
126       {
127          int x,y;
128          for(y=0; y<8; y++)
129                  for(x=0; x<8; x++)
130                RenderSquare(x, y);
131          
132          if(useDrag && pieceSelected)
133          {
134             Piece atBoard = chessState->board[start.y][start.x];
135             Piece atBoardDrag = chessState->board[dragging.y][dragging.x];
136             RenderPiece(atBoard, dragging.x, dragging.y,
137                (dragging.x != start.x || dragging.y != start.y) &&
138                atBoardDrag && atBoardDrag.player == atBoard.player);
139          }
140       }
141    }
142
143    void OnUnloadGraphics()
144    {
145       displaySystem.ClearMaterials();
146       displaySystem.ClearTextures();
147       displaySystem.ClearMeshes();
148    }
149
150    void OnPosition(int x, int y, int w, int h)
151    {
152       camera.Setup(w, h, null);
153    }
154
155    bool OnLeftButtonDown(int x, int y, Modifiers mods)
156    {
157       OldList list {};
158                    
159       display.StartSelection(x,y, 0,0);
160       display.SetCamera(null, camera);
161       display.CollectHits();
162
163
164       if(chessState->gameRunning)
165       {
166          int cx,cy;
167          for(cy = 0; cy < 8; cy++)
168                  for(cx = 0; cx < 8; cx++)
169                RenderSquare(cx, cy);
170       }
171
172       if(display.GetHits(list))
173       {
174          HitRecord hit = list.first;
175          int tag = ((int)hit.tags[0]) - 1;
176          int sx = tag & 7, sy = tag >> 3;
177
178          if(pieceSelected)
179          {
180             pieceSelected = false;
181             ((Chess)master).ProcessUserMove(start.x, start.y, sx, sy);
182          }
183          else if(chessState->board[sy][sx] && 
184             chessState->isLocalPlayer[chessState->turn] && 
185             chessState->board[sy][sx].player == chessState->turn)
186          {
187             if(useDrag)
188             {
189                Vector3D viewSpace, worldSpace;
190                display.IntersectPolygons();
191                RenderSquare(sx, sy);               
192                display.GetIntersect(viewSpace);
193
194                camera.Untransform(viewSpace, worldSpace);
195
196                dragY = worldSpace.y;
197                dragging.x = sx;
198                dragging.y = sy;
199             }
200             Capture();
201             pieceSelected = true;
202             start.x = sx;
203             start.y = sy;
204             Update(null);
205
206             OnMouseMove(x, y, mods);
207          }
208          
209          list.Free(null);
210       }
211       else if(display.DrawObject(chessBoard) && !moving && !lightMoving)
212       {
213          startPosition.x = x;
214          startPosition.y = y;
215          startOrientation = camera.orientation;
216          Capture();
217          moving = true;
218       }
219       display.SetCamera(null, null);
220       display.StopSelection();
221       Update(null);
222
223       return true;
224    }
225
226    bool OnLeftButtonUp(int x, int y, Modifiers mods)
227    {
228       if(moving)
229       {
230          ReleaseCapture();
231          moving = false;
232       }
233       if(useDrag && pieceSelected)
234       {
235          ReleaseCapture();
236          ((Chess)master).ProcessUserMove(start.x, start.y, dragging.x, dragging.y);
237          Update(null);
238          pieceSelected = false;
239       }
240       return true;
241    }
242
243    bool OnRightButtonDown(int x, int y, Modifiers mods)
244    {
245       if(!moving && !lightMoving)
246       {
247          startPosition.x = x;
248          startPosition.y = y;
249          startOrientation = light.orientation;
250          Capture();
251          lightMoving = true;
252       }
253       return true;
254    }
255
256    bool OnRightButtonUp(int x, int y, Modifiers mods)
257    {
258       if(lightMoving)
259       {
260          ReleaseCapture();
261          lightMoving = false;
262       }
263       return true;
264    }
265
266    bool OnMouseMove(int x, int y, Modifiers mods)
267    {
268       if(moving)
269       {
270          Euler angle
271          {
272             startOrientation.yaw   - (x - startPosition.x),
273             startOrientation.pitch + (y - startPosition.y),
274             0
275          };
276          if(angle.pitch > 90) angle.pitch = 90;
277          if(angle.pitch < 2)  angle.pitch = 2;
278          camera.orientation = angle;
279
280          Update(null);
281       }
282       else if(lightMoving)
283       {
284          light.orientation = Euler
285          { 
286             startOrientation.yaw + (x - startPosition.x), 
287             startOrientation.pitch + (y - startPosition.y), 
288             90 
289          };
290          
291          Update(null);
292       }
293       else if(pieceSelected && useDrag)
294       {
295          Vector3D p, v1, v2, w1, w2, vector;
296          Line line;
297          Plane plane;
298          int sx, sy;
299
300          // Compute ray of pixel
301          v1.x = 0;
302          v1.y = 0;
303          v1.z = 0;
304          p.x = (float)x;
305          p.y = (float)y;
306          p.z = 0;
307          camera.Unproject(p, v2);
308
309          // Convert ray to world space
310          camera.Untransform(v1, w1);
311          camera.Untransform(v2, w2);
312          line.p0 = w1;
313          line.delta.x = w2.x - w1.x;
314          line.delta.y = w2.y - w1.y;
315          line.delta.z = w2.z - w1.z;
316
317          // Compute plane of selection in world space
318          vector   = { 0,dragY,0 };
319          w1       = { 1,dragY,0 };
320          w2       = { 0,dragY,1 };
321          plane.FromPoints(vector, w1, w2);
322
323          // Find intersection
324          plane.IntersectLine(line, vector);
325
326          sx = (int)((vector.x + SQUARE * 4) / SQUARE);
327          sy = (int)((vector.z + SQUARE * 4) / SQUARE);
328          sx = Max(Min(sx, 7), 0);
329          sy = Max(Min(sy, 7), 0);
330
331          dragging.x = sx;
332          dragging.y = sy;
333          Update(null);
334       }
335       return true;
336    }
337
338    bool OnKeyHit(Key key, unichar ch)
339    {
340       switch((SmartKey)key)
341       {
342          case wheelDown:
343          case minus:
344             camera.position.z *= 1.1f;
345             if(camera.position.z <= -3800)
346                camera.position.z = -3800;
347             Update(null);
348             break;
349          case wheelUp:
350          case equal: camera.position.z /= 1.1f; 
351             if(camera.position.z >= -1100)
352                camera.position.z = -1100;
353             Update(null);
354             break;
355       }
356       return true;
357    }
358
359    bool OnLoadGraphics()
360    {
361       display.vSync = true;
362       chessSet.Load(":chessSet.3ds", null, displaySystem);
363
364       //chessSet.transform.orientation.RotateY(45);
365       //chessSet.UpdateTransform();
366
367       chessBoard = chessSet.Find("Rectangle0");
368       chessBoard.flags.root = true;
369
370       {
371          Object queen = chessSet.Find(names[White][Queen]);
372          Object king  = chessSet.Find(names[White][King]);
373
374          squareSize = king.transform.position.x - queen.transform.position.x;
375          offsetY = king.transform.position.y;
376       }
377
378       if(chessBoard)
379          camera.position.z = - chessBoard.radius * 2.5f;
380
381       camera.target = chessBoard;
382
383       return true;
384    }
385
386    void OnRedraw(Surface surface)
387    {
388       //surface.SetBackground(white);
389       surface.Clear(colorAndDepth);
390
391       camera.Update();
392       display.antiAlias = antiAlias;
393       display.SetCamera(surface, camera);
394       //display.fogDensity = 0.0002f;
395       display.antiAlias = antiAlias;
396
397       display.SetLight(0, light);
398       display.fillMode = fillMode;
399
400       RenderBoard();
401
402       display.SetCamera(surface, null);
403
404       display.fillMode = solid;
405    }
406
407    bool OnCreate()
408    {
409       fillMode = solid;
410       //fillMode = wireframe;
411
412       light.diffuse = white;
413       light.specular = white;
414
415       light.orientation = Euler { pitch = 90 };
416       useDrag = true;
417
418       return true;
419    }
420    property ChessState * chessState { set { chessState = value; } }
421 }