src/main.c

changeset 41
75887b42d7e5
parent 40
239bc48590ba
child 42
1d55c8c7c1ac
     1.1 --- a/src/main.c	Thu Dec 02 23:03:13 2010 +0000
     1.2 +++ b/src/main.c	Thu Dec 02 23:30:13 2010 +0000
     1.3 @@ -19,6 +19,99 @@
     1.4  	exit(EXIT_FAILURE);
     1.5  }
     1.6  
     1.7 +/**
     1.8 + * @brief Set the pixel at (x, y) to the given value
     1.9 + * @note The surface must be locked before calling this!
    1.10 + * @param	surface		SDL surface upon which to draw
    1.11 + * @param	x			X co-ordinate
    1.12 + * @param	y			Y co-ordinate
    1.13 + * @param	pixel		Pixel value (from SDL_MapRGB)
    1.14 + */
    1.15 +void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
    1.16 +{
    1.17 +	int bpp = surface->format->BytesPerPixel;
    1.18 +	/* Here p is the address to the pixel we want to set */
    1.19 +	Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
    1.20 +
    1.21 +	switch (bpp) {
    1.22 +		case 1:
    1.23 +			*p = pixel;
    1.24 +			break;
    1.25 +
    1.26 +		case 2:
    1.27 +			*(Uint16 *)p = pixel;
    1.28 +			break;
    1.29 +
    1.30 +		case 3:
    1.31 +			if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
    1.32 +				p[0] = (pixel >> 16) & 0xff;
    1.33 +				p[1] = (pixel >> 8) & 0xff;
    1.34 +				p[2] = pixel & 0xff;
    1.35 +			}
    1.36 +			else {
    1.37 +				p[0] = pixel & 0xff;
    1.38 +				p[1] = (pixel >> 8) & 0xff;
    1.39 +				p[2] = (pixel >> 16) & 0xff;
    1.40 +			}
    1.41 +			break;
    1.42 +
    1.43 +		case 4:
    1.44 +			*(Uint32 *)p = pixel;
    1.45 +			break;
    1.46 +
    1.47 +		default:
    1.48 +			break;           /* shouldn't happen, but avoids warnings */
    1.49 +	} // switch
    1.50 +}
    1.51 +
    1.52 +
    1.53 +/**
    1.54 + * @brief	Refresh the screen.
    1.55 + * @param	surface		SDL surface upon which to draw.
    1.56 + */
    1.57 +void refreshScreen(SDL_Surface *s)
    1.58 +{
    1.59 +	// Lock the screen surface (if necessary)
    1.60 +	if (SDL_MUSTLOCK(s)) {
    1.61 +		if (SDL_LockSurface(s) < 0) {
    1.62 +			fprintf(stderr, "ERROR: Unable to lock screen!\n");
    1.63 +			exit(EXIT_FAILURE);
    1.64 +		}
    1.65 +	}
    1.66 +
    1.67 +	// Map the foreground and background colours
    1.68 +	Uint32 fg = SDL_MapRGB(s->format, 0, 255, 0);	// green foreground
    1.69 +	Uint32 bg = SDL_MapRGB(s->format, 0, 0, 0);		// black background
    1.70 +
    1.71 +	// Refresh the 3B1 screen area first. TODO: only do this if VRAM has actually changed!
    1.72 +	uint32_t vram_address = 0;
    1.73 +	for (int y=0; y<348; y++) {
    1.74 +		for (int x=0; x<720; x+=16) {	// 720 pixels, monochrome, packed into 16bit words
    1.75 +			// Get the pixel
    1.76 +			uint16_t val = RD16(state.vram, vram_address, sizeof(state.vram)-1);
    1.77 +			vram_address += 2;
    1.78 +			// Now copy it to the video buffer
    1.79 +			for (int px=0; px<16; px++) {
    1.80 +				if (val & 1)
    1.81 +					putpixel(s, x+px, y, fg);
    1.82 +				else
    1.83 +					putpixel(s, x+px, y, bg);
    1.84 +			}
    1.85 +		}
    1.86 +	}
    1.87 +
    1.88 +	// TODO: blit LEDs and status info
    1.89 +
    1.90 +	// Unlock the screen surface
    1.91 +	if (SDL_MUSTLOCK(s)) {
    1.92 +		SDL_UnlockSurface(s);
    1.93 +	}
    1.94 +
    1.95 +	// Trigger a refresh -- TODO: partial refresh depending on whether we
    1.96 +	// refreshed the screen area, status area, both, or none. Use SDL_UpdateRect() for this.
    1.97 +	SDL_Flip(s);
    1.98 +}
    1.99 +
   1.100  /****************************
   1.101   * blessed be thy main()...
   1.102   ****************************/
   1.103 @@ -80,7 +173,8 @@
   1.104  
   1.105  		// Is it time to run the 60Hz periodic interrupt yet?
   1.106  		if (clock_cycles > CLOCKS_PER_60HZ) {
   1.107 -			// TODO: refresh screen
   1.108 +			// Refresh the screen
   1.109 +			refreshScreen(screen);
   1.110  			// TODO: trigger periodic interrupt (if enabled)
   1.111  			// decrement clock cycle counter, we've handled the intr.
   1.112  			clock_cycles -= CLOCKS_PER_60HZ;