From 602d2a65dd628ea75801c79bfdf960b081696e34 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 28 Jul 2019 15:09:01 +0200 Subject: [PATCH] Reviewed new examples --- examples/core/core_scissor_test.c | 34 ++-- examples/core/core_scissor_test.png | Bin 0 -> 15348 bytes examples/textures/textures_mouse_painting.c | 175 ++++++++++++------ examples/textures/textures_mouse_painting.png | Bin 0 -> 20070 bytes 4 files changed, 128 insertions(+), 81 deletions(-) create mode 100644 examples/core/core_scissor_test.png create mode 100644 examples/textures/textures_mouse_painting.png diff --git a/examples/core/core_scissor_test.c b/examples/core/core_scissor_test.c index acc84202d..55221330e 100644 --- a/examples/core/core_scissor_test.c +++ b/examples/core/core_scissor_test.c @@ -5,6 +5,8 @@ * This example has been created using raylib 2.5 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * +* Example contributed by Chris Dill (@MysteriousSpace) and reviewed by Ramon Santamaria (@raysan5) +* * Copyright (c) 2019 Chris Dill (@MysteriousSpace) * ********************************************************************************************/ @@ -20,10 +22,10 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [core] example - scissor test"); - Rectangle scissorArea = { 0, 0, 300, 300}; + Rectangle scissorArea = { 0, 0, 300, 300 }; bool scissorMode = true; - SetTargetFPS(60); + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -31,14 +33,11 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - if (IsKeyPressed(KEY_S)) - { - scissorMode = !scissorMode; - } + if (IsKeyPressed(KEY_S)) scissorMode = !scissorMode; // Centre the scissor area around the mouse position - scissorArea.x = GetMouseX() - scissorArea.width / 2; - scissorArea.y = GetMouseY() - scissorArea.height / 2; + scissorArea.x = GetMouseX() - scissorArea.width/2; + scissorArea.y = GetMouseY() - scissorArea.height/2; //---------------------------------------------------------------------------------- // Draw @@ -47,22 +46,17 @@ int main(void) ClearBackground(RAYWHITE); - if (scissorMode) - { - BeginScissorMode(scissorArea.x, scissorArea.y, scissorArea.width, scissorArea.height); - } + if (scissorMode) BeginScissorMode(scissorArea.x, scissorArea.y, scissorArea.width, scissorArea.height); - DrawRectangle(80, 45, 640, 360, RED); - DrawRectangleLines(80, 45, 640, 360, BLACK); + // Draw full screen rectangle and some text + // NOTE: Only part defined by scissor area will be rendered + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), RED); DrawText("Move the mouse around to reveal this text!", 190, 200, 20, LIGHTGRAY); - if (scissorMode) - { - EndScissorMode(); - } + if (scissorMode) EndScissorMode(); - DrawRectangleLinesEx(scissorArea, 2, BLACK); - DrawText("Press s to toggle scissor test", 10, 10, 20, DARKGRAY); + DrawRectangleLinesEx(scissorArea, 1, BLACK); + DrawText("Press S to toggle scissor test", 10, 10, 20, BLACK); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/core/core_scissor_test.png b/examples/core/core_scissor_test.png new file mode 100644 index 0000000000000000000000000000000000000000..194872bb7e74791dbe06617f356af788ec91903d GIT binary patch literal 15348 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYU_8XZ#=yWJp1k%11B3N$PZ!6Kin!!IzrMb% zZwoY#Vp^<-gDBx(Ty`-)j<@lmfCN^8v8wez278Lh+TOMU85})W2!oz72RGq^*d=?~ z4s76VyeK*0qKhpqXEY=AI(>aQWu==o+$Qi@zkHl zVak)j(W7@z%C{bOTyist1?4K41bM#dIZ)8~dZN)|<5}jJ(oBnAW|*|1g&og#0g1Vc zlD?1e8W(lj5!9qq5Nb?oA}0m3%Bjv(ia}{Z&BHg3);1O*Zvs9 zT$a}PE8z8gap`4bXZN%*JXJKXVm6x9<>s7V!h(%>A;zR~zM)`pg_PJC^(E_ak1v&* z{`ZQ}{5untUp-;4@t>0E9*&=r!@dP+$L(BMqIKJ0d3w@i>9v>5*M7d8;GMtY&gasW zIrq$?j`txaPlvVxFL+L5{F26+t{X23EQsa^_$#85wR6suiJ4BXJnvdNzT{!3vY23f z$!?bT3Sp)zeDy(>rI+rLSnOpA>b7O%|39%^pR4S9+N z8R-rkv7i0knm%08X0tZkr(mZ4t9fEsKf8mfGiBoqK4)%y-hStYTKRd7y_d|_UN&6# z#eHoFUw3)d@yjn>Ml9a?2|2O?^jX}}9o&M^Vi1wB816bX2wH6VUT?C;-8o@_GsE>W zta{}WSJj!cxnqf4Hg}Gma}7Pqj^N4J45u?9`r8<6oe~y&f7Npg#XYd%<^cz|2$^Dm z8u*AZ4OE2OWj30111$&<+!tct!0f~smjVyG-0|dQt*|%~M>*l{FBNvCr;c-Ei1r*MsnZan*Xl5AdnW2Q6aoWWVa=eWXrI_yAxwCkpH8eXoE3xdW z`)ef?49iDJ(88y^l*8t-iG1%vSXq8WQK9tjlMEhM8>xe<@uF(PV$QljoJB#E{{WW~ zqfP*&kI_&V4Fy=YW;88~riIb80PagbiP0P}nj=PY1T-^%`?aGvVl+pL=7`Z8fj(Y3 zS}stxTsR?6VN$Qe%pv@`GUzJ*HV4&ff1U5nUwpH&qWyr!>FtYOR)XwHFkxxS1`iot z{)Rk6hCDzB8ud;!S>x`UpwiBeBj%!KD4%UG!N}Wa)+FR)3@+UhOjtPD!DEzKlGw-p zz!MLkVR5x>g0f5-X7YcTDG*Z=ksxSo+;qC;i-UTK{5p?Arp3+Pw!3zpocq)9yZAyE zmo?TWdBc<5s+S$>j`=_FRh`qjW#JV(TR$joy`VJZ9lO;%x77<_!x@>7ao%Tm$9atv z7K6tB8WbJg_^?(bT&#M}vGuHanOajwb>>sQr1Um6ExCeJxvZV-0W}Y$cB-4rOMEAv z^Ri;al4_?`^_3qDq9kDBiyoZd;rT6g(191&cnh2h8lDGDHsvf4TGHJn`7q+I0pI$-4tpOLEVSicTI4@0uy%CO=64? z?>}}4D%LXtGE)5pBe-GyAvjV!2nNeXod8PRqoFVw3a}ZY(X=p{7Dm$otSvK|7Dm&; zXj(vDoHtrWjFtQvXN1jdrhHFO`8=69gPnFeJBHSKVL59)8UM$Y6MvUM>S#0r;tqW7h zAE_K&Q_IUZ@Vj8Z3!g_9n2#= 0) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + colorSelected = colorMouseHover; + colorSelectedPrev = colorSelected; + } - if (colorState >= MAX_COLORS_COUNT) - colorState = 0; - else if (colorState < 0) - colorState = MAX_COLORS_COUNT - 1; + if (colorSelected >= MAX_COLORS_COUNT) colorSelected = MAX_COLORS_COUNT - 1; + else if (colorSelected < 0) colorSelected = 0; - brushSize += GetMouseWheelMove() * 5; - if (brushSize < 0) - brushSize = 0; - if (brushSize > 50) - brushSize = 50; + // Change brush size + brushSize += GetMouseWheelMove()*5; + if (brushSize < 2) brushSize = 2; + if (brushSize > 50) brushSize = 50; - Vector2 position = GetMousePosition(); - - if (IsKeyPressed(KEY_C)) { + if (IsKeyPressed(KEY_C)) + { + // Clear render texture to clear color BeginTextureMode(target); - ClearBackground(RAYWHITE); + ClearBackground(colors[0]); EndTextureMode(); } - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - TraceLog(LOG_INFO, "Painting x: %f y: %f", position.x, position.y); + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + // Paint circle into render texture + // NOTE: To avoid discontinuous circles, we could store + // previous-next mouse points and just draw a line using brush size BeginTextureMode(target); - DrawCircle(position.x, position.y, brushSize, colors[colorState]); + if (mousePos.y > 50) DrawCircle(mousePos.x, mousePos.y, brushSize, colors[colorSelected]); EndTextureMode(); } - if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) { - TraceLog(LOG_INFO, "Erasing x: %f y: %f", position.x, position.y); + if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) + { + colorSelected = 0; + + // Erase circle from render texture BeginTextureMode(target); - DrawCircle(position.x, position.y, brushSize, clearColor); + if (mousePos.y > 50) DrawCircle(mousePos.x, mousePos.y, brushSize, colors[0]); EndTextureMode(); } - - if (IsKeyPressed(KEY_S)) { - TakeScreenshot("textures_mouse_painting.png"); - } + else colorSelected = colorSelectedPrev; + + // Check mouse hover save button + if (CheckCollisionPointRec(mousePos, btnSaveRec)) btnSaveMouseHover = true; + else btnSaveMouseHover = false; + + // Image saving logic + // NOTE: Saving painted texture to a default named image + if ((btnSaveMouseHover && IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) || IsKeyPressed(KEY_S)) + { + Image image = GetTextureData(target.texture); + ImageFlipVertical(&image); + ExportImage(image, "my_amazing_texture_painting.png"); + UnloadImage(image); + } //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(RAYWHITE); + ClearBackground(RAYWHITE); - // NOTE: Render texture must be y-flipped due to default OpenGL coordinates - // (left-bottom) - DrawTextureRec(target.texture, (Rectangle){0, 0, target.texture.width, -target.texture.height}, (Vector2){0, 0}, WHITE); + // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) + DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE); - // Draw 2d shapes and text over drawn texture - DrawRectangle(0, 9, 380, 60, Fade(LIGHTGRAY, 0.7f)); + // Draw drawing circle for reference + if (mousePos.y > 50) + { + if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) DrawCircleLines(mousePos.x, mousePos.y, brushSize, colors[colorSelected]); + else DrawCircle(GetMouseX(), GetMouseY(), brushSize, colors[colorSelected]); + } + + // Draw top panel + DrawRectangle(0, 0, GetScreenWidth(), 50, RAYWHITE); + DrawLine(0, 50, GetScreenWidth(), 50, LIGHTGRAY); - DrawText("COLOR:", 10, 15, 20, BLACK); - DrawText(colorNames[colorState], 130, 15, 20, RED); - DrawText("< >", 340, 10, 30, DARKBLUE); + // Draw color selection rectangles + for (int i = 0; i < MAX_COLORS_COUNT; i++) DrawRectangleRec(colorsRecs[i], colors[i]); + DrawRectangleLines(10, 10, 30, 30, LIGHTGRAY); - DrawText("Size:", 10, 40, 20, BLACK); - DrawText(FormatText("%i", brushSize), 130, 40, 20, RED); + if (colorMouseHover >= 0) DrawRectangleRec(colorsRecs[colorMouseHover], Fade(WHITE, 0.6f)); - DrawCircle(GetMouseX(), GetMouseY(), brushSize, colors[colorState]); - - DrawFPS(700, 15); + DrawRectangleLinesEx((Rectangle){ colorsRecs[colorSelected].x - 2, colorsRecs[colorSelected].y - 2, + colorsRecs[colorSelected].width + 4, colorsRecs[colorSelected].height + 4 }, 2, BLACK); + // Draw save image button + DrawRectangleLinesEx(btnSaveRec, 2, btnSaveMouseHover? RED : BLACK); + DrawText("SAVE!", 755, 20, 10, btnSaveMouseHover? RED : BLACK); + EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadRenderTexture(target); - CloseWindow(); // Close window and OpenGL context + UnloadRenderTexture(target); // Unload render texture + + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/textures/textures_mouse_painting.png b/examples/textures/textures_mouse_painting.png new file mode 100644 index 0000000000000000000000000000000000000000..a3dec5dad57908321d7b2e305e6e4b425590d445 GIT binary patch literal 20070 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

C?|*tLC_{l-bDYx8W>7a6G_> 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