blob: a1e15a81b4466c751721575dd4790835e19806cf [file] [log] [blame]
/**
* projectM -- Milkdrop-esque visualisation SDK
* Copyright (C)2003-2004 projectM Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* See 'LICENSE.txt' included within this release
*
*/
/**
* $Id: wxvisCanvas.cpp,v 1.5 2004/11/12 15:47:27 cvs Exp $
*
* Handles all the OpenGL drawing in the main wxvis display
*/
#include <wx/wx.h>
#ifdef WIN32
#include <windows.h>
#endif /** WIN32 */
#include <math.h>
#include <projectM-engine/wipemalloc.h>
#include <projectM-engine/BeatDetect.hpp>
#include <projectM-engine/PCM.hpp>
#include <projectM-engine/Preset.hpp>
#include "wxvisApp.h"
#include "wxvisFrame.h"
#include "wxvisCanvas.h"
/** Event handler table */
BEGIN_EVENT_TABLE(wxvisCanvas,wxGLCanvas)
EVT_SIZE(wxvisCanvas::OnSize)
EVT_PAINT(wxvisCanvas::OnPaint)
EVT_ERASE_BACKGROUND(wxvisCanvas::OnEraseBackground)
EVT_KEY_DOWN(wxvisCanvas::OnKeyPress)
END_EVENT_TABLE()
/** Create the OpenGL canvas */
wxvisCanvas::wxvisCanvas( wxFrame *parent, const wxWindowID id,
const wxPoint &pos, const wxSize &dims,
long style, const wxString &name ) :
wxGLCanvas( parent, (wxGLCanvas *)NULL, id,
pos, dims, style, name ) {
_parent = (wxvisFrame *)parent;
_hasInitialised = 0;
pm = NULL;
/** Create a semaphore to regulate thread access to the refresh function */
#ifdef WIN32
refreshSemaphore =
CreateSemaphore( NULL, 1, 1, "Redraw Semaphore" );
InitializeCriticalSection( &refreshMutex );
#endif
}
/** Repaint the canvas */
void wxvisCanvas::OnPaint( wxPaintEvent &event ) {
/** Acquire the semaphore before running... */
#ifdef WIN32
#ifdef DEBUG2
fprintf( debugFile, "-> OnPaint(): Acquiring mutex\n" );
fflush( debugFile );
#endif
// WaitForSingleObject( refreshSemaphore, INFINITE );
EnterCriticalSection( &refreshMutex );
#ifdef DEBUG2
fprintf( debugFile, "-> OnPaint(): Semaphore acquired[]\n" );
fflush( debugFile );
#endif
#endif
wxSize dims = GetClientSize();
/** Get the paint device context */
wxPaintDC dc( this );
/** Swap in the OpenGL context */
#ifndef __WXMOTIF__
if ( !GetContext() ) {
return;
}
#endif
SetCurrent();
/** See if we've initialised */
if ( !_hasInitialised ) {
printf( "here\n" );
initialise();
printf( "here2: %X\n", pm );
if ( pm != NULL ) {
printf( "here3\n" );
pm->projectM_resetGL( dims.x, dims.y );
printf( "here4\n" );
_hasInitialised = 1;
} else {
goto unlockAndExit;
}
}
int i;
short pcm_data[2][512];
/** Produce some fake PCM data to stuff into projectM */
if ( pm->count % 5 == 0 ) {
for ( i = 0 ; i < 512 ; i++ ) {
pcm_data[0][i] = 0;
pcm_data[1][i] = 0;
}
} else {
for ( i = 0 ; i < 512 ; i++ ) {
if ( i % 2 == 0 ) {
pcm_data[0][i] = (short)( (float)( rand() / ( (float)RAND_MAX ) * (pow(2,i%14) ) ) );
pcm_data[1][i] = (short)( (float)( rand() / ( (float)RAND_MAX ) * (pow(2,i/2%14) ) ) );
} else {
pcm_data[0][i] = (short)( (float)( rand() / ( (float)RAND_MAX ) * (pow(2,i/2%14) ) ) );
pcm_data[1][i] = (short)( (float)( rand() / ( (float)RAND_MAX ) * (pow(2,i%14) ) ) );
}
if ( i % 2 == 1 ) {
pcm_data[0][i] = -pcm_data[0][i];
pcm_data[1][i] = -pcm_data[1][i];
}
}
}
/** Add the waveform data */
DWRITE( "pm: %X\tbeatDetect: %X\tpcm: %X\tpcm_data: %X\n",
pm, pm->beatDetect, pm->beatDetect->pcm, pcm_data );
pm->beatDetect->pcm->addPCM16( pcm_data );
/** Render the new frame */
pm->renderFrame();
#ifdef PANTS
if ( dumpFrame ) {
char fname[1024];
FILE *f = fopen( fname, "wb" );
sprintf( fname, "projectM_%08d.ppm", frameNumber++ );
fprintf( f, "P3\n#\n%d %d\n255\n", pm->wvw, pm->wvh );
glReadPixels( 0, 0, pm->wvw, pm->wvh, GL_RGB, GL_UNSIGNED_BYTE, fbuffer );
index = 0;
for ( y = 0 ; y < pm->wvh ; y++ ) {
for ( x = 0 ; x < pm->wvw ; x++ ) {
fprintf( f, "%d %d %d ", fbuffer[index++], fbuffer[index++], fbuffer[index++] );
}
fprintf( f, "\n" );
}
fclose( f );
}
#endif
/** Buffer swap in here */
SwapBuffers();
unlockAndExit:
#ifdef WIN32
/** Unlock the mutex */
LeaveCriticalSection( &refreshMutex );
// ReleaseSemaphore( refreshSemaphore, 1, NULL );
#ifdef DEBUG2
fprintf( debugFile, "<- OnPaint(): Released semaphore[]\n" );
fflush( debugFile );
#endif
// ExitThread( 0 );
#endif
return;
}
/** Handles resize events */
void wxvisCanvas::OnSize( wxSizeEvent &event ) {
wxGLCanvas::OnSize( event );
int w, h;
GetClientSize( &w, &h );
/** Reset the viewport size */
#ifndef __WXMOTIF__
if ( GetContext() ) {
#endif
SetCurrent();
glViewport( 0, 0, w, h );
#ifndef __WXMOTIF__
}
#endif
if ( pm != NULL && pm->hasInit ) {
pm->projectM_resetGL( w, h );
}
}
/** Enables double-buffering, or a reasonable approximation thereof! */
void wxvisCanvas::OnEraseBackground( wxEraseEvent &event ) {
// Do nothing, to avoid flashing.
}
/** Initialise the context -- this only happens once */
void wxvisCanvas::initialise() {
#ifdef WIN32
/** Initialise font bitmap lists */
SelectObject( (HDC)GetHDC(), GetStockObject( SYSTEM_FONT ) );
glColor3f( 1, 1, 1 );
wglUseFontBitmaps( (HDC)GetHDC(), 0, 255, 1000 );
#else
#ifdef __WXMAC__
/** Initialise font bitmap lists */
short familyId = 0;
GetFNum( (const unsigned char *)"systemFont", &familyId );
aglUseFont( aglGetCurrentContext(), familyId, normal, 12, 0, 255, 1000 );
#endif
#endif
/** Initialise projectM */
pm = (projectM *)wipemalloc( sizeof( projectM ) );
pm->projectM_reset();
pm->fullscreen = 0;
pm->renderTarget->texsize = 1024;
#ifndef WIN32
pm->fontURL = (char *)malloc( sizeof( char ) * 512 );
strcpy( pm->fontURL, "../../fonts" );
pm->presetURL = (char *)malloc( sizeof( char ) * 512 );
strcpy( pm->presetURL, "/Users/descarte/tmp/projectM-1.00/presets_milkdrop" );
#else
pm->fontURL = (char *)malloc( sizeof( char ) * 512 );
strcpy( pm->fontURL, "c:\\tmp\\projectM-1.00\\fonts" );
pm->presetURL = (char *)malloc( sizeof( char ) * 512 );
strcpy( pm->presetURL, "c:\\tmp\\projectM-1.00\\presets_projectM" );
#endif /** MACOS */
pm->projectM_init();
}
/** Returns the number of depth bits */
int wxvisCanvas::getDepthBits() {
int rv[1];
SetCurrent();
glGetIntegerv( GL_DEPTH_BITS, (GLint *)rv );
return rv[0];
}
/** Returns the number of stencil bits */
int wxvisCanvas::getStencilBits() {
int rv[1];
SetCurrent();
glGetIntegerv( GL_STENCIL_BITS, (GLint *)rv );
return rv[0];
}
/** Handle keypresses */
void wxvisCanvas::OnKeyPress( wxKeyEvent &event ) {
int i;
switch ( event.GetKeyCode() ) {
case 'R': {
pm->switchPreset( RANDOM_NEXT, HARD_CUT );
break;
}
case 'N': {
pm->switchPreset( ALPHA_NEXT, HARD_CUT );
break;
}
case 'P': {
pm->switchPreset( ALPHA_PREVIOUS, HARD_CUT );
break;
}
case WXK_ESCAPE: {
_parent->app->shutdown();
break;
}
}
Refresh( FALSE );
}