I have been reading CUDA by Example by Jason Sanders and Edward Kandrot and have come across chapter 4 where they solve Julia Set using CUDA.
Also, there is a source code available on a books page; https://developer.nvidia.com/content/cuda-example-introduction-general-purpose-gpu-programming-0
When I try to include all the files necessary for the project (all header files and .cu ones) it won't compile.
My usual CUDA projects that I create from scratch work without problems (VS 2010, CUDA 5.0).
Did anyone had the same problem and can you please specify each step in order to make this Julia Set set up as it should be?
P.S. Here is a code that won't work in header file:
/*
* Copyright 1993-2010 NVIDIA Corporation. All rights reserved.
*
* NVIDIA Corporation and its licensors retain all intellectual property and
* proprietary rights in and to this software and related documentation.
* Any use, reproduction, disclosure, or distribution of this software
* and related documentation without an express license agreement from
* NVIDIA Corporation is strictly prohibited.
*
* Please refer to the applicable NVIDIA end user license agreement (EULA)
* associated with this source code for terms and conditions that govern
* your use of this NVIDIA software.
*
*/
#ifndef __GPU_ANIM_H__
#define __GPU_ANIM_H__
#include "gl_helper.h"
#include "cuda.h"
#include "cuda_gl_interop.h"
#include <iostream>
PFNGLBINDBUFFERARBPROC glBindBuffer = NULL;
PFNGLDELETEBUFFERSARBPROC glDeleteBuffers = NULL;
PFNGLGENBUFFERSARBPROC glGenBuffers = NULL;
PFNGLBUFFERDATAARBPROC glBufferData = NULL;
struct GPUAnimBitmap {
GLuint bufferObj;
cudaGraphicsResource *resource;
int width, height;
void *dataBlock;
void (*fAnim)(uchar4*,void*,int);
void (*animExit)(void*);
void (*clickDrag)(void*,int,int,int,int);
int dragStartX, dragStartY;
GPUAnimBitmap( int w, int h, void *d = NULL ) {
width = w;
height = h;
dataBlock = d;
clickDrag = NULL;
// first, find a CUDA device and set it to graphic interop
cudaDeviceProp prop;
int dev;
memset( &prop, 0, sizeof( cudaDeviceProp ) );
prop.major = 1;
prop.minor = 0;
HANDLE_ERROR( cudaChooseDevice( &dev, &prop ) );
cudaGLSetGLDevice( dev );
// a bug in the Windows GLUT implementation prevents us from
// passing zero arguments to glutInit()
int c=1;
char* dummy = "";
glutInit( &c, &dummy );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA );
glutInitWindowSize( width, height );
glutCreateWindow( "bitmap" );
glBindBuffer = (PFNGLBINDBUFFERARBPROC)GET_PROC_ADDRESS("glBindBuffer");
glDeleteBuffers = (PFNGLDELETEBUFFERSARBPROC)GET_PROC_ADDRESS("glDeleteBuffers");
glGenBuffers = (PFNGLGENBUFFERSARBPROC)GET_PROC_ADDRESS("glGenBuffers");
glBufferData = (PFNGLBUFFERDATAARBPROC)GET_PROC_ADDRESS("glBufferData");
glGenBuffers( 1, &bufferObj );
glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, bufferObj );
glBufferData( GL_PIXEL_UNPACK_BUFFER_ARB, width * height * 4,
NULL, GL_DYNAMIC_DRAW_ARB );
HANDLE_ERROR( cudaGraphicsGLRegisterBuffer( &resource, bufferObj, cudaGraphicsMapFlagsNone ) );
}
~GPUAnimBitmap() {
free_resources();
}
void free_resources( void ) {
HANDLE_ERROR( cudaGraphicsUnregisterResource( resource ) );
glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
glDeleteBuffers( 1, &bufferObj );
}
long image_size( void ) const { return width * height * 4; }
void click_drag( void (*f)(void*,int,int,int,int)) {
clickDrag = f;
}
void anim_and_exit( void (*f)(uchar4*,void*,int), void(*e)(void*) ) {
GPUAnimBitmap** bitmap = get_bitmap_ptr();
*bitmap = this;
fAnim = f;
animExit = e;
glutKeyboardFunc( Key );
glutDisplayFunc( Draw );
if (clickDrag != NULL)
glutMouseFunc( mouse_func );
glutIdleFunc( idle_func );
glutMainLoop();
}
// static method used for glut callbacks
static GPUAnimBitmap** get_bitmap_ptr( void ) {
static GPUAnimBitmap* gBitmap;
return &gBitmap;
}
// static method used for glut callbacks
static void mouse_func( int button, int state,
int mx, int my ) {
if (button == GLUT_LEFT_BUTTON) {
GPUAnimBitmap* bitmap = *(get_bitmap_ptr());
if (state == GLUT_DOWN) {
bitmap->dragStartX = mx;
bitmap->dragStartY = my;
} else if (state == GLUT_UP) {
bitmap->clickDrag( bitmap->dataBlock,
bitmap->dragStartX,
bitmap->dragStartY,
mx, my );
}
}
}
// static method used for glut callbacks
static void idle_func( void ) {
static int ticks = 1;
GPUAnimBitmap* bitmap = *(get_bitmap_ptr());
uchar4* devPtr;
size_t size;
HANDLE_ERROR( cudaGraphicsMapResources( 1, &(bitmap->resource), NULL ) );
HANDLE_ERROR( cudaGraphicsResourceGetMappedPointer( (void**)&devPtr, &size, bitmap->resource) );
bitmap->fAnim( devPtr, bitmap->dataBlock, ticks++ );
HANDLE_ERROR( cudaGraphicsUnmapResources( 1, &(bitmap->resource), NULL ) );
glutPostRedisplay();
}
// static method used for glut callbacks
static void Key(unsigned char key, int x, int y) {
switch (key) {
case 27:
GPUAnimBitmap* bitmap = *(get_bitmap_ptr());
if (bitmap->animExit)
bitmap->animExit( bitmap->dataBlock );
bitmap->free_resources();
exit(0);
}
}
// static method used for glut callbacks
static void Draw( void ) {
GPUAnimBitmap* bitmap = *(get_bitmap_ptr());
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
glDrawPixels( bitmap->width, bitmap->height, GL_RGBA,
GL_UNSIGNED_BYTE, 0 );
glutSwapBuffers();
}
};
#endif // __GPU_ANIM_H__
Line that is making a first error is :
PFNGLBINDBUFFERARBPROC glBindBuffer = NULL;
VS says: IntelliSense: PCH warning: header stop cannot be in a macro or #if block. An intellisense PCH file was not generated.
thank you very much
to run it properly you have to first download the source codes from :`CUDA by Example source code
then extract it. when you create your project in visual studio, if it is 2010 and newer you should go to the project properties and go to VC++ Directories and add the extracted folder as an include path. also add the lib folder as library path and the bin as the executable path.
then you can add a new cu file to your project and copy the content of the chapter 4 folder -which ever file you want from that- and paste it there and compile it.
if still it doesn't compile, you should go to project properties -> linker and find the "Additional Dependency" and add cudart.lib and you are all set.
also pay attention that the include phrases in the books code are like this: /.../common/book.h , you should change them to common/book.h format.
Related
I keep getting the error "func.h:23: error: cannot cast 'int' to 'struct Texture'" even though im inputting text as tile in renderTiles(). Am i just being dumb here? ¯_(ツ)_/¯ Im new to C so this might just be me. i copied and pasted the basic window example to create this. i know there isnt char before tile in "renderTiles(tile)" i tried that as well and it still did not work
main.c:
*
* raylib [core] example - Basic window
*
* Welcome to raylib!
*
* To test examples, just press F6 and execute raylib_compile_execute script
* Note that compiled executable is placed in the same folder as .c file
*
* You can find all basic examples on C:\raylib\raylib\examples folder or
* raylib official webpage: www.raylib.com
*
* Enjoy using raylib. :)
*
* Example originally created with raylib 1.0, last time updated with raylib 1.0
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2013-2022 Ramon Santamaria (#raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include "func.h"
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 768;
const int screenHeight = 576;
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// textures
Texture2D grass = LoadTexture("grass.png");
Texture2D stone = LoadTexture("stone.png");
Texture2D sand = LoadTexture("sand.png");
Texture2D stone_oasis = LoadTexture("stone-oasis.png");
Texture2D sand_oasis = LoadTexture("sand-oasis.png");
Texture2D UI = LoadTexture("ui.png");
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
DrawTexture(UI, 0, 0, RAYWHITE);
renderTiles("grass");
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
}
func.h
#ifndef FUNC
#define FUNC
const int screenWidth = 768;
const int screenHeight = 576;
int centerX(int x)
{
int ox = x + (screenWidth / 2);
return (ox);
}
int centerY(int y)
{
int oy = y + (screenHeight / 2);
return(oy);
}
void renderTiles(tile)
{
for( int b = 0; b < 12; b = b + 1)
{
for( int a = 0; a < 12; a = a + 1 ){
DrawTexture(tile, (a * 48) + 96, (b * 48), RAYWHITE);
}
}
}
#endif
Answering the question title, you have already converted the string to a texture struct with
Texture2D grass = LoadTexture("grass.png");
The raylib cheat sheet shows the function you are calling to be
void DrawTexture(Texture2D texture, int posX, int posY, Color tint);
but you have passed the char* value "grass" to your function, which has an untyped argument, so the compiler assumes it to be type int.
Your function should be
/* void renderTiles(tile) */
void renderTiles(Texture2D tile)
and you should call it with
/* renderTiles("grass"); */
renderTiles(grass);
Also, you should not have executable code in a header file.
This is the code i have., which will detect the faces in the image and draws rectangle around the face.
CvHaarClassifierCascade *cascade;
CvMemStorage *storage;
void detectFaces (IplImage *newframe);
int key;
int iImg;
int Num_Images=20;
int main( int argc, char** argv )
{
string filename = M:/Trend/FaceDetection/MyCascadeFolder/haarcascade_frontalface_alt2.xml";
storage = cvCreateMemStorage(0) ;
cascade = ( CvHaarClassifierCascade* )cvLoad( filename.c_str());
**//to load a single image**
**IplImage* inImage = cvLoadImage("M:/Trend/FaceDetection775/MyImages/face1.jpg",1);**
//IplImage* inImage = cvLoadImage(argv[1],1); >> It also works fine through command line
detectFaces( inImage );
cvShowImage("FaceDetection2",inImage);
cvSaveImage("M:/FaceDetection/MyImages/OpImages/faces.jpg",inImage);
cvReleaseImage( &inImage);
// **to load no. of images or a complete folder**
char buf[20];
for(iImg=0; iImg<=Num_Images; iImg++)
{
**sprintf(buf, "M:/FaceDetection/ImagesFolder/P%04d.jpg", iImg);**
*// sprintf(buf, argv[2], iImg); // I Tried with this., but its not working*
printf("\n");
inImage = cvLoadImage(buf, CV_LOAD_IMAGE_UNCHANGED);
printf("Input Image = P%04d.jpg\n", iImg);
detectFaces( inImage );
cvShowImage("FaceDetection",inImage);
cvReleaseImage( &inImage );
key= cvWaitKey(0);
if ( key == 'q' || key == 'Q' )
return(0);
}
cvReleaseHaarClassifierCascade( &cascade );
cvReleaseMemStorage( &storage );
return 0;
}
**// the actual detectfaces() function goes like this**
void detectFaces( IplImage *newframe)
{
CvSeq *faces = cvHaarDetectObjects( newframe, cascade, storage, 1.15, 5, 0, cvSize( 30, 30 ) );
for( int i = 0 ; i < ( faces ? faces->total : 0 ) ; i++ )
{
CvRect *r = ( CvRect *)cvGetSeqElem( faces, i );
cvRectangle(newframe,cvPoint( r->x, r->y ),cvPoint( r->x + r->width, r->y + r->height ),CV_RGB( 0, 255, 0 ), 2, 8, 0 );
}
}
Here., sprintf() method is taking multiple images statically (within the program itself). But I want to pass those multiple images as a single folder through command line argument.
I try to use cvLoadImage() function, but it also takes only one image as input instead of a folder.
Also I am not able to count the number of rectangles it draws for every single face in the image., how can I do that also...?
Please help me in this regards.
I am working on face detection project "www.MahdiRezaei.com" for my academics., and I am using visual studio-2010 with C, C++ and OpenCV.
Thankz in advance.
You can change the following code to use it with arguments.
#include<Windows.h>
#include<iostream>
#include<opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;
int main()
{
WIN32_FIND_DATA data;
HANDLE h = FindFirstFile(L"c:\\Images\\*.*", &data); // first file is the current directory
FindNextFile(h, &data); //second file is the parent directory
vector<Mat> Images;
if (h != INVALID_HANDLE_VALUE)
{
while (FindNextFile(h, &data))
{
string filename = data.cFileName;
sprintf(filename, "%s%s","C:\\Images\\", filename.c_str());
Images.push_back(imread(filename, 1));
delete[] nPtr;
}
}
else
cout << "Error: No such folder." << endl;
FindClose(h);
return 0;
}
I am trying to detect the face in the image and trying to save the detected face as an image in OpenCV.
Having some problems in the detectfaces function below.
#include "stdafx.h"
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
CvHaarClassifierCascade *cascade;
CvMemStorage *storage;
void detectFaces( IplImage *img );
int _tmain(int argc, _TCHAR* argv[])
{
//CvCapture *capture;
IplImage *img;//*out;
int key = 0;
char *filename = "C:/OpenCV2.1/data/haarcascades/haarcascade_frontalface_alt.xml";
cascade = ( CvHaarClassifierCascade* )cvLoad( filename, 0, 0, 0 );
storage = cvCreateMemStorage( 0 );
img = cvLoadImage("Yurico.png");
assert( cascade && storage && img );
cvNamedWindow( "video:", 1 );
//cvNamedWindow( "video1:", 1 );
//out = detectFaces( img );
detectFaces( img );
cvWaitKey( 0 );
//cvShowImage( "video", out );
cvDestroyWindow( "video:" );
//cvDestroyWindow( "video1:" );
cvReleaseImage( &img );
cvReleaseHaarClassifierCascade( &cascade );
cvReleaseMemStorage( &storage );
return 0;
}
void detectFaces( IplImage *img )
{
int i;
CvRect *r;
CvSeq *faces = cvHaarDetectObjects(
img,
cascade,
storage,
1.1,
3,
0 /*CV_HAAR_DO_CANNY_PRUNNING*/,
cvSize( 40, 40) );
for( i = 0 ; i < ( faces ? faces->total : 0 ) ; i++ ) {
CvRect *r = ( CvRect* )cvGetSeqElem( faces, i );
cvRectangle( img,
cvPoint( r->x, r->y ),
cvPoint( r->x + r->width, r->y + r->height ),
CV_RGB( 255, 0, 0 ), 1, 8, 0 );
}
//cvShowImage( "video:", img );
cvSetImageROI(img, CvRect *r);
IplImage *img2 = cvCreateImage(cvGetSize(img),
img->depth,
img->nChannels);
cvSaveImage("Lakshmen.jpg",img2);
}
Have a error saying this :
Error 1 error C2664: 'cvSetImageROI' : cannot convert parameter 2 from 'CvRect *' to 'CvRect' c:\users\hp\documents\visual studio 2010\projects\facedetect\facedetect\facedetect.cpp 67 1 facedetect
Want to save the region of interest into another image. Any corrections or improvements do tell me..
you need to pass a CvRect and not a CvRect*, so you do not need the pointer (*) before r.
and since it is already a cvRect you should just write:
cvSetImageROI(img, &r);
cvSetImageROI() takes a cvRect as the 2nd argument, and it uses it as input parameter to clip the image to that area.
In other words, you need to create a cvRect with valid info. You can do it before calling the function, or inline:
cvSetImageROI(img_corr, cvRect(x_pos, y_pos, width, height));
I also noticed that in your code, you create CvRect* r; on at least 3 diferent locations inside the same function. Bad practice! Tip: create variables in your code at the moment you are going to use them, not before that.
Just replace the CvRect *r as r=(CvRect*)cvGetSeqElem( faces,i) and after the for-loop write the two lines
cvSetImageROI(img, cvRect(r->x,r->y,r->width,r->height));
cvSaveImage("C1.jpg",img);
I'm trying to run simple code with installed OpenCV library
And have an error: The application was unable to start correctly (0xc0150002).
visual studio 2010
OpenCV 2.1.0
I've searched everywhere but cant find how to solve this problem...
This is my code. What can I do?
#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#ifdef _EiC
#define WIN32
#endif
static CvMemStorage* storage_face = 0; //Memory Storage to Sore faces
static CvHaarClassifierCascade* cascade_face = 0;
void detect_and_draw( IplImage* image );
//Haar cascade - if your openc CV is installed at location C:/OpenCV2.0/
const char* cascade_name_face ="C:/OpenCV2.0/data/haarcascades/haarcascade_frontalface_alt.xml";
/////////////////////////////////////////////////////////////////////////////////
int main()
{
IplImage *image =0;
image = cvLoadImage("picci.jpg",1);
if(!image)
{
printf("Error loading image\n");
return -1;
}
cascade_face = (CvHaarClassifierCascade*)cvLoad( cascade_name_face, 0, 0, 0 );
if( !cascade_face )
{
printf("ERROR: Could not load classifier of face cascade\n" );
return -1;
}
storage_face = cvCreateMemStorage(0);
cvNamedWindow( "result", 1 );
// Call function to detect and Draw rectagle around face
detect_and_draw( image);
// Wait for key event.
cvWaitKey(0);
// release resourses
cvReleaseImage( &image );
cvReleaseHaarClassifierCascade(&cascade_face );
cvReleaseMemStorage( &storage_face);
cvDestroyWindow("result");
return 0;
}
//////////////////////////// Function To detect face //////////////////////////
void detect_and_draw( IplImage* img )
{
double scale = 2;
// create a gray image for the input image
IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
// Scale down the ie. make it small. This will increase the detection speed
IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),cvRound (img->height/scale)),8, 1 );
int i;
cvCvtColor( img, gray, CV_BGR2GRAY );
cvResize( gray, small_img, CV_INTER_LINEAR );
// Equalise contrast by eqalizing histogram of image
cvEqualizeHist( small_img, small_img );
cvClearMemStorage( storage_face);
if( cascade_face )
{
// Detect object defined in Haar cascade. IN our case it is face
CvSeq* faces = cvHaarDetectObjects( small_img, cascade_face, storage_face,
1.1, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/,
cvSize(30, 30) );
// Draw a rectagle around all detected face
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect r = *(CvRect*)cvGetSeqElem( faces, i );
cvRectangle( img, cvPoint(r.x*scale,r.y*scale),cvPoint((r.x+r.width)*scale,(r.y+r.height)*scale),CV_RGB(255,0,0),3,8,0 );
}
}
cvShowImage( "result", img );
cvReleaseImage( &gray );
cvReleaseImage( &small_img );
}
Two potential problems:
Your app cannot find the OpenCV DLLs, you might need to copy the OpenCV DLLs into your respective bin/release or bin/debug dir.
Or the OpenCV binaries were built with a different version of CRT than what you have installed on your system. Did you build OpenCV binaries on your system? That could help.
As a preface, I really do not want the exact solution to my problem, just guidance. I don't want you to give me the code. This isn't homework, it's just an exercise I'm trying to solve.
I just want you to tell me how to access VDU and directly change character on same screen.
The screen is divided into 25 rows and 80 columns. The characters that are displayed on the
screen are stored in a special memory called VDU memory (not to be confused with ordinary
memory). Each character displayed on the screen occupies two bytes in VDU memory.
The first of these bytes contains the ASCII value of the character being displayed, whereas, the second byte contains the colour in which the character is displayed. For example, the ASCII value of the character present on zeroth row and zeroth column on the screen is stored at location number 0xB8000000.
Therefore the colour of this character would be present at location number 0xB8000000 + 1. Similarly ASCII value of character in row 0, col 1 will be at location 0xB8000000 + 2, and its colour at 0xB8000000 + 3.
My task:
With this knowledge write a program which when executed would keep converting every capital letter on the screen to small case letter and every small case letter to capital letter. The procedure should stop the moment the user hits a key from the keyboard. This is an activity of a rampant Virus called Dancing Dolls. (For monochrome adapter, use 0xB0000000 instead of 0xB8000000).
Really I don't have any idea to build this code. I'm stuck at even getting started.
You are referring to what was once called the video refresh buffer. It's important to state that Dancing Dolls was a virus for DOS.
Basically, you are expecting video memory to be at address 0xB8000000 on your program's memory. However, modern Operating Systems (like Linux/Windows/Mac OS X) provide a virtual memory mechanism that prevents applications from manipulating devices directly. So the 0xB8000000 address your application sees is not the physical address 0xb8000000 that corresponds to the video refresh buffer. The last post of this thread also has some interesting info on this subject.
Nevertheless, the technique you are interested in is still valid for 16-bit DOS and is covered on the book Assembly Language Step-by-step: Programming with DOS and Linux. This book has a great section on chapter 6 that explains how this work exactly. The section is named Inspecting the Video Refresh Buffer with DEBUG, and has an interesting example that shows how to use debug.exe to access the video memory and modify it. I tested it successfully on cmd.exe of my Win 7 box.
But if you want to manipulate the screen of a Linux terminal, check ncurses:
It is a library of functions that manage an application's display on character-cell terminals
I think, most important is to be aware that your question is about an exercise that (apparently) at one time was designed to be easy and interesting.
However, that was long ago, and meanwhile both hardware and software has progressed. It is no longer easy to access physical memory. And, at least for the beginner, it is no longer interesting to do that.
Thus, the main goodness points of the exercise have been chopped off by time’s inexorable entropic action.
However, for one who absolutely want to do this exercise, that once-so-easily-accessible hardware can be simulated. Doing such a simulation transparently, so that the student code is the same as if it was for real, is rather difficult and system-dependent. However, if you (the student) just agree to explicitly call some “update” routine in order to simulate the hardware screen update, then it’s more near managable – and thus, old exercises can be reused! :-)
One can then imagine that main does some initialization of things, and calls a routine doTheDancingDolls with arguments that give access to simulated video memory, and the aforementioned “update” functionality:
void doTheDancingDolls(
curses::Console& console,
b8000::DisplayMemorySim& memorySim
)
{
do
{
// Whatever - this is where you Do Things to the simulated video memory.
// Then:
memorySim.update( console );
} while( !console.keyboard().keypressIsAvailable() );
console.keyboard().getKey(); // Consume the keypress.
}
… where the memorySim object somehow provides the necessary pointer to the simulated video memory – a pointer that corresponds to the B8000000 address in the exercise.
That’s the main idea, how to get a starting point for solving this exercise that's designed for now ANTIQUATED equipment.
Fleshing it out a bit more, here’s one possible implementation of the video memory simulation (note that this is not code that addresses the things that you were meant to do in the exercise, it just addresses the things that you were never meant to do, but possibly would have to today):
File [b8000.h]
#ifndef B8000_H
#define B8000_H
// A simulation of the early PC's 25*80 color text mode video memory.
// The structure of the memory is INTENTIONALLY not modelled in the
// exposed interface. A student can learn from imposing such structure.
//
// Copyright (c) 2011 Alf P. Steinbach.
//------------------------------------------ Dependencies:
#include "curses_plus_plus.h" // curses::Console
#include <vector> // std::vector
//------------------------------------------ Interface:
namespace b8000 {
typedef unsigned char Byte;
class DisplayMemorySim
{
private:
std::vector< Byte > buf_;
public:
enum { nColumns = 80, nLines = 25 };
DisplayMemorySim(): buf_( 2*nLines*nColumns ) {}
void* bufferPointer() { return &buf_[0]; }
void const* bufferPointer() const { return &buf_[0]; }
void update( curses::Console& console ) const
{
assert( console.nLines() >= nLines );
assert( console.nColumns() >= nColumns );
assert( console.colors().nColors() >= 16 );
for( int y = 0; y < nLines; ++y )
{
for( int x = 0; x < nColumns; ++x )
{
int const iCell = 2*(y*nColumns + x);
Byte const charCode = buf_[iCell];
Byte const colors = buf_[iCell + 1];
Byte const fg = colors & 0xF;
Byte const bg = colors >> 4;
console.colors().setFgBg( fg, bg );
console.putAt( x, y, charCode );
}
}
console.updateScreen();
}
};
} // namespace b8000
#endif
And the curses::Console class might be a simple wrapper over the curses library, e.g. like …
File [curses_plus_plus.h]
#ifndef CURSES_PLUS_PLUS_H
#define CURSES_PLUS_PLUS_H
// Sort of minimal C++ interface to the "curses" library.
// Copyright (c) 2011 Alf P. Steinbach.
//------------------------------------------ Dependencies:
#include "curses.h"
#if defined( _MSC_VER ) && defined( __PDCURSES__ )
# pragma comment( lib, "pdcurses.lib" )
#endif
#ifdef _MSC_VER
# pragma warning( disable: 4355 ) // 'this' used in member initializer
#endif
#include <assert.h> // assert
#include <stddef.h> // NULL
//------------------------------------------ Interface:
namespace curses {
class Console;
namespace detail {
template< class Number > inline Number square( Number x ) { return x*x; }
template< class Derived >
struct SingleInstance
{
static int& instanceCount()
{
static int n = 0;
return n;
}
SingleInstance( SingleInstance const& ); // No such.
SingleInstance& operator=( SingleInstance const& ); // No such.
SingleInstance()
{
++instanceCount();
assert(( "can only have one instance at a time", (instanceCount() == 1) ));
}
~SingleInstance() { --instanceCount(); }
};
} // namespace detail
namespace color {
#ifdef _WIN32 // Any Windows, 32-bit or 64-bit.
int const lightness = 0x08; // Windows only. 8
// The portable colors, expressed for Windows systems.
int const black = COLOR_BLACK; // 0
int const blue = COLOR_BLUE; // 1
int const green = COLOR_GREEN; // 2
int const cyan = COLOR_CYAN; // 3
int const red = COLOR_RED; // 4
int const magenta = COLOR_MAGENTA; // 5
int const yellow = COLOR_YELLOW | lightness; // 6 + 8
int const white = COLOR_WHITE | lightness; // 7 + 8
// Windows-specific colors.
int const gray = COLOR_BLACK | lightness;
int const lightBlue = COLOR_BLUE | lightness;
int const lightGreen = COLOR_GREEN | lightness;
int const lightCyan = COLOR_CYAN | lightness;
int const lightRed = COLOR_RED | lightness;
int const lightMagenta = COLOR_MAGENTA | lightness;
int const brown = COLOR_YELLOW & ~lightness; // A bit greenish.
int const lightGray = COLOR_WHITE & ~lightness;
#else
// The portable colors, expressed for non-Windows systems.
int const black = COLOR_BLACK;
int const blue = COLOR_BLUE;
int const green = COLOR_GREEN;
int const cyan = COLOR_CYAN;
int const red = COLOR_RED;
int const magenta = COLOR_MAGENTA;
int const yellow = COLOR_YELLOW;
int const white = COLOR_WHITE;
#endif
} // namespace color
class Colors
: private detail::SingleInstance< Colors >
{
private:
Colors( Colors const& ); // No such.
Colors& operator=( Colors const& ); // No such.
int n_;
int nPairs_;
int rawIndexOfPair0_;
int rawIndexFor( int fg, int bg ) const
{
return bg*n_ + fg;
}
public:
int nColors() const { return n_; }
int nColorPairs() const { return nPairs_; }
int indexFor( int fg, int bg ) const
{
int const rawIndex = rawIndexFor( fg, bg );
return 0?0
: (rawIndex == rawIndexOfPair0_)? 0
: (rawIndex == 0)? rawIndexOfPair0_
: rawIndex;
}
void setColorPair( int i )
{
::color_set( short( i ), NULL ); //attrset( COLOR_PAIR( i ) );
}
void setFgBg( int fg, int bg )
{
setColorPair( indexFor( fg, bg ) );
}
Colors( Console& )
{
::start_color(); // Initialize color support.
// Although these look like global constants, they're global variables
// that are initialized by the call to Curses' `start_color` (above).
n_ = ::COLORS; nPairs_ = ::COLOR_PAIRS;
assert( detail::square( n_ ) <= nPairs_ ); // Our requirement.
// Obtain curses' default colors, those are at color pair index 0.
{
short fg0 = -1;
short bg0 = -1;
::pair_content( 0, &fg0, &bg0 );
assert( fg0 != -1 );
assert( bg0 != -1 );
rawIndexOfPair0_ = rawIndexFor( fg0, bg0 );
}
// Initialize color pair table to support finding index for given colors.
// The color pair at index 0 can't be specified (according to docs),
// so trickery is required. Here like swapping index 0 to elsewhere.
for( int fg = 0; fg < n_; ++fg )
{
for( int bg = 0; bg < n_; ++bg )
{
int const i = indexFor( fg, bg );
if( i == 0 ) { continue; } // It's initialized already.
::init_pair( short( i ), short( fg ), short( bg ) );
}
}
}
};
class Keyboard
: private detail::SingleInstance< Keyboard >
{
private:
WINDOW* pCursesWin_;
bool isBlocking_;
int bufferedKeypress_;
bool hasBufferedKeypress_;
void setBlocking( bool desiredBlocking )
{
if( isBlocking_ != desiredBlocking )
{
::nodelay( pCursesWin_, !desiredBlocking );
isBlocking_ = desiredBlocking;
}
}
public:
int getKey()
{
if( hasBufferedKeypress_ )
{
hasBufferedKeypress_ = false;
return bufferedKeypress_;
}
setBlocking( true );
return ::getch();
}
bool keypressIsAvailable()
{
if( hasBufferedKeypress_ ) { return true; }
setBlocking( false );
int const key = ::getch();
if( key == ERR ) { return false; }
hasBufferedKeypress_ = true;
bufferedKeypress_ = key;
return true;
}
Keyboard( WINDOW& pCursesWin )
: pCursesWin_( &pCursesWin )
, isBlocking_( true )
, hasBufferedKeypress_( false )
{
::keypad( pCursesWin_, true ); // Assemble multi-character sequences into key symbols.
::nodelay( pCursesWin_, false );
assert( isBlocking_ == true );
}
~Keyboard()
{
setBlocking( true );
}
};
class Console
: private detail::SingleInstance< Console >
{
private:
::WINDOW* pCursesWin_;
Colors colors_;
Keyboard keyboard_;
Console( Console const& ); // No such.
Console& operator=( Console const& ); // No such.
static ::WINDOW* beginWin()
{
return ::initscr();
}
public:
// At least with pdcurses in Windows, these numbers are for the
// console window, i.e. not for its underlying text buffer.
int nColumns() const { return ::getmaxx( pCursesWin_ ); }
int nLines() const { return ::getmaxy( pCursesWin_ ); }
Colors& colors() { return colors_; }
Colors const& colors() const { return colors_; }
Keyboard& keyboard() { return keyboard_; }
Keyboard const& keyboard() const { return keyboard_; }
void putAt( int x, int y, char const s[] )
{
::mvaddstr( y, x, s );
}
void putAt( int x, int y, char c )
{
::mvaddch( y, x, c );
}
void updateScreen() { ::refresh(); }
Console()
: pCursesWin_( beginWin() )
, colors_( *this )
, keyboard_( *pCursesWin_ )
{
::cbreak(); // Immediate input (no line buffering).
::noecho(); // No input echo.
}
~Console()
{
::endwin();
}
};
} // namespace curses
#endif
To drive it all, in the main program you’d check whether the terminal window (Windows “ console window”) is sufficiently large, etc.:
File [main.cpp]
#include "string_util.h" // strUtil::S
#include "b8000.h" // b8000::DisplayMemorySim
#include "curses_plus_plus.h" // curses::Console
#include <algorithm> // std::max
#include <assert.h> // assert
#include <iostream> // std::cerr, std::endl
#include <stdexcept> // std::runtime_error, std::exception
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
void doTheDancingDolls(
curses::Console& console,
b8000::DisplayMemorySim& memorySim
)
{
do
{
// Whatever - this is where you Do Things to the simulated video memory.
// The following three lines are just to see that something's going on here.
using stringUtil::S;
static int x = 0;
console.putAt( 30, 5, S() << "I have now counted to " << ++x << "..." );
// Then:
//memorySim.update( console );
} while( !console.keyboard().keypressIsAvailable() );
console.keyboard().getKey(); // Consume the keypress.
}
bool throwX( std::string const& s ) { throw std::runtime_error( s ); }
void cppMain()
{
using std::max;
using stringUtil::S;
curses::Console console;
enum
{
w = b8000::DisplayMemorySim::nColumns,
h = b8000::DisplayMemorySim::nLines
};
(console.colors().nColors() >= 16)
|| throwX( "The console window doesn't support 16 colors." );
(console.nColumns() >= w)
|| throwX( S() << "The console window has less than " << w << " columns." );
(console.nLines() >= h)
|| throwX( S() << "The console window has less than " << h << " lines." );
namespace color = curses::color;
console.colors().setFgBg( color::lightRed, color::yellow );
console.putAt( 30, 0, " The Dancing Dolls! " );
console.putAt( 30, 1, S() << " In " << h << "x" << w << " color mode." );
console.putAt( 30, 3, S() << " Press ANY key to start... " );
console.keyboard().getKey();
console.putAt( 30, 3, S() << " Press ANY key to stop... " );
b8000::DisplayMemorySim displayMemorySim;
doTheDancingDolls( console, displayMemorySim );
}
int main()
{
using namespace std;
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cout << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
This post got a bit long, so I’m not adding in the code for the S() thing (it's not much code but still).
Anyway, this should provide a starting point for experimentation.
Disclaimer: I just cobbled this together. It’s not very extensively tested. I may, for example, have misunderstood things about the curses library’ keyboard handling –. And I’m hoping that it will work also in *nix-land, but I don’t know.
Cheers & hth.,
#include<conio.h>
#include<dos.h>
#define MEMORY_SIZE 3999 // 2 bytes for each character total char 2000
void main(){
char far *vidmem = 0xB8000000; // video memory address row & column zero
int i,o=0;
for(i=0;i<=MEMORY_SIZE;i+=2){
if (o%2==0)
*( vidmem + i) = 'A';
else
*( vidmem + i) = 'a';
o++;
}
while(!kbhit()){
for(i=0;i<=MEMORY_SIZE;i+=2){
if(*( vidmem +i) == 'A')
*( vidmem + i) = 'a';
else
*( vidmem + i) = 'A';
}
delay(200); // wait for 200 ms
}
}
/* run and compile success fully in Turbo C++ v3.0 non error just warring during running programme u just want to disable it option>>compiler>>message>>portablity */
Are we talking about actually performing modifications to what is displayed on your screen or do we just take the above assignment as an exercise.
In the latter case it's just looping over the described memory region (0xb8000000 + 25 (rows) * 80 (columns) * 2(bytes/displayed char). Reading the char portion for each displayed character and converting it from upper/lower to lower/upper case.
Conversion is simply done by simple arithmetic. Look at http://www.asciitable.com/ :
E.g: A = 0x41, a = 0x61
So in order to convert one to the other just add/remove 0x20 from the read value.