static void page_create( Page* pPage, int width, int height ) { SYS_VERIFY( rendertarget_create( &pPage->bgTarget, width, height, PixelFormat_R8G8B8A8 ) ); SYS_VERIFY( rendertarget_create( &pPage->fgTarget, width, height, PixelFormat_R8G8B8A8 ) ); SYS_VERIFY( rendertarget_create( &pPage->burnTarget, width, height, PixelFormat_R8G8B8A8 ) ); // render into render target: graphics_setRenderTarget( &pPage->bgTarget ); graphics_setBlendMode( BlendMode_Disabled ); // render paper: graphics_setShader( &s_renderer.paperShader ); graphics_setFp4f( 0u, float_rand(), float_rand(), 2.0f / width, 2.0f / height ); graphics_setVp4f( 0u, 32.0f, 18.0f, 0.4f, 0.3f ); graphics_setFsTexture(0,s_renderer.noiseTarget.id,SamplerState_MirrorU_MirrorV_Bilinear); graphics_drawFullscreenQuad(); // clear fg+burn target: graphics_setShader( 0 ); graphics_setRenderTarget( &pPage->fgTarget ); graphics_clear( 0.0f, 0.0f, 0.0f, 0.0f ); graphics_setRenderTarget( &pPage->burnTarget ); graphics_clear( 0.0f, 0.0f, 0.0f, 0.0f ); }
void renderer_drawCircle(const float2* pPos, float radius,const float3* pColor) { Page* pPage = &s_renderer.pages[ s_renderer.currentPage ]; graphics_setRenderTarget( &pPage->fgTarget ); graphics_setShader( &s_renderer.debugPenShader ); graphics_setBlendMode( BlendMode_Over ); graphics_setFp4f( 0u, pColor->x, pColor->y, pColor->z, 1.0f ); graphics_drawCircle(pPos,radius); }
void graphics_reset(void) { // TODO point and line drawing modes matrixstack_origin(); graphics_setColor(1.0f, 1.0f, 1.0f, 1.0f); graphics_setBackgroundColor(0.0f, 0.0f, 0.0f, 1.0f); graphics_setBlendMode(graphics_BlendMode_alpha); graphics_setDefaultShader(); graphics_setColorMask(true, true, true, true); graphics_clearScissor(); graphics_setCanvas(NULL); }
static void drawBurnHole( const BurnHole* pBurnHole ) { const float size=pBurnHole->size; if( size <= 0.0f ) { return; } Page* pPage = &s_renderer.pages[ s_renderer.currentPage ]; graphics_setRenderTarget( &pPage->burnTarget ); graphics_setShader( &s_renderer.burnHoleShader ); graphics_setBlendMode( BlendMode_Over ); graphics_setFsTexture( 0, s_renderer.noiseTarget.id, SamplerState_MirrorU_MirrorV_Bilinear ); const float initialSize=pBurnHole->initialSize; const float rot=pBurnHole->rot; const float2 start=pBurnHole->start; const float2 end=pBurnHole->end; const float len=float2_distance(&start,&end); const float s=initialSize; const float us=(len+2.0f*s)/10.0f; const float vs=2.0f*s/10.0f; graphics_setFp4f(0u,start.x,start.y,end.x,end.y); graphics_setFp4f(1u,size,0.0f,0.0f,0.0f); float2 dir; float2_normalize(float2_sub(&dir, &end, &start)); float2 normal; float2_perpendicular(&normal, &dir); float2 v[4u]; float2_addScaled1f(&v[0u], &start, &normal, s); float2_addScaled1f(&v[1u], &start, &normal, -s); float2_addScaled1f(&v[2u], &end, &normal, -s); float2_addScaled1f(&v[3u], &end, &normal, s); float2_addScaled1f(&v[0u], &v[0u], &dir, -s); float2_addScaled1f(&v[1u], &v[1u], &dir, -s); float2_addScaled1f(&v[2u], &v[2u], &dir, s); float2_addScaled1f(&v[3u], &v[3u], &dir, s); float2 uv0, uv1; float2_set(&uv0,0.0f,0.0f); float2_set(&uv1,us,vs); float2x2 rotM; float2x2_rotationY(&rotM,rot); /* float2x2_transform(&uv0,&rotM,&uv0); float2x2_transform(&uv1,&rotM,&uv1);*/ graphics_drawQuad(v,uv0.x,uv0.y,uv1.x,uv1.y); }
void renderer_drawFrame( const FrameData* pFrame ) { SYS_USE_ARGUMENT( pFrame ); // now render the final screen graphics_setRenderTarget( 0 ); graphics_setBlendMode( BlendMode_Disabled ); // render paper: graphics_setShader( &s_renderer.pageShader ); const Page* pCurrentPage=&s_renderer.pages[s_renderer.currentPage]; graphics_setFsTexture(0,pCurrentPage->bgTarget.id,SamplerState_ClampU_ClampV_Nearest); graphics_setFsTexture(1,pCurrentPage->fgTarget.id,SamplerState_ClampU_ClampV_Nearest); graphics_setFsTexture(2,pCurrentPage->burnTarget.id,SamplerState_ClampU_ClampV_Nearest); graphics_drawFullscreenQuad(); // render the flipped page on top: if( s_renderer.flipTime >= 0.0f ) { const float flipProgress=float_saturate( s_renderer.flipTime / s_renderer.flipDuration ); //SYS_TRACE_DEBUG( "%f (%f/%f)\n", flipProgress, s_renderer.flipTime, s_renderer.flipDuration ); graphics_setShader( &s_renderer.pageFlipShader ); const Page* pLastPage=&s_renderer.pages[s_renderer.lastPage]; graphics_setFsTexture(0,pLastPage->bgTarget.id,SamplerState_ClampU_ClampV_Trilinear); graphics_setFsTexture(1,pLastPage->fgTarget.id,SamplerState_ClampU_ClampV_Trilinear); graphics_setFsTexture(2,pLastPage->burnTarget.id,SamplerState_ClampU_ClampV_Trilinear); float3 flipParams; computeFlipParams( &flipParams, flipProgress ); graphics_setVp4f( 0u, flipParams.x, flipParams.y, flipParams.z, 0.0f ); graphics_drawMesh2d( &s_renderer.pageFlipMesh ); } }
void renderer_flipPage() { // if( s_renderer.flipTime >= 0.0f ) { //SYS_TRACE_WARNING( "starting page flip while another flip is still active!\n" ); } s_renderer.lastPage = s_renderer.currentPage; s_renderer.currentPage = 1 - s_renderer.currentPage; //s_renderer.currentStroke.pDefinition = 0; s_renderer.currentCommand = 0u; clearStrokeBuffer( &s_renderer.strokeBuffer ); setPageState( PageState_BeforeDraw ); Page* pPage = &s_renderer.pages[ s_renderer.currentPage ]; // clear current page: graphics_setRenderTarget( &pPage->fgTarget ); graphics_setBlendMode( BlendMode_Disabled ); graphics_setShader( 0 ); // graphics_clear( 0.0f, 0.0f, 0.0f, 0.0f ); graphics_setRenderTarget( &pPage->burnTarget ); graphics_clear( 0.0f, 0.0f, 0.0f, 0.0f ); for( uint i = 0u; i < SYS_COUNTOF(s_renderer.burnHoles); ++i ) { if( s_renderer.burnHoles[i].size>=0.0f) { // SYS_TRACE_DEBUG("bh[%i]=%f\n", i, s_renderer.burnHoles[i].size); drawBurnHole( &s_renderer.burnHoles[i] ); s_renderer.burnHoles[i].size -= 0.1f; } } if( s_renderer.flipDuration > 0.0f ) { s_renderer.flipTime = 0.0f; } else { // flip instantly: s_renderer.flipTime = -1.0f; } s_renderer.pageNumber++; float oldVariance=s_renderer.currentVariance; s_renderer.currentVariance=0.0f; renderer_setPen(Pen_PageNumber); // add the page number; float2 textPos; float2_set(&textPos,1.0f,1.0f); char numberText[16u]; sprintf(numberText,"%i",s_renderer.pageNumber); font_drawText(&textPos,0.5f,0.0f,numberText); renderer_flush(); s_renderer.currentVariance=oldVariance; //font_ }
void renderer_init() { SYS_VERIFY( shader_create( &s_renderer.paperShader, &s_shader_paper, 1u, 1u, 0u ) ); SYS_VERIFY( shader_create( &s_renderer.penShader, &s_shader_pen, 0u, 2u, 0u ) ); SYS_VERIFY( shader_create( &s_renderer.pageShader, &s_shader_page, 0u, 0u, 3u ) ); SYS_VERIFY( shader_create( &s_renderer.pageFlipShader, &s_shader_pageflip, 1u, 0u, 2u ) ); SYS_VERIFY( shader_create( &s_renderer.burnHoleShader, &s_shader_burnhole, 0u, 2u, 1u ) ); SYS_VERIFY( shader_create( &s_renderer.noiseShader, &s_shader_noise, 0u, 0u, 0u ) ); #ifndef SYS_BUILD_MASTER SYS_VERIFY( shader_create( &s_renderer.debugPenShader, &s_shader_debugpen, 1u, 0u, 0u ) ); #endif SYS_VERIFY( rendertarget_create( &s_renderer.noiseTarget, 512u, 512u, PixelFormat_R8G8B8A8 ) ); graphics_setBlendMode( BlendMode_Disabled ); // fill noise map: graphics_setRenderTarget( &s_renderer.noiseTarget ); graphics_setShader( &s_renderer.noiseShader ); graphics_drawFullscreenQuad(); const int width = sys_getScreenWidth(); const int height = sys_getScreenHeight(); // create page: for( uint i = 0u; i < SYS_COUNTOF( s_renderer.pages ); ++i ) { page_create( &s_renderer.pages[ i ], width, height ); } s_renderer.currentPage = 0u; s_renderer.lastPage = 1u; s_renderer.currentCommand = 0u; s_renderer.pageNumber = 0u; s_renderer.pageState = PageState_Done; s_renderer.stateTime = 0.0f; clearStrokeBuffer( &s_renderer.strokeBuffer ); float3 color; color.x = 0.2f; color.y = 0.2f; color.z = 0.2f; createPen( &s_renderer.pens[ Pen_Default ], 2.0f, 1.0f, &color ); createPen( &s_renderer.pens[ Pen_Font ], 2.0f, 1.0f, &color ); createPen( &s_renderer.pens[ Pen_Fat ], 3.0f, 1.0f, &color ); createPen( &s_renderer.pens[ Pen_DebugRed ], 2.0f, 1.0f, float3_set( &color, 1.0f, 0.0f, 0.0f ) ); createPen( &s_renderer.pens[ Pen_DebugGreen ], 2.0f, 1.0f, float3_set( &color, 0.0f, 1.0f, 0.0f ) ); createPen( &s_renderer.pens[ Pen_PageNumber ], 2.0f, 1.0f, float3_set( &color, 0.0f, 0.0f, 0.0f ) ); // create page flip mesh: createPageFlipMesh( &s_renderer.pageFlipMesh, 64u, 36u ); s_renderer.flipTime = -1.0f; for( uint i = 0u; i < SYS_COUNTOF(s_renderer.burnHoles); ++i ) { s_renderer.burnHoles[i].size = -1.0f; } renderer_setDrawSpeed( 0.5f ); renderer_setPen( Pen_Default ); renderer_setTransform( 0 ); }
static int advanceStroke( float* pRemainingTime, float timeStep ) { // draw stroke.. Page* pPage = &s_renderer.pages[ s_renderer.currentPage ]; Stroke* pStroke = &s_renderer.currentStroke; const StrokeCommand* pCommand = &s_renderer.strokeBuffer.commands[ s_renderer.currentCommand ]; if( !pCommand || pCommand->type != StrokeCommandType_Draw ) { SYS_TRACE_ERROR( "no active stroke!\n" ); return FALSE; } const StrokeDrawCommandData* pDrawCommand = &pCommand->data.draw; graphics_setRenderTarget( &pPage->fgTarget ); graphics_setShader( &s_renderer.penShader ); graphics_setBlendMode( BlendMode_Over ); const PenDefinition* pPen = &s_renderer.pens[ pDrawCommand->penId ]; const float variance = pDrawCommand->variance; // set constant shader parameters: graphics_setFp4f( 0u, 0.5f * pPen->width, variance, 0.05f * variance, 0.0f ); graphics_setFp4f( 1u, pPen->color.x, pPen->color.y, pPen->color.z, 1.0f ); float currentProgress = pStroke->progress; const float strokeLength = pStroke->length; float newProgress; if( s_renderer.strokeDrawSpeed <= 0.0f ) { // always finish the whole stroke: newProgress = strokeLength; // and we don't need any time: *pRemainingTime = timeStep; } else { // how long until we reach the end of this stroke?: const float remainingStrokeTime = ( strokeLength - pStroke->progress ) / s_renderer.strokeDrawSpeed; const float usedTime = float_min( timeStep, remainingStrokeTime ); newProgress = pStroke->progress + usedTime * s_renderer.strokeDrawSpeed; *pRemainingTime = timeStep - usedTime; } // SYS_TRACE_DEBUG( "advancing stroke from %f to %f! length=%f\n", currentProgress, newProgress, strokeLength ); if( newProgress <= currentProgress ) { return TRUE; } const uint segmentCount = pDrawCommand->pointCount - 1u; float remainingLength = newProgress - currentProgress; const float2* pStrokePoints = &s_renderer.strokeBuffer.points[ pDrawCommand->pointIndex ]; const float2* pStrokeNormals = &s_renderer.strokeBuffer.pointNormals[ pDrawCommand->pointIndex ]; while( pStroke->activeSegment < segmentCount && remainingLength > 0.0f ) { const float2 segmentStart = pStrokePoints[ pStroke->activeSegment ]; const float2 segmentEnd = pStrokePoints[ pStroke->activeSegment + 1u ]; const float2 segmentNormalStart = pStrokeNormals[ pStroke->activeSegment ]; const float2 segmentNormalEnd = pStrokeNormals[ pStroke->activeSegment + 1u ]; // get remaining length in current segment: float activeSegmentLength = float2_distance( &segmentStart, &segmentEnd ); if( activeSegmentLength <= 0.0f ) { break; } float remainingSegmentLength = activeSegmentLength - pStroke->segmentProgress; const float segmentAdvance = float_min( remainingSegmentLength, remainingLength ); // draw segment part: const float partStart = pStroke->segmentProgress; const float partEnd = partStart + segmentAdvance; const float strokeU0 = currentProgress / strokeLength; const float strokeU1 = ( currentProgress + segmentAdvance ) / strokeLength; const float segmentU0 = partStart / activeSegmentLength; const float segmentU1 = partEnd / activeSegmentLength; // draw the active segment between partStart and partEnd: //SYS_TRACE_DEBUG( "drawing segment part from %f to %f!\n", partStart / activeSegmentLength, partEnd / activeSegmentLength ); // compute part // :todo: draw start and end parts if this is the start/end of the segment // compute coordinates of quad enclosing the segment part: float2 segmentDir; float2_normalize( float2_sub( &segmentDir, &segmentEnd, &segmentStart ) ); float2 normalStart, normalEnd; float2_lerp( &normalStart, &segmentNormalStart, &segmentNormalEnd, segmentU0 ); float2_lerp( &normalEnd, &segmentNormalStart, &segmentNormalEnd, segmentU1 ); float2 startPos, endPos; float2_addScaled1f( &startPos, &segmentStart, &segmentDir, partStart ); float2_addScaled1f( &endPos, &segmentStart, &segmentDir, partEnd ); const float ws = 2.0f * ( 64.0f / sys_getScreenWidth() ); float2 vertices[ 4u ]; float2_addScaled1f( &vertices[ 0u ], &startPos, &normalStart, ws * pPen->width ); float2_addScaled1f( &vertices[ 1u ], &startPos, &normalStart, -ws * pPen->width ); float2_addScaled1f( &vertices[ 2u ], &endPos, &normalEnd, -ws * pPen->width ); float2_addScaled1f( &vertices[ 3u ], &endPos, &normalEnd, ws * pPen->width ); const float u0 = strokeU0; const float u1 = strokeU1; //SYS_TRACE_DEBUG( "u0=%f u1=%f v0=%f,%f v3=%f,%f\n", u0, u1, vertices[ 0u ].x, vertices[ 0u ].y, vertices[ 3u ].x, vertices[ 3u ].y ); graphics_drawQuad( vertices, u0, 0.0f, u1, 1.0f ); pStroke->segmentProgress += segmentAdvance; remainingLength -= segmentAdvance; currentProgress += segmentAdvance; if( segmentAdvance >= remainingSegmentLength ) { // next segment: pStroke->activeSegment++; pStroke->segmentProgress = 0.0f; } } if( newProgress < strokeLength ) { pStroke->progress = newProgress; return TRUE; } return FALSE; }
void graphics_init(int width, int height) { SDL_Init(SDL_INIT_VIDEO); //#ifdef EMSCRIPTEN // moduleData.surface = SDL_SetVideoMode(width, height, 0, SDL_OPENGL); //#else #ifndef EMSCRIPTEN SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); #else SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #endif SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); #if EMSCRIPTEN char const * title = emscripten_run_script_string("document.title"); #else char const * title = "Motor2D"; #endif moduleData.window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL); moduleData.context = SDL_GL_CreateContext(moduleData.window); SDL_GL_MakeCurrent(moduleData.window, moduleData.context); moduleData.surface = SDL_GetWindowSurface(moduleData.window); glewExperimental = GL_TRUE; printf("%d\n", glewInit()); #ifndef EMSCRIPTEN SDL_GL_SetSwapInterval(1); #endif //#endif // glViewport(0,0,width,height); matrixstack_init(); graphics_canvas_init(width, height); graphics_setColor(1.0f, 1.0f, 1.0f, 1.0f); graphics_geometry_init(); graphics_font_init(); graphics_batch_init(); graphics_image_init(); graphics_shader_init(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1); graphics_setColorMask(true, true, true, true); graphics_setBlendMode(graphics_BlendMode_alpha); glEnable(GL_BLEND); graphics_clearScissor(); glGenVertexArrays(1, &moduleData.polygonVAO); glBindVertexArray(moduleData.polygonVAO); glGenBuffers(1, &moduleData.polygonVBO); glGenBuffers(1, &moduleData.polygonIBO); }