Why do I keep getting a multiple definition error? - c

Recently I've been working on my first game in C. (It is also my first programming language.) I finished a course ages ago and found a wonderful library called SDL2. It's great for graphics and all sorts. I've been also looking at other people's code and just been learning off of that too.
Anyway, my error is this "multiple definition of: function-name", I think it's a classic error as some people have experienced it too. It seems to have problem with all the functions in "pong_function.c". I’m also using the Code::Blocks IDE if anyone’s wondering.
In my pong.c file:
#include "pong.h"
int main( int argc, char** argv ) {
auto unsigned int col = 0x00;
paddle[0].x = 575 ;
paddle[0].y = 210 ;
paddle[0].hit = false ;
paddle[1].x = 0 ;
paddle[1].y = 205 ;
paddle[1].hit = false ;
ball.x = WIDTH / 2 ;
ball.y = HEIGHT / 2 ;
ball.speedX = 3;
ball.speedY = 0;
ball.direction = 2 ;
int n ;
init( ) ;
SDL_Window *window = SDL_CreateWindow( "Pong", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, FLAG ) ;
SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED ) ;
load_files( renderer );
get_text( surface, renderer );
bool running = true;
while( running ) {
SDL_Event e;
while( SDL_PollEvent( &e ) ) {
switch( e.type ) {
case SDL_QUIT :
running = false;
break ;
switch( e.key.keysym.sym ) {
case SDL_KEYDOWN:
case SDLK_ESCAPE :
running = false ;
break;
}
default:
running = true;
}
}
input( );
update( );
draw_screen( renderer ) ;
}
surface = NULL; // Just in case
delete_items( window, renderer ) ;
return 0;
}
In my pong.h file:
#ifndef pong_h_
#define pong_h_
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
typedef struct {
float x ;
float y ;
bool hit ;
} Paddle_t ;
typedef struct {
float x, speedX ;
float y , speedY ;
short direction ;
} Ball_t ;
const int WIDTH = 640 ;
const int HEIGHT = 480 ;
const int FLAG = 0 ;
extern unsigned int col ;
int tWidth = 0, tHeight = 0, tX = 0, tY = 0;
SDL_Texture *f_text = NULL ;
SDL_Texture *p_text = NULL ;
SDL_Texture *b_text = NULL ;
SDL_Surface *surface ;
TTF_Font *test;
Paddle_t paddle[ 2 ];
Ball_t ball;
extern void draw_screen( SDL_Renderer *renderer ) ;
extern void update( void ) ;
extern void load_files( SDL_Renderer *renderer ) ;
extern void input( void ) ;
extern void init( void ) ;
extern void get_text( SDL_Surface *surface, SDL_Renderer *renderer ) ;
extern void delete_items( SDL_Window *win, SDL_Renderer* renderer ) ;
#endif // pong_h_
Lastly, in my pong_func.c file:
#include "pong.h"
void draw_screen( SDL_Renderer *renderer ) {
// Clear screen to black colour
SDL_SetRenderDrawColor( renderer, col, col, col, col );
SDL_RenderClear( renderer ) ;
// Paddle (player 1)
SDL_Rect src = { 0, 0, 32*2, 32*2 } ;
SDL_Rect dRect = { paddle[ 0 ].x, paddle[ 0 ].y, 32*2, 32*2 } ;
SDL_RenderCopy( renderer, p_text, &src, &dRect ) ;
// Paddle (player 2)
SDL_Rect src2 = { 0, 0, 32*2, 32*2 } ;
SDL_Rect dRect2 = { paddle[ 1 ].x, paddle[ 1 ].y, 32*2, 32*2 } ;
SDL_RenderCopy( renderer, p_text, &src2, &dRect2 ) ;
// Ball
SDL_Rect bRect = { 0, 0, 32, 32 } ;
SDL_Rect bRect2 = { ball.x, ball.y, 32, 32 } ;
SDL_RenderCopy( renderer, b_text, &bRect, &bRect2 ) ;
// Font
SDL_Rect dstRect = { tX, tY, tWidth, tHeight } ;
SDL_RenderCopy( renderer, f_text, NULL, &dstRect ) ;
SDL_RenderPresent( renderer ) ;
}
void update( void ) {
// Nothing yet...
}
void load_files( SDL_Renderer *renderer ) {
if( ( surface = IMG_Load( "paddle.png" ) ) == NULL ) {
fprintf( stderr, "Unable to load file\n" ) ;
exit(-1);
}
p_text = SDL_CreateTextureFromSurface( renderer, surface ) ;
if( ( surface = IMG_Load( "ball.png" ) ) == NULL ) {
fprintf( stderr, "Unable to load file\n" ) ;
exit( -1 ) ;
}
b_text = SDL_CreateTextureFromSurface( renderer, surface ) ;
}
void input( void ) {
// Input
const Uint8 *state = SDL_GetKeyboardState( NULL ) ;
if( state[SDL_SCANCODE_A] ) paddle[ 0 ].y++;
if( state[SDL_SCANCODE_D] ) paddle[ 0 ].y--;
if( state[SDL_SCANCODE_LEFT] ) paddle[ 1 ].y++;
if( state[SDL_SCANCODE_RIGHT] ) paddle[ 1 ].y--;
}
void init( void ) {
// Init random
srand( time( NULL ) ) ;
// Init TTF
TTF_Init( ) ;
// Init PNG
IMG_Init( IMG_INIT_PNG ) ;
// Init SDL
if( SDL_Init(SDL_INIT_AUDIO) < 0 ) {
fprintf( stderr, "Unable to initialise SDL: %s", SDL_GetError() );
exit( -1 ) ;
}
}
void get_text( SDL_Surface *surface, SDL_Renderer *renderer ) {
const char *string = "Welcome to pong!" ;
SDL_Color clr = { 255, 255, 255 } ;
test = TTF_OpenFont( "slkscr.ttf", 25 ) ;
surface = TTF_RenderText_Solid(test, string, clr);
f_text = SDL_CreateTextureFromSurface(renderer, surface);
SDL_QueryTexture( f_text, NULL, NULL, &tWidth, &tHeight ) ;
}
void delete_items( SDL_Window *win, SDL_Renderer* renderer ) {
// Delete items
SDL_DestroyTexture( f_text ) ;
SDL_DestroyTexture( b_text ) ;
SDL_DestroyTexture( p_text ) ;
TTF_CloseFont( test ) ;
SDL_FreeSurface( surface ) ;
SDL_DestroyWindow( win ) ;
SDL_DestroyRenderer( renderer ) ;
SDL_Quit( );
IMG_Quit( );
TTF_Quit( );
}

Related

Why does this SDL2 program slow down?

I have a problem with this program that reads audio data from an input device and displays a line representing the volume level. It starts ok then a few seconds later it starts lagging. It worked without slow downs until I tried to add some code to add image display functionality, which didn't work so I removed it, but now it the program doesn't work properly. I've removed most of the program functionality which I'll add back if I fix it. The CPU and GPU usage remains low so no problems there. If I switch to Software Mode it seems to work. I'm on Windows using MinGW-w64.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#include <math.h>
int SCREEN_WIDTH = 1024; //default
int SCREEN_HEIGHT = 768; //default
int FULLSCREEN = 0;
SDL_Renderer *rend;
//#define SOFTWARE_RENDER
//#define VSYNC_ON
#define PROGRAM_NAME "My Game"
#ifdef SOFTWARE_RENDER
#define RENDERER SDL_RENDERER_SOFTWARE
#else
#define RENDERER SDL_RENDERER_ACCELERATED
#endif
#if !defined(SOFTWARE_RENDER) && defined(VSYNC_ON)
#define VSYNC SDL_RENDERER_PRESENTVSYNC
#else
#define VSYNC 0
#endif
////https://wiki.libsdl.org/SDL_AudioSpec#callback
void audioInCallback(void *userdata, Uint8 *stream,int len)
{
float *floatStream = (float*)stream;
if (stream == NULL)
{
puts("Stream is NULL.");
return;
}
SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
SDL_RenderClear(rend);
SDL_SetRenderDrawColor(rend, 255, 255, 255, 255);
float avg = 0;
for (int i=0;i<len;i++)
avg += fabs(floatStream[i]);
avg /= len;
SDL_RenderDrawLine(rend, 0,
SCREEN_HEIGHT/2 + round(SCREEN_HEIGHT/2.0 * avg),
SCREEN_WIDTH,
SCREEN_HEIGHT/2 + round(SCREEN_HEIGHT/2.0 * avg)
);
return;
}
int main(int argv, char *argc[])
{
int bufferSize = 8;
SDL_Window* window = NULL;
rend = NULL;
SDL_Event event;
bool loopIsActive = true;
SDL_AudioSpec want, have;
SDL_AudioDeviceID dev;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0)
{
printf("Unable to initialize SDL: %s", SDL_GetError());
return 1;
}
if( (window = SDL_CreateWindow( PROGRAM_NAME, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOW_SHOWN )) == NULL )
{
printf("Window could not be created! %s\n", SDL_GetError());
SDL_Quit();
return 0;
}
if ( (rend = SDL_CreateRenderer(window, -1, RENDERER | VSYNC)) == NULL )
{
printf("Error creating renderer. %s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
int count = SDL_GetNumAudioDevices(1);
for (int i=0;i<count;i++)
{
printf("%d. %s\n", i, SDL_GetAudioDeviceName(i, 1));
}
SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */
want.freq = 44100;
want.format = AUDIO_S16;
want.channels = 1;
want.samples = pow(2,bufferSize);
want.callback = audioInCallback;
dev = SDL_OpenAudioDevice(NULL, 1, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
if (dev == 0)
printf("Failed to open audio: %s", SDL_GetError());
else
{
printf("have.samples = %u\n", have.samples);
printf("Opened device %s\nAudio format: ", SDL_GetAudioDeviceName(0, 1));
if (SDL_AUDIO_ISFLOAT(have.format))
printf("%d-bit %s\n", SDL_AUDIO_BITSIZE(have.format), SDL_AUDIO_ISFLOAT(have.format) ? "float" :
SDL_AUDIO_ISSIGNED(have.format) ? "signed" : "unsigned");
SDL_PauseAudioDevice(dev, 0); /* start audio playing. */
}
while (loopIsActive == true)
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
loopIsActive = false;
break;
case SDL_KEYDOWN:
if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
{
loopIsActive = false;
}
break;
}
}
SDL_RenderPresent(rend);
SDL_Delay(16);
}
if (dev != 0) SDL_CloseAudioDevice(dev);
SDL_DestroyRenderer(rend);
SDL_DestroyWindow(window);
SDL_Quit();
puts("Hello world!");
return 0;
}
Don't try to do SDL_Renderer operations in a different thread like the one the audio callback is typically called from. As #keltar pointed out this is prohibited by SDL:
These functions must be called from the main thread.
Instead, bundle up the audio samples via your favorite method for rendering on the main thread (sorry for the C++, not much of a C guy re: threading primitives):
#include <SDL.h>
#include <vector>
#include <atomic>
#include <iostream>
// triple-buffering logic stol^H^H^H^Hborrowed from:
// https://stackoverflow.com/questions/49352853
std::vector< float >* g_ProducerBuffer;
std::vector< float >* g_ConsumerBuffer;
std::atomic< std::vector< float >* > g_CurrentBuffer;
void audioInCallback( void* userdata, Uint8* stream, int len )
{
const float* floatStream = reinterpret_cast< float* >( stream );
for( auto& sample : *g_ProducerBuffer )
{
sample = *floatStream;
floatStream++;
}
// post new buffer
g_ProducerBuffer = g_CurrentBuffer.exchange( g_ProducerBuffer );
}
int main( int argc, char** argv )
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_SetHint( SDL_HINT_RENDER_VSYNC, "1" );
//SDL_SetHint( SDL_HINT_RENDER_DRIVER, "software" );
Uint32 flags = SDL_WINDOW_SHOWN;
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_CreateWindowAndRenderer( 1024, 768, flags, &window, &renderer );
// dump device names
int count = SDL_GetNumAudioDevices( 1 );
for( int i = 0; i < count; i++ )
{
std::cout << i << ": " << SDL_GetAudioDeviceName( i, 1 ) << '\n';
}
SDL_AudioSpec spec = { 0 };
spec.freq = 44100;
spec.format = AUDIO_F32LSB;
spec.channels = 1;
spec.samples = 1024;
spec.callback = audioInCallback;
const unsigned int deviceIndex = 0;
const std::string deviceName = SDL_GetAudioDeviceName( deviceIndex, 1 );
SDL_AudioDeviceID dev = SDL_OpenAudioDevice( deviceName.c_str(), 1, &spec, nullptr, 0 );
// set up audio buffers
std::vector< float > buffers[ 3 ];
buffers[ 0 ].resize( spec.samples );
buffers[ 1 ].resize( spec.samples );
buffers[ 2 ].resize( spec.samples );
g_ProducerBuffer = &buffers[ 0 ];
g_ConsumerBuffer = &buffers[ 1 ];
g_CurrentBuffer = &buffers[ 2 ];
// start audio capture
SDL_PauseAudioDevice( dev, 0 );
bool running = true;
while( running )
{
SDL_Event ev;
while( running && SDL_PollEvent( &ev ) )
{
if( SDL_QUIT == ev.type ||
SDL_KEYDOWN == ev.type && SDL_SCANCODE_ESCAPE == ev.key.keysym.scancode )
{
running = false;
}
}
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
SDL_RenderClear( renderer );
// grab latest audio buffer
// (this *seems* to work on my system but I'm not 100% sure it's correct)
while( !g_CurrentBuffer.compare_exchange_weak( g_ConsumerBuffer, g_ConsumerBuffer ) );
// draw audio sample waveform
std::vector< SDL_Point > points( g_ConsumerBuffer->size() );
for( size_t i = 0; i < g_ConsumerBuffer->size(); ++i )
{
const int x = static_cast< int >( i );
const int y = static_cast< int >( (*g_ConsumerBuffer)[ i ] * 200 + 768 / 2 );
points[ i ] = SDL_Point{ x, y };
}
SDL_SetRenderDrawColor( renderer, 255, 255, 255, 255 );
SDL_RenderDrawLines( renderer, points.data(), points.size() );
SDL_RenderPresent( renderer );
}
SDL_CloseAudioDevice( dev );
SDL_DestroyRenderer( renderer );
SDL_DestroyWindow( window );
SDL_Quit();
return 0;
}

Pixel Manipulation in SDL2.0

I can not display pixels in SDL 2.0.
#include<SDL2/SDL.h>
#include<stdbool.h>
void end( SDL_Window *Window, SDL_Surface *Surface);
void drawPixel( SDL_Surface *Surface, int x, int y);
void main(){
Uint32 start;
const int FPS = 60;
bool running = true;
SDL_Event event;
SDL_Window *main_window = NULL;
SDL_Surface *main_screen = NULL;
SDL_Init( SDL_INIT_EVERYTHING );
main_window = SDL_CreateWindow("Pixel", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,800,600,
SDL_WINDOW_RESIZABLE);
main_screen = SDL_GetWindowSurface ( main_window );
SDL_UpdateWindowSurface( main_window );
//printf("%d\n",main_screen->pixels);
SDL_FillRect( main_screen, NULL, SDL_MapRGB(main_screen->format, 255, 255, 255));
SDL_UpdateWindowSurface( main_window );
for(int i = 0; i <= 3000; i++ ){
drawPixel( main_screen, i, 0);
//break;
}
// SDL_UpdateWindowSurface( main_window );
while( running ) {
// start = SDL_GetTicks();
while ( SDL_PollEvent( &event ) ){
switch( event.type ){
case SDL_QUIT:
running = false;
break;
}
}
}
end( main_window, main_screen);
}
void end(SDL_Window *Window, SDL_Surface *Surface){
SDL_FreeSurface( Surface );
SDL_DestroyWindow( Window );
}
void drawPixel(SDL_Surface *Surface, int x, int y){
Uint8 *pixel_array = (Uint8 *) Surface->pixels;
Uint8 *pixel = pixel_array + Surface->pitch * y + x;
*pixel = SDL_MapRGB(Surface->format, 0, 0, 0 );
}`
I tried to locate pixel position and try to color the pixel black while background color white, but it does not print anything.
Although I tried to create a line in case i am not unable to see the pixel, but it turned out to be not working. I see only white screen.

Rendering in a small section of my window

I am currently working with SDL2. I am on Mac OS and I'm using xCode.
I have created a function to draw lines using randomly generated points.
However, when I try to render the lines, they are only render in a subset of my window (top left square).
Here's my code.
main.c
#include <SDL2/SDL.h>
#include "utils.h"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
// Prototypes
void drawRandomPoints( int pointsNo, SDL_Renderer *renderer );
void drawRandomLines( int linesNo, SDL_Renderer *renderer );
int main( int argc, const char * argv[] ) {
SDL_Init( SDL_INIT_VIDEO );
SDL_Window *window = SDL_CreateWindow( "Hello World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL );
SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
int running = 1;
SDL_Event event;
while( running ) {
while( SDL_PollEvent( &event ) ) {
if( event.type == SDL_QUIT ) {
running = 0;
}
}
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
SDL_RenderClear( renderer );
// Draw a point
SDL_SetRenderDrawColor( renderer, 255, 0, 0, 255 );
drawRandomLines( 100, renderer );
SDL_RenderPresent( renderer );
}
SDL_DestroyRenderer( renderer );
SDL_DestroyWindow( window );
SDL_Quit();
return 0;
}
void drawRandomPoints( int pointsNo, SDL_Renderer *renderer ) {
int i = 0;
for( i = 0; i < pointsNo; ++i ) {
SDL_SetRenderDrawColor( renderer, getRandomColor(), getRandomColor(), getRandomColor(), 255 );
SDL_RenderDrawPoint( renderer, getRandomNumber( 0, SCREEN_WIDTH ), getRandomNumber( 0, SCREEN_HEIGHT ) );
}
}
void drawRandomLines( int linesNo, SDL_Renderer *renderer ) {
int i = 0;
for( i = 0; i < linesNo; ++i ) {
SDL_SetRenderDrawColor( renderer, getRandomColor(), getRandomColor(), getRandomColor(), 255 );
SDL_RenderDrawLine( renderer, getRandomNumber( 0, SCREEN_WIDTH ), getRandomNumber( 0, SCREEN_HEIGHT ), getRandomNumber( 0, SCREEN_WIDTH ), getRandomNumber( 0, SCREEN_HEIGHT ) );
}
}
utils.c
#include "utils.h"
#include <stdlib.h>
#include <time.h>
int getRandomNumber( int min, int max ) {
static int init = 0;
if( !init ) {
srand( time( NULL ) );
init = 1;
}
return ( rand() % ( max - min + 1 ) ) + min;
}
int getRandomColor() {
return getRandomNumber( 0, 255 );
}
Here's the result when compiling.
SDL window
You're only using a VGA size screen by defining these;
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
Try this
int SCREEN_WIDTH=640;
int SCREEN_HEIGHT=480;
and add to main like this;
SDL_Window *window = SDL_CreateWindow( "Hello World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL );
SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
SDL_GL_GetDrawableSize(window,&SCREEN_WIDTH,&SCREEN_HEIGHT);

Rotating and compositing PNG files using Cairo with C

I am writing an application using Cairo in C that does the following:
Load background PNG (wheel)
rotate wheel 90 degrees
draw on wheel a set of numbers from other PNG files
do this until all 6 parts of the wheel have the numbers drawn on the wheel
save the PNG to a file ( results.png )
The problem I'm having is if I don't rotate the wheel, the numbers are drawn properly as seen in this image, except the wheel isn't rotated as needed.
However, if I attempt to rotate AND draw the numbers on the wheel I get a rotated wheel with no numbers as seen in this image.
I've tried various permutations of the code, but I can't seem to make it work. I would appreciate some hints and / or sample code that shows what I'm doing wrong. I've checked the Cairo documentation to no avail.
The code can be found here.
And here:
#include <cairo.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
typedef struct
{
int numImages; /* Number of images in win amount string */
int indexes[7]; /* indexes into NumberImages[] */
}WinAmountData;
/***** Function Prototypes *****************/
int InitImages( void );
void DestroyNumberImages( void );
int ParseWinAmountString( char *string, WinAmountData *amtData );
int Rotate( cairo_t *cr , cairo_surface_t *image, double degrees );
/*******************************************/
typedef struct
{
int xOffset; /* pixel count offsete before next digit */
char fileName[20];
cairo_surface_t *image;
}ImageInfo;
ImageInfo NumberImages[] =
{
{ 8, "images/0.png", NULL },
{ 10, "images/1.png", NULL },
{ 10, "images/2.png", NULL },
{ 10, "images/3.png", NULL },
{ 10, "images/4.png", NULL },
{ 10, "images/5.png", NULL },
{ 10, "images/6.png", NULL },
{ 10, "images/7.png", NULL },
{ 10, "images/8.png", NULL },
{ 10, "images/9.png", NULL },
{ 7, "images/$.png", NULL },
{ 10, "images/euro.png", NULL },
{ 7, "images/pound.png", NULL },
{ 7, "images/yen.png", NULL }
};
enum { DOLLAR = 10, EURO, POUND, YEN };
#define FALSE 0
#define TRUE 1
int InitImages( void )
{
int i;
int ret = TRUE;
cairo_status_t imgStatus;
for( i = 0; i < ( sizeof( NumberImages ) / sizeof( ImageInfo ) ) && ret == TRUE; i++ )
{
NumberImages[i].image = cairo_image_surface_create_from_png( NumberImages[i].fileName );
imgStatus = cairo_surface_status(NumberImages[i].image);
ret = ( CAIRO_STATUS_SUCCESS == imgStatus );
}
return( ret );
}
void DestroyNumberImages( void )
{
int i;
for( i = 0; i < ( sizeof( NumberImages ) / sizeof( ImageInfo ) ); i++ )
{
cairo_surface_destroy(NumberImages[i].image);
}
return;
}
int ParseWinAmountString( char *string, WinAmountData *amtData )
{
int ret = TRUE;
int i = 0, len;
len = strlen( string );
if( (len > 0) && (len < 8) )
{
amtData->numImages = len;
for( i = 0; i < amtData->numImages && TRUE == ret; i++ )
{
if( string[i] >= '0' && string[i] <= '9' )
{
amtData->indexes[i] = string[i] - '0';
}
else
{
switch( string[i] )
{
case 'D':
amtData->indexes[i] = DOLLAR;
break;
case 'Y':
amtData->indexes[i] = YEN;
break;
case 'E':
amtData->indexes[i] = EURO;
break;
case 'P':
amtData->indexes[i] = POUND;
break;
default:
ret = FALSE;
break;
}
}
}
}
else
{
ret = FALSE;
}
return( ret );
}
double DegreesToRadians( double degrees )
{
return((double)((double)degrees * ( (double)M_PI/(double)180.0 )));
}
int Rotate( cairo_t *cr , cairo_surface_t *image, double degrees )
{
int ret = 0;
cairo_translate(cr, 90, 90);
cairo_rotate(cr, DegreesToRadians( degrees ));
cairo_set_source_surface(cr, image, -90, -90);
cairo_paint(cr);
return ( ret );
}
int main(int argc, char *argv[])
{
int i,x,y;
cairo_surface_t *imgWheelBg = NULL;
WinAmountData amtData;
if( argc == 2 )
{
printf("Parsing [%s]\n", argv[1]);
if ( ParseWinAmountString( argv[1], &amtData ) == TRUE )
{
printf("Amount indexes = [ ");
for( i = 0; i < amtData.numImages; i++ )
{
printf("%d ", amtData.indexes[i]);
}
printf("]\n");
}
else
{
printf("Failed to parse amount.\n");
return( 1 );
}
}
else
{
printf("Usage: %s <Amount String>\n", argv[0]);
return( 1 );
}
if( InitImages() == TRUE )
{
imgWheelBg = cairo_image_surface_create_from_png("images/blankwheel.png");
//Create the background image
cairo_surface_t *imgResult = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 180, 180);
//Create the cairo context
cairo_t *cr = cairo_create(imgResult);
//Paint empty wheel image
cairo_set_source_surface(cr, imgWheelBg, 0, 0);
cairo_paint(cr);
// At this point the wheel is painted ( blankwheel.png )
// vvvvvvvvvv THIS PART SEEMS TO BE CAUSING TROUBLES vvvvvvvvvv
// With this call the wheel DOES get rotated 90 degress. Confirmed
// by viewing the resulting PNG file.
// HOWEVER, after the Rotate() is called the numbers aren't put on the wheel.
// if I remove the Rotate() call, the wheel is drawn, not rotated, but the
// numbers are properly composited over the image.
//Rotate( cr, imgWheelBg, 90 );
// ^^^^^^^^^^^ THIS PART SEEMS TO BE CAUSING TROUBLES ^^^^^^^^^^^
/* Set drawing begin point in pixels */
x = 101;
y = 82;
/* Draw all characters in win amount string */
for( i = 0; i < amtData.numImages; i++ )
{
cairo_set_source_surface(cr, NumberImages[amtData.indexes[i]].image, x, y);
cairo_paint(cr);
x += NumberImages[i].xOffset;
}
//Destroy the cairo context and/or flush the destination image
cairo_surface_flush(imgResult);
cairo_destroy(cr);
//And write the results into a new file
cairo_surface_write_to_png(imgResult, "result.png");
// Destroy resources
cairo_surface_destroy(imgResult);
cairo_surface_destroy(imgWheelBg);
DestroyNumberImages();
printf("SUCCESS\n");
}
else
{
printf("FAILED Init Images\n");
}
return 0;
}
EDIT: The ultimate goal is to generate an image like this one programmatically and the animate it as needed in real time within a GTK application.
EDIT: With the comments from Mikhail Kozhevnikov and Uli Schlachter I was able to find a solution using this code.
Thank you very much!
I think the problem is that the transformation is applied to everything, including the number images, and they get drawn somewhere outside the picture because of this transformation. I'd suggest that the matrix be stored before applying the transformation and restored after the circle is drawn. Or would you like the numbers to rotate too?..

How to use a RichEdit control like a console with the Win32 API?

I have a RichEdit control in my simple application that I wish to simulate a console-like display with. I want to be able to have a buffer of x number of lines (say, 300) and whenever a line is added, I would like to also remove the oldest (top) line if the new line exceeded the threshold x. I would also like it to automatically scroll to the bottom to display the newest line when added.
I've been using SetWindowText with some success, however it occurs to me that there is likely a more efficient method of appending text to the end and removing text from the beginning without having to replace all of it every time. Is this true, and, if so, how might I go about it?
Also, how might I make it automatically scroll to the bottom of the window when new text is added?
This is using the Win32 API from C, and I'm not using the MFC version of RichEdit (just using the vanilla Win32 API on XP and Vista).
To add text, you set the selection to the end of the text (EM_SETSEL), then replace the selection with the new text (EM_REPLACESEL).
To scroll to the bottom, you can send it a WM_VSCROLL with SB_BOTTOM.
I send you some methods of sample class cConsole:
class cConsole {
private:
//-------------------
int lines;
int max_lines; // Init it with your choise ( 300 )
//-------------------
char* buf;
int buf_size;
//-------------------
int CheckMemory( int size );
void NewLine( int new_lines );
void InternalPrint( char* msg, int size );
public:
HWND hWin;
void Print( char* msg ); // Add text data through this methods
void Print( char* msg, int size );
cConsole( );
~cConsole( );
};
int cConsole::CheckMemory( int size ) {
int rv = 1;
if( size + 16 >= buf_size ) {
int new_buf_size = size + 1024;
char* new_buf = ( char* )realloc( buf, new_buf_size );
if( new_buf != NULL ) {
buf = new_buf;
buf_size = new_buf_size;
} else {
rv = 0;
}
}
return rv;
}
void cConsole::NewLine( int new_lines ) {
int rem_lines = ( new_lines + lines + 1 ) - max_lines;
if( rem_lines <= 0 ) {
lines += new_lines;
} else {
int sel = SendMessage( hWin, EM_LINEINDEX, rem_lines, 0 );
SendMessage( hWin, EM_SETSEL, 0, (LPARAM)sel );
SendMessage( hWin, EM_REPLACESEL, FALSE, (LPARAM)"" );
SendMessage( hWin, WM_VSCROLL, SB_BOTTOM, NULL );
lines = max_lines - 1;
}
}
void cConsole::Print( char* msg ) { InternalPrint( msg, -1 ); }
void cConsole::Print( char* msg, int size ) { if( size < 0 ) size = 0; InternalPrint( msg, size ); }
void cConsole::InternalPrint( char* msg, int size ) {
int s, t = 0;
int new_lines = 0;
char* tb;
// msg only mode
if( size == -1 ) size = 0x7fffffff;
if( msg != NULL && size && CheckMemory( t ) ) {
for( s = 0; msg[ s ] && ( s < size ); s++ ) {
if( msg[ s ] == '\r' ) continue;
if( !CheckMemory( t ) ) break;
if( msg[ s ] == '\n' ) {
++new_lines;
buf[ t++ ] = '\r';
}
buf[ t++ ] = msg[ s ];
}
buf[ t ] = '\0';
}
if( t && msg != NULL ) {
tb = buf;
} else {
++new_lines;
tb = "\r\n";
}
SendMessage( hWin, EM_SETSEL, (WPARAM)-2, (LPARAM)-1 );
SendMessage( hWin, EM_REPLACESEL, FALSE, (LPARAM)tb );
SendMessage( hWin, WM_VSCROLL, SB_BOTTOM, NULL );
if( new_lines ) NewLine( new_lines );
}
Built your own class and check this!

Resources