The Pedigree Project  0.1
gears.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
22  *
23  * Permission is hereby granted, free of charge, to any person obtaining a
24  * copy of this software and associated documentation files (the "Software"),
25  * to deal in the Software without restriction, including without limitation
26  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
27  * and/or sell copies of the Software, and to permit persons to whom the
28  * Software is furnished to do so, subject to the following conditions:
29  *
30  * The above copyright notice and this permission notice shall be included
31  * in all copies or substantial portions of the Software.
32  *
33  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
34  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
36  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
37  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39  */
40 /* $XFree86: xc/programs/glxgears/glxgears.c,v 1.4 2003/10/24 20:38:11 tsi Exp $ */
41 
42 /*
43  * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
44  * Port by Brian Paul 23 March 2001
45  *
46  * Command line options:
47  * -info print GL implementation information
48  *
49  */
50 
51 // Simplified, courtesy of Kevin Lange.
52 
53 #define _USE_MATH_DEFINES
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <math.h>
57 #include <sched.h>
58 #include <string.h>
59 #include <unistd.h>
60 #include <sys/klog.h>
61 #include <sys/time.h>
62 
63 #include <GL/gl.h>
64 #include <GL/osmesa.h>
65 
66 #include "pedigree/native/graphics/Graphics.h"
67 #include <Widget.h>
68 
69 class Gears;
70 
71 Gears *g_pGears = NULL;
72 
73 bool g_bRunning = false;
74 
75 static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
76 static GLint gear1, gear2, gear3;
77 static GLfloat angle = 0.0;
78 
79 static unsigned int frames = 0;
80 static unsigned int start_time = 0;
81 
82 void fps()
83 {
84  struct timeval now;
85  gettimeofday(&now, NULL);
86  frames++;
87  if (!start_time)
88  {
89  start_time = now.tv_sec;
90  }
91  else if ((now.tv_sec - start_time) >= 5)
92  {
93  GLfloat seconds = now.tv_sec - start_time;
94  GLfloat fps = frames / seconds;
95  klog(LOG_INFO, "%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds, fps);
96  start_time = now.tv_sec;
97  frames = 0;
98  }
99 }
100 
101 static void
102 gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
103  GLint teeth, GLfloat tooth_depth)
104 {
105  GLint i;
106  GLfloat r0, r1, r2;
107  GLfloat angle, da;
108  GLfloat u, v, len;
109 
110  r0 = inner_radius;
111  r1 = outer_radius - tooth_depth / 2.0;
112  r2 = outer_radius + tooth_depth / 2.0;
113 
114  da = 2.0 * M_PI / teeth / 4.0;
115 
116  glShadeModel(GL_FLAT);
117 
118  glNormal3f(0.0, 0.0, 1.0);
119 
120  /* draw front face */
121  glBegin(GL_QUAD_STRIP);
122  for (i = 0; i <= teeth; i++) {
123  angle = i * 2.0 * M_PI / teeth;
124  glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
125  glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
126  if (i < teeth) {
127  glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
128  glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
129  width * 0.5);
130  }
131  }
132  glEnd();
133 
134  /* draw front sides of teeth */
135  glBegin(GL_QUADS);
136  da = 2.0 * M_PI / teeth / 4.0;
137  for (i = 0; i < teeth; i++) {
138  angle = i * 2.0 * M_PI / teeth;
139 
140  glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
141  glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
142  glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
143  width * 0.5);
144  glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
145  width * 0.5);
146  }
147  glEnd();
148 
149  glNormal3f(0.0, 0.0, -1.0);
150 
151  /* draw back face */
152  glBegin(GL_QUAD_STRIP);
153  for (i = 0; i <= teeth; i++) {
154  angle = i * 2.0 * M_PI / teeth;
155  glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
156  glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
157  if (i < teeth) {
158  glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
159  -width * 0.5);
160  glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
161  }
162  }
163  glEnd();
164 
165  /* draw back sides of teeth */
166  glBegin(GL_QUADS);
167  da = 2.0 * M_PI / teeth / 4.0;
168  for (i = 0; i < teeth; i++) {
169  angle = i * 2.0 * M_PI / teeth;
170 
171  glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
172  -width * 0.5);
173  glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
174  -width * 0.5);
175  glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
176  glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
177  }
178  glEnd();
179 
180  /* draw outward faces of teeth */
181  glBegin(GL_QUAD_STRIP);
182  for (i = 0; i < teeth; i++) {
183  angle = i * 2.0 * M_PI / teeth;
184 
185  glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
186  glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
187  u = r2 * cos(angle + da) - r1 * cos(angle);
188  v = r2 * sin(angle + da) - r1 * sin(angle);
189  len = sqrt(u * u + v * v);
190  u /= len;
191  v /= len;
192  glNormal3f(v, -u, 0.0);
193  glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
194  glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
195  glNormal3f(cos(angle), sin(angle), 0.0);
196  glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
197  width * 0.5);
198  glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
199  -width * 0.5);
200  u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
201  v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
202  glNormal3f(v, -u, 0.0);
203  glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
204  width * 0.5);
205  glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
206  -width * 0.5);
207  glNormal3f(cos(angle), sin(angle), 0.0);
208  }
209 
210  glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
211  glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
212 
213  glEnd();
214 
215  glShadeModel(GL_SMOOTH);
216 
217  /* draw inside radius cylinder */
218  glBegin(GL_QUAD_STRIP);
219  for (i = 0; i <= teeth; i++) {
220  angle = i * 2.0 * M_PI / teeth;
221  glNormal3f(-cos(angle), -sin(angle), 0.0);
222  glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
223  glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
224  }
225  glEnd();
226 }
227 
228 
229 static void
230 draw(void)
231 {
232  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
233 
234  glPushMatrix();
235  glRotatef(view_rotx, 1.0, 0.0, 0.0);
236  glRotatef(view_roty, 0.0, 1.0, 0.0);
237  glRotatef(view_rotz, 0.0, 0.0, 1.0);
238 
239  glPushMatrix();
240  glTranslatef(-3.0, -2.0, 0.0);
241  glRotatef(angle, 0.0, 0.0, 1.0);
242  glCallList(gear1);
243  glPopMatrix();
244 
245  glPushMatrix();
246  glTranslatef(3.1, -2.0, 0.0);
247  glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
248  glCallList(gear2);
249  glPopMatrix();
250 
251  glPushMatrix();
252  glTranslatef(-3.1, 4.2, 0.0);
253  glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
254  glCallList(gear3);
255  glPopMatrix();
256 
257  glPopMatrix();
258 }
259 
260 
261 
262 /* new window size or exposure */
263 static void
264 reshape(int width, int height)
265 {
266  GLfloat h = (GLfloat) height / (GLfloat) width;
267 
268  glViewport(0, 0, (GLint) width, (GLint) height);
269  glMatrixMode(GL_PROJECTION);
270  glLoadIdentity();
271  glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
272  glMatrixMode(GL_MODELVIEW);
273  glLoadIdentity();
274  glTranslatef(0.0, 0.0, -40.0);
275 }
276 
277 
278 
279 static void
280 init(void)
281 {
282  static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
283  static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
284  static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
285  static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
286 
287  glLightfv(GL_LIGHT0, GL_POSITION, pos);
288  glEnable(GL_CULL_FACE);
289  glEnable(GL_LIGHTING);
290  glEnable(GL_LIGHT0);
291  glEnable(GL_DEPTH_TEST);
292 
293  /* make the gears */
294  gear1 = glGenLists(1);
295  glNewList(gear1, GL_COMPILE);
296  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
297  gear(1.0, 4.0, 1.0, 20, 0.7);
298  glEndList();
299 
300  gear2 = glGenLists(1);
301  glNewList(gear2, GL_COMPILE);
302  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
303  gear(0.5, 2.0, 2.0, 10, 0.7);
304  glEndList();
305 
306  gear3 = glGenLists(1);
307  glNewList(gear3, GL_COMPILE);
308  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
309  gear(1.3, 2.0, 0.5, 10, 0.7);
310  glEndList();
311 
312  glEnable(GL_NORMALIZE);
313 }
314 
315 
316 class Gears : public Widget
317 {
318  public:
319  Gears() : Widget(), fb(NULL), m_bGlInit(false), m_bContextValid(false), m_nWidth(0), m_nHeight(0)
320  {};
321  virtual ~Gears()
322  {}
323 
324  bool initOpenGL()
325  {
326  gl_ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
327 
328  m_bGlInit = true;
329 
330  if(m_nWidth)
331  {
332  glResize(m_nWidth, m_nHeight);
333  }
334 
335  return true;
336  }
337 
338  void deinitOpenGL()
339  {
340  OSMesaDestroyContext(gl_ctx);
341  }
342 
343  void reposition(PedigreeGraphics::Rect newrt)
344  {
345  m_nWidth = newrt.getW();
346  m_nHeight = newrt.getH();
347  glResize(newrt.getW(), newrt.getH());
348  }
349 
351  {
352  if(!(m_bGlInit && m_bContextValid && fb))
353  {
354  return false;
355  }
356 
357  // Render frame.
358  angle += 0.2;
359  draw();
360 
361  dirty.update(0, 0, m_nWidth, m_nHeight);
362 
363  return true;
364  }
365 
366  private:
367 
368  bool glResize(size_t w, size_t h)
369  {
370  if(!m_bGlInit)
371  {
372  return false;
373  }
374 
375  fb = (uint8_t*) getRawFramebuffer();
376  if(!fb)
377  {
378  m_bContextValid = false;
379  fprintf(stderr, "Couldn't get a framebuffer to use.\n");
380  return false;
381  }
382 
383  if(!OSMesaMakeCurrent(gl_ctx, fb, GL_UNSIGNED_BYTE, w, h))
384  {
385  m_bContextValid = false;
386  fprintf(stderr, "OSMesaMakeCurrent failed.\n");
387  return false;
388  }
389 
390  // Don't render upside down.
391  OSMesaPixelStore(OSMESA_Y_UP, 0);
392 
393  reshape(w, h);
394 
395  m_bContextValid = true;
396 
397  return true;
398  }
399 
400  uint8_t *fb;
401 
402  bool m_bGlInit;
403  bool m_bContextValid;
404 
405  OSMesaContext gl_ctx;
406 
407  size_t m_nWidth, m_nHeight;
408 };
409 
410 bool callback(WidgetMessages message, size_t msgSize, const void *msgData)
411 {
412  switch(message)
413  {
414  case RepaintNeeded:
415  {
416  PedigreeGraphics::Rect rt, dirty;
417  if(g_pGears->render(rt, dirty))
418  {
419  g_pGears->redraw(dirty);
420  }
421  }
422  break;
423  case Reposition:
424  {
425  const PedigreeGraphics::Rect *rt = reinterpret_cast<const PedigreeGraphics::Rect*>(msgData);
426  g_pGears->reposition(*rt);
427  }
428  break;
429  case KeyUp:
430  {
431  const uint64_t *key = reinterpret_cast<const uint64_t*>(msgData);
432  klog(LOG_INFO, "gears: keypress %d '%c'", (uint32_t) *key, (char) (*key & 0xFF));
433 
434  // What do we have?
436  char realChar = *key & 0xFF;
437  if(realChar == 'a')
438  {
439  view_roty += 5.0;
440  }
441  else if(realChar == 'd')
442  {
443  view_roty -= 5.0;
444  }
445  else if(realChar == 'w')
446  {
447  view_rotx += 5.0;
448  }
449  else if(realChar == 's')
450  {
451  view_rotx -= 5.0;
452  }
453  }
454  break;
455  case Terminate:
456  g_bRunning = false;
457  break;
458  default:
459  klog(LOG_INFO, "gears: unhandled callback");
460  }
461  return true;
462 }
463 
464 int main (int argc, char ** argv) {
465  PedigreeGraphics::Rect rt(30, 30, 500, 500);
466 
467  char endpoint[256];
468  sprintf(endpoint, "gears.%d", getpid());
469 
470  g_pGears = new Gears();
471  if(!g_pGears->construct(endpoint, "OSMesa 3D Gears", callback, rt)) {
472  klog(LOG_ERR, "gears: not able to construct widget");
473  delete g_pGears;
474  return 1;
475  }
476  klog(LOG_INFO, "gears: widget constructed");
477 
478  g_pGears->initOpenGL();
479 
480  klog(LOG_INFO, "gears: reshaping");
481 
482  init();
483 
484  klog(LOG_INFO, "gears: entering main loop");
485 
486  g_bRunning = true;
487  while (g_bRunning) {
489 
490  // Cheat a bit, render every frame.
491  callback(RepaintNeeded, 0, 0);
492 
493  // Display our FPS - nice way to see how vbe performs...
494  fps();
495  }
496 
497  g_pGears->deinitOpenGL();
498  g_pGears->destroy();
499 
500  delete g_pGears;
501 
502  return 0;
503 }
504 
static void checkForEvents(bool bAsync=false)
Definition: Widget.cc:339
void * getRawFramebuffer()
Definition: Widget.h:142
bool redraw(PedigreeGraphics::Rect &rt)
Definition: Widget.cc:225
void destroy()
Definition: Widget.cc:301
Definition: Widget.h:63
bool construct(const char *endpoint, const char *title, widgetCallback_t cb, PedigreeGraphics::Rect &dimensions)
Definition: Widget.cc:90
virtual bool render(PedigreeGraphics::Rect &rt, PedigreeGraphics::Rect &dirty)
Definition: gears.cc:350
Definition: gears.cc:316